View.java revision 8686e1f157f9d1e21cb39762d1ec495cc74afdb1
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 17package android.view; 18 19import static android.view.accessibility.AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED; 20 21import static java.lang.Math.max; 22 23import android.animation.AnimatorInflater; 24import android.animation.StateListAnimator; 25import android.annotation.CallSuper; 26import android.annotation.ColorInt; 27import android.annotation.DrawableRes; 28import android.annotation.FloatRange; 29import android.annotation.IdRes; 30import android.annotation.IntDef; 31import android.annotation.IntRange; 32import android.annotation.LayoutRes; 33import android.annotation.NonNull; 34import android.annotation.Nullable; 35import android.annotation.Size; 36import android.annotation.TestApi; 37import android.annotation.UiThread; 38import android.content.ClipData; 39import android.content.Context; 40import android.content.ContextWrapper; 41import android.content.Intent; 42import android.content.res.ColorStateList; 43import android.content.res.Configuration; 44import android.content.res.Resources; 45import android.content.res.TypedArray; 46import android.graphics.Bitmap; 47import android.graphics.Canvas; 48import android.graphics.Color; 49import android.graphics.Insets; 50import android.graphics.Interpolator; 51import android.graphics.LinearGradient; 52import android.graphics.Matrix; 53import android.graphics.Outline; 54import android.graphics.Paint; 55import android.graphics.PixelFormat; 56import android.graphics.Point; 57import android.graphics.PorterDuff; 58import android.graphics.PorterDuffXfermode; 59import android.graphics.Rect; 60import android.graphics.RectF; 61import android.graphics.Region; 62import android.graphics.Shader; 63import android.graphics.drawable.ColorDrawable; 64import android.graphics.drawable.Drawable; 65import android.hardware.display.DisplayManagerGlobal; 66import android.net.Uri; 67import android.os.Build; 68import android.os.Bundle; 69import android.os.Handler; 70import android.os.IBinder; 71import android.os.Message; 72import android.os.Parcel; 73import android.os.Parcelable; 74import android.os.RemoteException; 75import android.os.SystemClock; 76import android.os.SystemProperties; 77import android.os.Trace; 78import android.text.InputType; 79import android.text.TextUtils; 80import android.util.AttributeSet; 81import android.util.FloatProperty; 82import android.util.LayoutDirection; 83import android.util.Log; 84import android.util.LongSparseLongArray; 85import android.util.Pools.SynchronizedPool; 86import android.util.Property; 87import android.util.SparseArray; 88import android.util.StateSet; 89import android.util.SuperNotCalledException; 90import android.util.TypedValue; 91import android.view.AccessibilityIterators.CharacterTextSegmentIterator; 92import android.view.AccessibilityIterators.ParagraphTextSegmentIterator; 93import android.view.AccessibilityIterators.TextSegmentIterator; 94import android.view.AccessibilityIterators.WordTextSegmentIterator; 95import android.view.ContextMenu.ContextMenuInfo; 96import android.view.accessibility.AccessibilityEvent; 97import android.view.accessibility.AccessibilityEventSource; 98import android.view.accessibility.AccessibilityManager; 99import android.view.accessibility.AccessibilityNodeInfo; 100import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction; 101import android.view.accessibility.AccessibilityNodeProvider; 102import android.view.accessibility.AccessibilityWindowInfo; 103import android.view.animation.Animation; 104import android.view.animation.AnimationUtils; 105import android.view.animation.Transformation; 106import android.view.autofill.AutofillId; 107import android.view.autofill.AutofillManager; 108import android.view.autofill.AutofillValue; 109import android.view.inputmethod.EditorInfo; 110import android.view.inputmethod.InputConnection; 111import android.view.inputmethod.InputMethodManager; 112import android.widget.Checkable; 113import android.widget.FrameLayout; 114import android.widget.ScrollBarDrawable; 115 116import com.android.internal.R; 117import com.android.internal.view.TooltipPopup; 118import com.android.internal.view.menu.MenuBuilder; 119import com.android.internal.widget.ScrollBarUtils; 120 121import com.google.android.collect.Lists; 122import com.google.android.collect.Maps; 123 124import java.lang.annotation.Retention; 125import java.lang.annotation.RetentionPolicy; 126import java.lang.ref.WeakReference; 127import java.lang.reflect.Field; 128import java.lang.reflect.InvocationTargetException; 129import java.lang.reflect.Method; 130import java.lang.reflect.Modifier; 131import java.util.ArrayList; 132import java.util.Arrays; 133import java.util.Calendar; 134import java.util.Collection; 135import java.util.Collections; 136import java.util.HashMap; 137import java.util.List; 138import java.util.Locale; 139import java.util.Map; 140import java.util.concurrent.CopyOnWriteArrayList; 141import java.util.concurrent.atomic.AtomicInteger; 142import java.util.function.Predicate; 143 144/** 145 * <p> 146 * This class represents the basic building block for user interface components. A View 147 * occupies a rectangular area on the screen and is responsible for drawing and 148 * event handling. View is the base class for <em>widgets</em>, which are 149 * used to create interactive UI components (buttons, text fields, etc.). The 150 * {@link android.view.ViewGroup} subclass is the base class for <em>layouts</em>, which 151 * are invisible containers that hold other Views (or other ViewGroups) and define 152 * their layout properties. 153 * </p> 154 * 155 * <div class="special reference"> 156 * <h3>Developer Guides</h3> 157 * <p>For information about using this class to develop your application's user interface, 158 * read the <a href="{@docRoot}guide/topics/ui/index.html">User Interface</a> developer guide. 159 * </div> 160 * 161 * <a name="Using"></a> 162 * <h3>Using Views</h3> 163 * <p> 164 * All of the views in a window are arranged in a single tree. You can add views 165 * either from code or by specifying a tree of views in one or more XML layout 166 * files. There are many specialized subclasses of views that act as controls or 167 * are capable of displaying text, images, or other content. 168 * </p> 169 * <p> 170 * Once you have created a tree of views, there are typically a few types of 171 * common operations you may wish to perform: 172 * <ul> 173 * <li><strong>Set properties:</strong> for example setting the text of a 174 * {@link android.widget.TextView}. The available properties and the methods 175 * that set them will vary among the different subclasses of views. Note that 176 * properties that are known at build time can be set in the XML layout 177 * files.</li> 178 * <li><strong>Set focus:</strong> The framework will handle moving focus in 179 * response to user input. To force focus to a specific view, call 180 * {@link #requestFocus}.</li> 181 * <li><strong>Set up listeners:</strong> Views allow clients to set listeners 182 * that will be notified when something interesting happens to the view. For 183 * example, all views will let you set a listener to be notified when the view 184 * gains or loses focus. You can register such a listener using 185 * {@link #setOnFocusChangeListener(android.view.View.OnFocusChangeListener)}. 186 * Other view subclasses offer more specialized listeners. For example, a Button 187 * exposes a listener to notify clients when the button is clicked.</li> 188 * <li><strong>Set visibility:</strong> You can hide or show views using 189 * {@link #setVisibility(int)}.</li> 190 * </ul> 191 * </p> 192 * <p><em> 193 * Note: The Android framework is responsible for measuring, laying out and 194 * drawing views. You should not call methods that perform these actions on 195 * views yourself unless you are actually implementing a 196 * {@link android.view.ViewGroup}. 197 * </em></p> 198 * 199 * <a name="Lifecycle"></a> 200 * <h3>Implementing a Custom View</h3> 201 * 202 * <p> 203 * To implement a custom view, you will usually begin by providing overrides for 204 * some of the standard methods that the framework calls on all views. You do 205 * not need to override all of these methods. In fact, you can start by just 206 * overriding {@link #onDraw(android.graphics.Canvas)}. 207 * <table border="2" width="85%" align="center" cellpadding="5"> 208 * <thead> 209 * <tr><th>Category</th> <th>Methods</th> <th>Description</th></tr> 210 * </thead> 211 * 212 * <tbody> 213 * <tr> 214 * <td rowspan="2">Creation</td> 215 * <td>Constructors</td> 216 * <td>There is a form of the constructor that are called when the view 217 * is created from code and a form that is called when the view is 218 * inflated from a layout file. The second form should parse and apply 219 * any attributes defined in the layout file. 220 * </td> 221 * </tr> 222 * <tr> 223 * <td><code>{@link #onFinishInflate()}</code></td> 224 * <td>Called after a view and all of its children has been inflated 225 * from XML.</td> 226 * </tr> 227 * 228 * <tr> 229 * <td rowspan="3">Layout</td> 230 * <td><code>{@link #onMeasure(int, int)}</code></td> 231 * <td>Called to determine the size requirements for this view and all 232 * of its children. 233 * </td> 234 * </tr> 235 * <tr> 236 * <td><code>{@link #onLayout(boolean, int, int, int, int)}</code></td> 237 * <td>Called when this view should assign a size and position to all 238 * of its children. 239 * </td> 240 * </tr> 241 * <tr> 242 * <td><code>{@link #onSizeChanged(int, int, int, int)}</code></td> 243 * <td>Called when the size of this view has changed. 244 * </td> 245 * </tr> 246 * 247 * <tr> 248 * <td>Drawing</td> 249 * <td><code>{@link #onDraw(android.graphics.Canvas)}</code></td> 250 * <td>Called when the view should render its content. 251 * </td> 252 * </tr> 253 * 254 * <tr> 255 * <td rowspan="4">Event processing</td> 256 * <td><code>{@link #onKeyDown(int, KeyEvent)}</code></td> 257 * <td>Called when a new hardware key event occurs. 258 * </td> 259 * </tr> 260 * <tr> 261 * <td><code>{@link #onKeyUp(int, KeyEvent)}</code></td> 262 * <td>Called when a hardware key up event occurs. 263 * </td> 264 * </tr> 265 * <tr> 266 * <td><code>{@link #onTrackballEvent(MotionEvent)}</code></td> 267 * <td>Called when a trackball motion event occurs. 268 * </td> 269 * </tr> 270 * <tr> 271 * <td><code>{@link #onTouchEvent(MotionEvent)}</code></td> 272 * <td>Called when a touch screen motion event occurs. 273 * </td> 274 * </tr> 275 * 276 * <tr> 277 * <td rowspan="2">Focus</td> 278 * <td><code>{@link #onFocusChanged(boolean, int, android.graphics.Rect)}</code></td> 279 * <td>Called when the view gains or loses focus. 280 * </td> 281 * </tr> 282 * 283 * <tr> 284 * <td><code>{@link #onWindowFocusChanged(boolean)}</code></td> 285 * <td>Called when the window containing the view gains or loses focus. 286 * </td> 287 * </tr> 288 * 289 * <tr> 290 * <td rowspan="3">Attaching</td> 291 * <td><code>{@link #onAttachedToWindow()}</code></td> 292 * <td>Called when the view is attached to a window. 293 * </td> 294 * </tr> 295 * 296 * <tr> 297 * <td><code>{@link #onDetachedFromWindow}</code></td> 298 * <td>Called when the view is detached from its window. 299 * </td> 300 * </tr> 301 * 302 * <tr> 303 * <td><code>{@link #onWindowVisibilityChanged(int)}</code></td> 304 * <td>Called when the visibility of the window containing the view 305 * has changed. 306 * </td> 307 * </tr> 308 * </tbody> 309 * 310 * </table> 311 * </p> 312 * 313 * <a name="IDs"></a> 314 * <h3>IDs</h3> 315 * Views may have an integer id associated with them. These ids are typically 316 * assigned in the layout XML files, and are used to find specific views within 317 * the view tree. A common pattern is to: 318 * <ul> 319 * <li>Define a Button in the layout file and assign it a unique ID. 320 * <pre> 321 * <Button 322 * android:id="@+id/my_button" 323 * android:layout_width="wrap_content" 324 * android:layout_height="wrap_content" 325 * android:text="@string/my_button_text"/> 326 * </pre></li> 327 * <li>From the onCreate method of an Activity, find the Button 328 * <pre class="prettyprint"> 329 * Button myButton = findViewById(R.id.my_button); 330 * </pre></li> 331 * </ul> 332 * <p> 333 * View IDs need not be unique throughout the tree, but it is good practice to 334 * ensure that they are at least unique within the part of the tree you are 335 * searching. 336 * </p> 337 * 338 * <a name="Position"></a> 339 * <h3>Position</h3> 340 * <p> 341 * The geometry of a view is that of a rectangle. A view has a location, 342 * expressed as a pair of <em>left</em> and <em>top</em> coordinates, and 343 * two dimensions, expressed as a width and a height. The unit for location 344 * and dimensions is the pixel. 345 * </p> 346 * 347 * <p> 348 * It is possible to retrieve the location of a view by invoking the methods 349 * {@link #getLeft()} and {@link #getTop()}. The former returns the left, or X, 350 * coordinate of the rectangle representing the view. The latter returns the 351 * top, or Y, coordinate of the rectangle representing the view. These methods 352 * both return the location of the view relative to its parent. For instance, 353 * when getLeft() returns 20, that means the view is located 20 pixels to the 354 * right of the left edge of its direct parent. 355 * </p> 356 * 357 * <p> 358 * In addition, several convenience methods are offered to avoid unnecessary 359 * computations, namely {@link #getRight()} and {@link #getBottom()}. 360 * These methods return the coordinates of the right and bottom edges of the 361 * rectangle representing the view. For instance, calling {@link #getRight()} 362 * is similar to the following computation: <code>getLeft() + getWidth()</code> 363 * (see <a href="#SizePaddingMargins">Size</a> for more information about the width.) 364 * </p> 365 * 366 * <a name="SizePaddingMargins"></a> 367 * <h3>Size, padding and margins</h3> 368 * <p> 369 * The size of a view is expressed with a width and a height. A view actually 370 * possess two pairs of width and height values. 371 * </p> 372 * 373 * <p> 374 * The first pair is known as <em>measured width</em> and 375 * <em>measured height</em>. These dimensions define how big a view wants to be 376 * within its parent (see <a href="#Layout">Layout</a> for more details.) The 377 * measured dimensions can be obtained by calling {@link #getMeasuredWidth()} 378 * and {@link #getMeasuredHeight()}. 379 * </p> 380 * 381 * <p> 382 * The second pair is simply known as <em>width</em> and <em>height</em>, or 383 * sometimes <em>drawing width</em> and <em>drawing height</em>. These 384 * dimensions define the actual size of the view on screen, at drawing time and 385 * after layout. These values may, but do not have to, be different from the 386 * measured width and height. The width and height can be obtained by calling 387 * {@link #getWidth()} and {@link #getHeight()}. 388 * </p> 389 * 390 * <p> 391 * To measure its dimensions, a view takes into account its padding. The padding 392 * is expressed in pixels for the left, top, right and bottom parts of the view. 393 * Padding can be used to offset the content of the view by a specific amount of 394 * pixels. For instance, a left padding of 2 will push the view's content by 395 * 2 pixels to the right of the left edge. Padding can be set using the 396 * {@link #setPadding(int, int, int, int)} or {@link #setPaddingRelative(int, int, int, int)} 397 * method and queried by calling {@link #getPaddingLeft()}, {@link #getPaddingTop()}, 398 * {@link #getPaddingRight()}, {@link #getPaddingBottom()}, {@link #getPaddingStart()}, 399 * {@link #getPaddingEnd()}. 400 * </p> 401 * 402 * <p> 403 * Even though a view can define a padding, it does not provide any support for 404 * margins. However, view groups provide such a support. Refer to 405 * {@link android.view.ViewGroup} and 406 * {@link android.view.ViewGroup.MarginLayoutParams} for further information. 407 * </p> 408 * 409 * <a name="Layout"></a> 410 * <h3>Layout</h3> 411 * <p> 412 * Layout is a two pass process: a measure pass and a layout pass. The measuring 413 * pass is implemented in {@link #measure(int, int)} and is a top-down traversal 414 * of the view tree. Each view pushes dimension specifications down the tree 415 * during the recursion. At the end of the measure pass, every view has stored 416 * its measurements. The second pass happens in 417 * {@link #layout(int,int,int,int)} and is also top-down. During 418 * this pass each parent is responsible for positioning all of its children 419 * using the sizes computed in the measure pass. 420 * </p> 421 * 422 * <p> 423 * When a view's measure() method returns, its {@link #getMeasuredWidth()} and 424 * {@link #getMeasuredHeight()} values must be set, along with those for all of 425 * that view's descendants. A view's measured width and measured height values 426 * must respect the constraints imposed by the view's parents. This guarantees 427 * that at the end of the measure pass, all parents accept all of their 428 * children's measurements. A parent view may call measure() more than once on 429 * its children. For example, the parent may measure each child once with 430 * unspecified dimensions to find out how big they want to be, then call 431 * measure() on them again with actual numbers if the sum of all the children's 432 * unconstrained sizes is too big or too small. 433 * </p> 434 * 435 * <p> 436 * The measure pass uses two classes to communicate dimensions. The 437 * {@link MeasureSpec} class is used by views to tell their parents how they 438 * want to be measured and positioned. The base LayoutParams class just 439 * describes how big the view wants to be for both width and height. For each 440 * dimension, it can specify one of: 441 * <ul> 442 * <li> an exact number 443 * <li>MATCH_PARENT, which means the view wants to be as big as its parent 444 * (minus padding) 445 * <li> WRAP_CONTENT, which means that the view wants to be just big enough to 446 * enclose its content (plus padding). 447 * </ul> 448 * There are subclasses of LayoutParams for different subclasses of ViewGroup. 449 * For example, AbsoluteLayout has its own subclass of LayoutParams which adds 450 * an X and Y value. 451 * </p> 452 * 453 * <p> 454 * MeasureSpecs are used to push requirements down the tree from parent to 455 * child. A MeasureSpec can be in one of three modes: 456 * <ul> 457 * <li>UNSPECIFIED: This is used by a parent to determine the desired dimension 458 * of a child view. For example, a LinearLayout may call measure() on its child 459 * with the height set to UNSPECIFIED and a width of EXACTLY 240 to find out how 460 * tall the child view wants to be given a width of 240 pixels. 461 * <li>EXACTLY: This is used by the parent to impose an exact size on the 462 * child. The child must use this size, and guarantee that all of its 463 * descendants will fit within this size. 464 * <li>AT_MOST: This is used by the parent to impose a maximum size on the 465 * child. The child must guarantee that it and all of its descendants will fit 466 * within this size. 467 * </ul> 468 * </p> 469 * 470 * <p> 471 * To initiate a layout, call {@link #requestLayout}. This method is typically 472 * called by a view on itself when it believes that is can no longer fit within 473 * its current bounds. 474 * </p> 475 * 476 * <a name="Drawing"></a> 477 * <h3>Drawing</h3> 478 * <p> 479 * Drawing is handled by walking the tree and recording the drawing commands of 480 * any View that needs to update. After this, the drawing commands of the 481 * entire tree are issued to screen, clipped to the newly damaged area. 482 * </p> 483 * 484 * <p> 485 * The tree is largely recorded and drawn in order, with parents drawn before 486 * (i.e., behind) their children, with siblings drawn in the order they appear 487 * in the tree. If you set a background drawable for a View, then the View will 488 * draw it before calling back to its <code>onDraw()</code> method. The child 489 * drawing order can be overridden with 490 * {@link ViewGroup#setChildrenDrawingOrderEnabled(boolean) custom child drawing order} 491 * in a ViewGroup, and with {@link #setZ(float)} custom Z values} set on Views. 492 * </p> 493 * 494 * <p> 495 * To force a view to draw, call {@link #invalidate()}. 496 * </p> 497 * 498 * <a name="EventHandlingThreading"></a> 499 * <h3>Event Handling and Threading</h3> 500 * <p> 501 * The basic cycle of a view is as follows: 502 * <ol> 503 * <li>An event comes in and is dispatched to the appropriate view. The view 504 * handles the event and notifies any listeners.</li> 505 * <li>If in the course of processing the event, the view's bounds may need 506 * to be changed, the view will call {@link #requestLayout()}.</li> 507 * <li>Similarly, if in the course of processing the event the view's appearance 508 * may need to be changed, the view will call {@link #invalidate()}.</li> 509 * <li>If either {@link #requestLayout()} or {@link #invalidate()} were called, 510 * the framework will take care of measuring, laying out, and drawing the tree 511 * as appropriate.</li> 512 * </ol> 513 * </p> 514 * 515 * <p><em>Note: The entire view tree is single threaded. You must always be on 516 * the UI thread when calling any method on any view.</em> 517 * If you are doing work on other threads and want to update the state of a view 518 * from that thread, you should use a {@link Handler}. 519 * </p> 520 * 521 * <a name="FocusHandling"></a> 522 * <h3>Focus Handling</h3> 523 * <p> 524 * The framework will handle routine focus movement in response to user input. 525 * This includes changing the focus as views are removed or hidden, or as new 526 * views become available. Views indicate their willingness to take focus 527 * through the {@link #isFocusable} method. To change whether a view can take 528 * focus, call {@link #setFocusable(boolean)}. When in touch mode (see notes below) 529 * views indicate whether they still would like focus via {@link #isFocusableInTouchMode} 530 * and can change this via {@link #setFocusableInTouchMode(boolean)}. 531 * </p> 532 * <p> 533 * Focus movement is based on an algorithm which finds the nearest neighbor in a 534 * given direction. In rare cases, the default algorithm may not match the 535 * intended behavior of the developer. In these situations, you can provide 536 * explicit overrides by using these XML attributes in the layout file: 537 * <pre> 538 * nextFocusDown 539 * nextFocusLeft 540 * nextFocusRight 541 * nextFocusUp 542 * </pre> 543 * </p> 544 * 545 * 546 * <p> 547 * To get a particular view to take focus, call {@link #requestFocus()}. 548 * </p> 549 * 550 * <a name="TouchMode"></a> 551 * <h3>Touch Mode</h3> 552 * <p> 553 * When a user is navigating a user interface via directional keys such as a D-pad, it is 554 * necessary to give focus to actionable items such as buttons so the user can see 555 * what will take input. If the device has touch capabilities, however, and the user 556 * begins interacting with the interface by touching it, it is no longer necessary to 557 * always highlight, or give focus to, a particular view. This motivates a mode 558 * for interaction named 'touch mode'. 559 * </p> 560 * <p> 561 * For a touch capable device, once the user touches the screen, the device 562 * will enter touch mode. From this point onward, only views for which 563 * {@link #isFocusableInTouchMode} is true will be focusable, such as text editing widgets. 564 * Other views that are touchable, like buttons, will not take focus when touched; they will 565 * only fire the on click listeners. 566 * </p> 567 * <p> 568 * Any time a user hits a directional key, such as a D-pad direction, the view device will 569 * exit touch mode, and find a view to take focus, so that the user may resume interacting 570 * with the user interface without touching the screen again. 571 * </p> 572 * <p> 573 * The touch mode state is maintained across {@link android.app.Activity}s. Call 574 * {@link #isInTouchMode} to see whether the device is currently in touch mode. 575 * </p> 576 * 577 * <a name="Scrolling"></a> 578 * <h3>Scrolling</h3> 579 * <p> 580 * The framework provides basic support for views that wish to internally 581 * scroll their content. This includes keeping track of the X and Y scroll 582 * offset as well as mechanisms for drawing scrollbars. See 583 * {@link #scrollBy(int, int)}, {@link #scrollTo(int, int)}, and 584 * {@link #awakenScrollBars()} for more details. 585 * </p> 586 * 587 * <a name="Tags"></a> 588 * <h3>Tags</h3> 589 * <p> 590 * Unlike IDs, tags are not used to identify views. Tags are essentially an 591 * extra piece of information that can be associated with a view. They are most 592 * often used as a convenience to store data related to views in the views 593 * themselves rather than by putting them in a separate structure. 594 * </p> 595 * <p> 596 * Tags may be specified with character sequence values in layout XML as either 597 * a single tag using the {@link android.R.styleable#View_tag android:tag} 598 * attribute or multiple tags using the {@code <tag>} child element: 599 * <pre> 600 * <View ... 601 * android:tag="@string/mytag_value" /> 602 * <View ...> 603 * <tag android:id="@+id/mytag" 604 * android:value="@string/mytag_value" /> 605 * </View> 606 * </pre> 607 * </p> 608 * <p> 609 * Tags may also be specified with arbitrary objects from code using 610 * {@link #setTag(Object)} or {@link #setTag(int, Object)}. 611 * </p> 612 * 613 * <a name="Themes"></a> 614 * <h3>Themes</h3> 615 * <p> 616 * By default, Views are created using the theme of the Context object supplied 617 * to their constructor; however, a different theme may be specified by using 618 * the {@link android.R.styleable#View_theme android:theme} attribute in layout 619 * XML or by passing a {@link ContextThemeWrapper} to the constructor from 620 * code. 621 * </p> 622 * <p> 623 * When the {@link android.R.styleable#View_theme android:theme} attribute is 624 * used in XML, the specified theme is applied on top of the inflation 625 * context's theme (see {@link LayoutInflater}) and used for the view itself as 626 * well as any child elements. 627 * </p> 628 * <p> 629 * In the following example, both views will be created using the Material dark 630 * color scheme; however, because an overlay theme is used which only defines a 631 * subset of attributes, the value of 632 * {@link android.R.styleable#Theme_colorAccent android:colorAccent} defined on 633 * the inflation context's theme (e.g. the Activity theme) will be preserved. 634 * <pre> 635 * <LinearLayout 636 * ... 637 * android:theme="@android:theme/ThemeOverlay.Material.Dark"> 638 * <View ...> 639 * </LinearLayout> 640 * </pre> 641 * </p> 642 * 643 * <a name="Properties"></a> 644 * <h3>Properties</h3> 645 * <p> 646 * The View class exposes an {@link #ALPHA} property, as well as several transform-related 647 * properties, such as {@link #TRANSLATION_X} and {@link #TRANSLATION_Y}. These properties are 648 * available both in the {@link Property} form as well as in similarly-named setter/getter 649 * methods (such as {@link #setAlpha(float)} for {@link #ALPHA}). These properties can 650 * be used to set persistent state associated with these rendering-related properties on the view. 651 * The properties and methods can also be used in conjunction with 652 * {@link android.animation.Animator Animator}-based animations, described more in the 653 * <a href="#Animation">Animation</a> section. 654 * </p> 655 * 656 * <a name="Animation"></a> 657 * <h3>Animation</h3> 658 * <p> 659 * Starting with Android 3.0, the preferred way of animating views is to use the 660 * {@link android.animation} package APIs. These {@link android.animation.Animator Animator}-based 661 * classes change actual properties of the View object, such as {@link #setAlpha(float) alpha} and 662 * {@link #setTranslationX(float) translationX}. This behavior is contrasted to that of the pre-3.0 663 * {@link android.view.animation.Animation Animation}-based classes, which instead animate only 664 * how the view is drawn on the display. In particular, the {@link ViewPropertyAnimator} class 665 * makes animating these View properties particularly easy and efficient. 666 * </p> 667 * <p> 668 * Alternatively, you can use the pre-3.0 animation classes to animate how Views are rendered. 669 * You can attach an {@link Animation} object to a view using 670 * {@link #setAnimation(Animation)} or 671 * {@link #startAnimation(Animation)}. The animation can alter the scale, 672 * rotation, translation and alpha of a view over time. If the animation is 673 * attached to a view that has children, the animation will affect the entire 674 * subtree rooted by that node. When an animation is started, the framework will 675 * take care of redrawing the appropriate views until the animation completes. 676 * </p> 677 * 678 * <a name="Security"></a> 679 * <h3>Security</h3> 680 * <p> 681 * Sometimes it is essential that an application be able to verify that an action 682 * is being performed with the full knowledge and consent of the user, such as 683 * granting a permission request, making a purchase or clicking on an advertisement. 684 * Unfortunately, a malicious application could try to spoof the user into 685 * performing these actions, unaware, by concealing the intended purpose of the view. 686 * As a remedy, the framework offers a touch filtering mechanism that can be used to 687 * improve the security of views that provide access to sensitive functionality. 688 * </p><p> 689 * To enable touch filtering, call {@link #setFilterTouchesWhenObscured(boolean)} or set the 690 * android:filterTouchesWhenObscured layout attribute to true. When enabled, the framework 691 * will discard touches that are received whenever the view's window is obscured by 692 * another visible window. As a result, the view will not receive touches whenever a 693 * toast, dialog or other window appears above the view's window. 694 * </p><p> 695 * For more fine-grained control over security, consider overriding the 696 * {@link #onFilterTouchEventForSecurity(MotionEvent)} method to implement your own 697 * security policy. See also {@link MotionEvent#FLAG_WINDOW_IS_OBSCURED}. 698 * </p> 699 * 700 * @attr ref android.R.styleable#View_alpha 701 * @attr ref android.R.styleable#View_background 702 * @attr ref android.R.styleable#View_clickable 703 * @attr ref android.R.styleable#View_contentDescription 704 * @attr ref android.R.styleable#View_drawingCacheQuality 705 * @attr ref android.R.styleable#View_duplicateParentState 706 * @attr ref android.R.styleable#View_id 707 * @attr ref android.R.styleable#View_requiresFadingEdge 708 * @attr ref android.R.styleable#View_fadeScrollbars 709 * @attr ref android.R.styleable#View_fadingEdgeLength 710 * @attr ref android.R.styleable#View_filterTouchesWhenObscured 711 * @attr ref android.R.styleable#View_fitsSystemWindows 712 * @attr ref android.R.styleable#View_isScrollContainer 713 * @attr ref android.R.styleable#View_focusable 714 * @attr ref android.R.styleable#View_focusableInTouchMode 715 * @attr ref android.R.styleable#View_focusedByDefault 716 * @attr ref android.R.styleable#View_hapticFeedbackEnabled 717 * @attr ref android.R.styleable#View_keepScreenOn 718 * @attr ref android.R.styleable#View_keyboardNavigationCluster 719 * @attr ref android.R.styleable#View_layerType 720 * @attr ref android.R.styleable#View_layoutDirection 721 * @attr ref android.R.styleable#View_longClickable 722 * @attr ref android.R.styleable#View_minHeight 723 * @attr ref android.R.styleable#View_minWidth 724 * @attr ref android.R.styleable#View_nextClusterForward 725 * @attr ref android.R.styleable#View_nextFocusDown 726 * @attr ref android.R.styleable#View_nextFocusLeft 727 * @attr ref android.R.styleable#View_nextFocusRight 728 * @attr ref android.R.styleable#View_nextFocusUp 729 * @attr ref android.R.styleable#View_onClick 730 * @attr ref android.R.styleable#View_outlineSpotShadowColor 731 * @attr ref android.R.styleable#View_outlineAmbientShadowColor 732 * @attr ref android.R.styleable#View_padding 733 * @attr ref android.R.styleable#View_paddingHorizontal 734 * @attr ref android.R.styleable#View_paddingVertical 735 * @attr ref android.R.styleable#View_paddingBottom 736 * @attr ref android.R.styleable#View_paddingLeft 737 * @attr ref android.R.styleable#View_paddingRight 738 * @attr ref android.R.styleable#View_paddingTop 739 * @attr ref android.R.styleable#View_paddingStart 740 * @attr ref android.R.styleable#View_paddingEnd 741 * @attr ref android.R.styleable#View_saveEnabled 742 * @attr ref android.R.styleable#View_rotation 743 * @attr ref android.R.styleable#View_rotationX 744 * @attr ref android.R.styleable#View_rotationY 745 * @attr ref android.R.styleable#View_scaleX 746 * @attr ref android.R.styleable#View_scaleY 747 * @attr ref android.R.styleable#View_scrollX 748 * @attr ref android.R.styleable#View_scrollY 749 * @attr ref android.R.styleable#View_scrollbarSize 750 * @attr ref android.R.styleable#View_scrollbarStyle 751 * @attr ref android.R.styleable#View_scrollbars 752 * @attr ref android.R.styleable#View_scrollbarDefaultDelayBeforeFade 753 * @attr ref android.R.styleable#View_scrollbarFadeDuration 754 * @attr ref android.R.styleable#View_scrollbarTrackHorizontal 755 * @attr ref android.R.styleable#View_scrollbarThumbHorizontal 756 * @attr ref android.R.styleable#View_scrollbarThumbVertical 757 * @attr ref android.R.styleable#View_scrollbarTrackVertical 758 * @attr ref android.R.styleable#View_scrollbarAlwaysDrawHorizontalTrack 759 * @attr ref android.R.styleable#View_scrollbarAlwaysDrawVerticalTrack 760 * @attr ref android.R.styleable#View_stateListAnimator 761 * @attr ref android.R.styleable#View_transitionName 762 * @attr ref android.R.styleable#View_soundEffectsEnabled 763 * @attr ref android.R.styleable#View_tag 764 * @attr ref android.R.styleable#View_textAlignment 765 * @attr ref android.R.styleable#View_textDirection 766 * @attr ref android.R.styleable#View_transformPivotX 767 * @attr ref android.R.styleable#View_transformPivotY 768 * @attr ref android.R.styleable#View_translationX 769 * @attr ref android.R.styleable#View_translationY 770 * @attr ref android.R.styleable#View_translationZ 771 * @attr ref android.R.styleable#View_visibility 772 * @attr ref android.R.styleable#View_theme 773 * 774 * @see android.view.ViewGroup 775 */ 776@UiThread 777public class View implements Drawable.Callback, KeyEvent.Callback, 778 AccessibilityEventSource { 779 private static final boolean DBG = false; 780 781 /** @hide */ 782 public static boolean DEBUG_DRAW = false; 783 784 /** 785 * The logging tag used by this class with android.util.Log. 786 */ 787 protected static final String VIEW_LOG_TAG = "View"; 788 789 /** 790 * When set to true, apps will draw debugging information about their layouts. 791 * 792 * @hide 793 */ 794 public static final String DEBUG_LAYOUT_PROPERTY = "debug.layout"; 795 796 /** 797 * When set to true, this view will save its attribute data. 798 * 799 * @hide 800 */ 801 public static boolean mDebugViewAttributes = false; 802 803 /** 804 * Used to mark a View that has no ID. 805 */ 806 public static final int NO_ID = -1; 807 808 /** 809 * Last ID that is given to Views that are no part of activities. 810 * 811 * {@hide} 812 */ 813 public static final int LAST_APP_AUTOFILL_ID = Integer.MAX_VALUE / 2; 814 815 /** 816 * Attribute to find the autofilled highlight 817 * 818 * @see #getAutofilledDrawable() 819 */ 820 private static final int[] AUTOFILL_HIGHLIGHT_ATTR = 821 new int[]{android.R.attr.autofilledHighlight}; 822 823 /** 824 * Signals that compatibility booleans have been initialized according to 825 * target SDK versions. 826 */ 827 private static boolean sCompatibilityDone = false; 828 829 /** 830 * Use the old (broken) way of building MeasureSpecs. 831 */ 832 private static boolean sUseBrokenMakeMeasureSpec = false; 833 834 /** 835 * Always return a size of 0 for MeasureSpec values with a mode of UNSPECIFIED 836 */ 837 static boolean sUseZeroUnspecifiedMeasureSpec = false; 838 839 /** 840 * Ignore any optimizations using the measure cache. 841 */ 842 private static boolean sIgnoreMeasureCache = false; 843 844 /** 845 * Ignore an optimization that skips unnecessary EXACTLY layout passes. 846 */ 847 private static boolean sAlwaysRemeasureExactly = false; 848 849 /** 850 * Relax constraints around whether setLayoutParams() must be called after 851 * modifying the layout params. 852 */ 853 private static boolean sLayoutParamsAlwaysChanged = false; 854 855 /** 856 * Allow setForeground/setBackground to be called (and ignored) on a textureview, 857 * without throwing 858 */ 859 static boolean sTextureViewIgnoresDrawableSetters = false; 860 861 /** 862 * Prior to N, some ViewGroups would not convert LayoutParams properly even though both extend 863 * MarginLayoutParams. For instance, converting LinearLayout.LayoutParams to 864 * RelativeLayout.LayoutParams would lose margin information. This is fixed on N but target API 865 * check is implemented for backwards compatibility. 866 * 867 * {@hide} 868 */ 869 protected static boolean sPreserveMarginParamsInLayoutParamConversion; 870 871 /** 872 * Prior to N, when drag enters into child of a view that has already received an 873 * ACTION_DRAG_ENTERED event, the parent doesn't get a ACTION_DRAG_EXITED event. 874 * ACTION_DRAG_LOCATION and ACTION_DROP were delivered to the parent of a view that returned 875 * false from its event handler for these events. 876 * Starting from N, the parent will get ACTION_DRAG_EXITED event before the child gets its 877 * ACTION_DRAG_ENTERED. ACTION_DRAG_LOCATION and ACTION_DROP are never propagated to the parent. 878 * sCascadedDragDrop is true for pre-N apps for backwards compatibility implementation. 879 */ 880 static boolean sCascadedDragDrop; 881 882 /** 883 * Prior to O, auto-focusable didn't exist and widgets such as ListView use hasFocusable 884 * to determine things like whether or not to permit item click events. We can't break 885 * apps that do this just because more things (clickable things) are now auto-focusable 886 * and they would get different results, so give old behavior to old apps. 887 */ 888 static boolean sHasFocusableExcludeAutoFocusable; 889 890 /** 891 * Prior to O, auto-focusable didn't exist and views marked as clickable weren't implicitly 892 * made focusable by default. As a result, apps could (incorrectly) change the clickable 893 * setting of views off the UI thread. Now that clickable can effect the focusable state, 894 * changing the clickable attribute off the UI thread will cause an exception (since changing 895 * the focusable state checks). In order to prevent apps from crashing, we will handle this 896 * specific case and just not notify parents on new focusables resulting from marking views 897 * clickable from outside the UI thread. 898 */ 899 private static boolean sAutoFocusableOffUIThreadWontNotifyParents; 900 901 /** 902 * Prior to P things like setScaleX() allowed passing float values that were bogus such as 903 * Float.NaN. If the app is targetting P or later then passing these values will result in an 904 * exception being thrown. If the app is targetting an earlier SDK version, then we will 905 * silently clamp these values to avoid crashes elsewhere when the rendering code hits 906 * these bogus values. 907 */ 908 private static boolean sThrowOnInvalidFloatProperties; 909 910 /** 911 * Prior to P, {@code #startDragAndDrop} accepts a builder which produces an empty drag shadow. 912 * Currently zero size SurfaceControl cannot be created thus we create a dummy 1x1 surface 913 * instead. 914 */ 915 private static boolean sAcceptZeroSizeDragShadow; 916 917 /** @hide */ 918 @IntDef({NOT_FOCUSABLE, FOCUSABLE, FOCUSABLE_AUTO}) 919 @Retention(RetentionPolicy.SOURCE) 920 public @interface Focusable {} 921 922 /** 923 * This view does not want keystrokes. 924 * <p> 925 * Use with {@link #setFocusable(int)} and <a href="#attr_android:focusable">{@code 926 * android:focusable}. 927 */ 928 public static final int NOT_FOCUSABLE = 0x00000000; 929 930 /** 931 * This view wants keystrokes. 932 * <p> 933 * Use with {@link #setFocusable(int)} and <a href="#attr_android:focusable">{@code 934 * android:focusable}. 935 */ 936 public static final int FOCUSABLE = 0x00000001; 937 938 /** 939 * This view determines focusability automatically. This is the default. 940 * <p> 941 * Use with {@link #setFocusable(int)} and <a href="#attr_android:focusable">{@code 942 * android:focusable}. 943 */ 944 public static final int FOCUSABLE_AUTO = 0x00000010; 945 946 /** 947 * Mask for use with setFlags indicating bits used for focus. 948 */ 949 private static final int FOCUSABLE_MASK = 0x00000011; 950 951 /** 952 * This view will adjust its padding to fit sytem windows (e.g. status bar) 953 */ 954 private static final int FITS_SYSTEM_WINDOWS = 0x00000002; 955 956 /** @hide */ 957 @IntDef({VISIBLE, INVISIBLE, GONE}) 958 @Retention(RetentionPolicy.SOURCE) 959 public @interface Visibility {} 960 961 /** 962 * This view is visible. 963 * Use with {@link #setVisibility} and <a href="#attr_android:visibility">{@code 964 * android:visibility}. 965 */ 966 public static final int VISIBLE = 0x00000000; 967 968 /** 969 * This view is invisible, but it still takes up space for layout purposes. 970 * Use with {@link #setVisibility} and <a href="#attr_android:visibility">{@code 971 * android:visibility}. 972 */ 973 public static final int INVISIBLE = 0x00000004; 974 975 /** 976 * This view is invisible, and it doesn't take any space for layout 977 * purposes. Use with {@link #setVisibility} and <a href="#attr_android:visibility">{@code 978 * android:visibility}. 979 */ 980 public static final int GONE = 0x00000008; 981 982 /** 983 * Mask for use with setFlags indicating bits used for visibility. 984 * {@hide} 985 */ 986 static final int VISIBILITY_MASK = 0x0000000C; 987 988 private static final int[] VISIBILITY_FLAGS = {VISIBLE, INVISIBLE, GONE}; 989 990 /** 991 * Hint indicating that this view can be autofilled with an email address. 992 * 993 * <p>Can be used with either {@link #setAutofillHints(String[])} or 994 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 995 * value should be <code>{@value #AUTOFILL_HINT_EMAIL_ADDRESS}</code>). 996 * 997 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 998 */ 999 public static final String AUTOFILL_HINT_EMAIL_ADDRESS = "emailAddress"; 1000 1001 /** 1002 * Hint indicating that this view can be autofilled with a user's real name. 1003 * 1004 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1005 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1006 * value should be <code>{@value #AUTOFILL_HINT_NAME}</code>). 1007 * 1008 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1009 */ 1010 public static final String AUTOFILL_HINT_NAME = "name"; 1011 1012 /** 1013 * Hint indicating that this view can be autofilled with a username. 1014 * 1015 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1016 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1017 * value should be <code>{@value #AUTOFILL_HINT_USERNAME}</code>). 1018 * 1019 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1020 */ 1021 public static final String AUTOFILL_HINT_USERNAME = "username"; 1022 1023 /** 1024 * Hint indicating that this view can be autofilled with a password. 1025 * 1026 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1027 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1028 * value should be <code>{@value #AUTOFILL_HINT_PASSWORD}</code>). 1029 * 1030 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1031 */ 1032 public static final String AUTOFILL_HINT_PASSWORD = "password"; 1033 1034 /** 1035 * Hint indicating that this view can be autofilled with a phone number. 1036 * 1037 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1038 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1039 * value should be <code>{@value #AUTOFILL_HINT_PHONE}</code>). 1040 * 1041 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1042 */ 1043 public static final String AUTOFILL_HINT_PHONE = "phone"; 1044 1045 /** 1046 * Hint indicating that this view can be autofilled with a postal address. 1047 * 1048 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1049 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1050 * value should be <code>{@value #AUTOFILL_HINT_POSTAL_ADDRESS}</code>). 1051 * 1052 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1053 */ 1054 public static final String AUTOFILL_HINT_POSTAL_ADDRESS = "postalAddress"; 1055 1056 /** 1057 * Hint indicating that this view can be autofilled with a postal code. 1058 * 1059 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1060 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1061 * value should be <code>{@value #AUTOFILL_HINT_POSTAL_CODE}</code>). 1062 * 1063 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1064 */ 1065 public static final String AUTOFILL_HINT_POSTAL_CODE = "postalCode"; 1066 1067 /** 1068 * Hint indicating that this view can be autofilled with a credit card number. 1069 * 1070 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1071 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1072 * value should be <code>{@value #AUTOFILL_HINT_CREDIT_CARD_NUMBER}</code>). 1073 * 1074 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1075 */ 1076 public static final String AUTOFILL_HINT_CREDIT_CARD_NUMBER = "creditCardNumber"; 1077 1078 /** 1079 * Hint indicating that this view can be autofilled with a credit card security code. 1080 * 1081 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1082 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1083 * value should be <code>{@value #AUTOFILL_HINT_CREDIT_CARD_SECURITY_CODE}</code>). 1084 * 1085 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1086 */ 1087 public static final String AUTOFILL_HINT_CREDIT_CARD_SECURITY_CODE = "creditCardSecurityCode"; 1088 1089 /** 1090 * Hint indicating that this view can be autofilled with a credit card expiration date. 1091 * 1092 * <p>It should be used when the credit card expiration date is represented by just one view; 1093 * if it is represented by more than one (for example, one view for the month and another view 1094 * for the year), then each of these views should use the hint specific for the unit 1095 * ({@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DAY}, 1096 * {@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH}, 1097 * or {@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR}). 1098 * 1099 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1100 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1101 * value should be <code>{@value #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE}</code>). 1102 * 1103 * <p>When annotating a view with this hint, it's recommended to use a date autofill value to 1104 * avoid ambiguity when the autofill service provides a value for it. To understand why a 1105 * value can be ambiguous, consider "April of 2020", which could be represented as either of 1106 * the following options: 1107 * 1108 * <ul> 1109 * <li>{@code "04/2020"} 1110 * <li>{@code "4/2020"} 1111 * <li>{@code "2020/04"} 1112 * <li>{@code "2020/4"} 1113 * <li>{@code "April/2020"} 1114 * <li>{@code "Apr/2020"} 1115 * </ul> 1116 * 1117 * <p>You define a date autofill value for the view by overriding the following methods: 1118 * 1119 * <ol> 1120 * <li>{@link #getAutofillType()} to return {@link #AUTOFILL_TYPE_DATE}. 1121 * <li>{@link #getAutofillValue()} to return a 1122 * {@link AutofillValue#forDate(long) date autofillvalue}. 1123 * <li>{@link #autofill(AutofillValue)} to expect a data autofillvalue. 1124 * </ol> 1125 * 1126 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1127 */ 1128 public static final String AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE = 1129 "creditCardExpirationDate"; 1130 1131 /** 1132 * Hint indicating that this view can be autofilled with a credit card expiration month. 1133 * 1134 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1135 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1136 * value should be <code>{@value #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH}</code>). 1137 * 1138 * <p>When annotating a view with this hint, it's recommended to use a text autofill value 1139 * whose value is the numerical representation of the month, starting on {@code 1} to avoid 1140 * ambiguity when the autofill service provides a value for it. To understand why a 1141 * value can be ambiguous, consider "January", which could be represented as either of 1142 * 1143 * <ul> 1144 * <li>{@code "1"}: recommended way. 1145 * <li>{@code "0"}: if following the {@link Calendar#MONTH} convention. 1146 * <li>{@code "January"}: full name, in English. 1147 * <li>{@code "jan"}: abbreviated name, in English. 1148 * <li>{@code "Janeiro"}: full name, in another language. 1149 * </ul> 1150 * 1151 * <p>Another recommended approach is to use a date autofill value - see 1152 * {@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE} for more details. 1153 * 1154 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1155 */ 1156 public static final String AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH = 1157 "creditCardExpirationMonth"; 1158 1159 /** 1160 * Hint indicating that this view can be autofilled with a credit card expiration year. 1161 * 1162 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1163 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1164 * value should be <code>{@value #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR}</code>). 1165 * 1166 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1167 */ 1168 public static final String AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR = 1169 "creditCardExpirationYear"; 1170 1171 /** 1172 * Hint indicating that this view can be autofilled with a credit card expiration day. 1173 * 1174 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1175 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1176 * value should be <code>{@value #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DAY}</code>). 1177 * 1178 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1179 */ 1180 public static final String AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DAY = "creditCardExpirationDay"; 1181 1182 /** 1183 * Hints for the autofill services that describes the content of the view. 1184 */ 1185 private @Nullable String[] mAutofillHints; 1186 1187 /** 1188 * Autofill id, lazily created on calls to {@link #getAutofillId()}. 1189 */ 1190 private AutofillId mAutofillId; 1191 1192 /** @hide */ 1193 @IntDef(prefix = { "AUTOFILL_TYPE_" }, value = { 1194 AUTOFILL_TYPE_NONE, 1195 AUTOFILL_TYPE_TEXT, 1196 AUTOFILL_TYPE_TOGGLE, 1197 AUTOFILL_TYPE_LIST, 1198 AUTOFILL_TYPE_DATE 1199 }) 1200 @Retention(RetentionPolicy.SOURCE) 1201 public @interface AutofillType {} 1202 1203 /** 1204 * Autofill type for views that cannot be autofilled. 1205 * 1206 * <p>Typically used when the view is read-only; for example, a text label. 1207 * 1208 * @see #getAutofillType() 1209 */ 1210 public static final int AUTOFILL_TYPE_NONE = 0; 1211 1212 /** 1213 * Autofill type for a text field, which is filled by a {@link CharSequence}. 1214 * 1215 * <p>{@link AutofillValue} instances for autofilling a {@link View} can be obtained through 1216 * {@link AutofillValue#forText(CharSequence)}, and the value passed to autofill a 1217 * {@link View} can be fetched through {@link AutofillValue#getTextValue()}. 1218 * 1219 * @see #getAutofillType() 1220 */ 1221 public static final int AUTOFILL_TYPE_TEXT = 1; 1222 1223 /** 1224 * Autofill type for a togglable field, which is filled by a {@code boolean}. 1225 * 1226 * <p>{@link AutofillValue} instances for autofilling a {@link View} can be obtained through 1227 * {@link AutofillValue#forToggle(boolean)}, and the value passed to autofill a 1228 * {@link View} can be fetched through {@link AutofillValue#getToggleValue()}. 1229 * 1230 * @see #getAutofillType() 1231 */ 1232 public static final int AUTOFILL_TYPE_TOGGLE = 2; 1233 1234 /** 1235 * Autofill type for a selection list field, which is filled by an {@code int} 1236 * representing the element index inside the list (starting at {@code 0}). 1237 * 1238 * <p>{@link AutofillValue} instances for autofilling a {@link View} can be obtained through 1239 * {@link AutofillValue#forList(int)}, and the value passed to autofill a 1240 * {@link View} can be fetched through {@link AutofillValue#getListValue()}. 1241 * 1242 * <p>The available options in the selection list are typically provided by 1243 * {@link android.app.assist.AssistStructure.ViewNode#getAutofillOptions()}. 1244 * 1245 * @see #getAutofillType() 1246 */ 1247 public static final int AUTOFILL_TYPE_LIST = 3; 1248 1249 1250 /** 1251 * Autofill type for a field that contains a date, which is represented by a long representing 1252 * the number of milliseconds since the standard base time known as "the epoch", namely 1253 * January 1, 1970, 00:00:00 GMT (see {@link java.util.Date#getTime()}. 1254 * 1255 * <p>{@link AutofillValue} instances for autofilling a {@link View} can be obtained through 1256 * {@link AutofillValue#forDate(long)}, and the values passed to 1257 * autofill a {@link View} can be fetched through {@link AutofillValue#getDateValue()}. 1258 * 1259 * @see #getAutofillType() 1260 */ 1261 public static final int AUTOFILL_TYPE_DATE = 4; 1262 1263 /** @hide */ 1264 @IntDef(prefix = { "IMPORTANT_FOR_AUTOFILL_" }, value = { 1265 IMPORTANT_FOR_AUTOFILL_AUTO, 1266 IMPORTANT_FOR_AUTOFILL_YES, 1267 IMPORTANT_FOR_AUTOFILL_NO, 1268 IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS, 1269 IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS 1270 }) 1271 @Retention(RetentionPolicy.SOURCE) 1272 public @interface AutofillImportance {} 1273 1274 /** 1275 * Automatically determine whether a view is important for autofill. 1276 * 1277 * @see #isImportantForAutofill() 1278 * @see #setImportantForAutofill(int) 1279 */ 1280 public static final int IMPORTANT_FOR_AUTOFILL_AUTO = 0x0; 1281 1282 /** 1283 * The view is important for autofill, and its children (if any) will be traversed. 1284 * 1285 * @see #isImportantForAutofill() 1286 * @see #setImportantForAutofill(int) 1287 */ 1288 public static final int IMPORTANT_FOR_AUTOFILL_YES = 0x1; 1289 1290 /** 1291 * The view is not important for autofill, but its children (if any) will be traversed. 1292 * 1293 * @see #isImportantForAutofill() 1294 * @see #setImportantForAutofill(int) 1295 */ 1296 public static final int IMPORTANT_FOR_AUTOFILL_NO = 0x2; 1297 1298 /** 1299 * The view is important for autofill, but its children (if any) will not be traversed. 1300 * 1301 * @see #isImportantForAutofill() 1302 * @see #setImportantForAutofill(int) 1303 */ 1304 public static final int IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS = 0x4; 1305 1306 /** 1307 * The view is not important for autofill, and its children (if any) will not be traversed. 1308 * 1309 * @see #isImportantForAutofill() 1310 * @see #setImportantForAutofill(int) 1311 */ 1312 public static final int IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS = 0x8; 1313 1314 /** @hide */ 1315 @IntDef(flag = true, prefix = { "AUTOFILL_FLAG_" }, value = { 1316 AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS 1317 }) 1318 @Retention(RetentionPolicy.SOURCE) 1319 public @interface AutofillFlags {} 1320 1321 /** 1322 * Flag requesting you to add views that are marked as not important for autofill 1323 * (see {@link #setImportantForAutofill(int)}) to a {@link ViewStructure}. 1324 */ 1325 public static final int AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS = 0x1; 1326 1327 /** 1328 * This view is enabled. Interpretation varies by subclass. 1329 * Use with ENABLED_MASK when calling setFlags. 1330 * {@hide} 1331 */ 1332 static final int ENABLED = 0x00000000; 1333 1334 /** 1335 * This view is disabled. Interpretation varies by subclass. 1336 * Use with ENABLED_MASK when calling setFlags. 1337 * {@hide} 1338 */ 1339 static final int DISABLED = 0x00000020; 1340 1341 /** 1342 * Mask for use with setFlags indicating bits used for indicating whether 1343 * this view is enabled 1344 * {@hide} 1345 */ 1346 static final int ENABLED_MASK = 0x00000020; 1347 1348 /** 1349 * This view won't draw. {@link #onDraw(android.graphics.Canvas)} won't be 1350 * called and further optimizations will be performed. It is okay to have 1351 * this flag set and a background. Use with DRAW_MASK when calling setFlags. 1352 * {@hide} 1353 */ 1354 static final int WILL_NOT_DRAW = 0x00000080; 1355 1356 /** 1357 * Mask for use with setFlags indicating bits used for indicating whether 1358 * this view is will draw 1359 * {@hide} 1360 */ 1361 static final int DRAW_MASK = 0x00000080; 1362 1363 /** 1364 * <p>This view doesn't show scrollbars.</p> 1365 * {@hide} 1366 */ 1367 static final int SCROLLBARS_NONE = 0x00000000; 1368 1369 /** 1370 * <p>This view shows horizontal scrollbars.</p> 1371 * {@hide} 1372 */ 1373 static final int SCROLLBARS_HORIZONTAL = 0x00000100; 1374 1375 /** 1376 * <p>This view shows vertical scrollbars.</p> 1377 * {@hide} 1378 */ 1379 static final int SCROLLBARS_VERTICAL = 0x00000200; 1380 1381 /** 1382 * <p>Mask for use with setFlags indicating bits used for indicating which 1383 * scrollbars are enabled.</p> 1384 * {@hide} 1385 */ 1386 static final int SCROLLBARS_MASK = 0x00000300; 1387 1388 /** 1389 * Indicates that the view should filter touches when its window is obscured. 1390 * Refer to the class comments for more information about this security feature. 1391 * {@hide} 1392 */ 1393 static final int FILTER_TOUCHES_WHEN_OBSCURED = 0x00000400; 1394 1395 /** 1396 * Set for framework elements that use FITS_SYSTEM_WINDOWS, to indicate 1397 * that they are optional and should be skipped if the window has 1398 * requested system UI flags that ignore those insets for layout. 1399 */ 1400 static final int OPTIONAL_FITS_SYSTEM_WINDOWS = 0x00000800; 1401 1402 /** 1403 * <p>This view doesn't show fading edges.</p> 1404 * {@hide} 1405 */ 1406 static final int FADING_EDGE_NONE = 0x00000000; 1407 1408 /** 1409 * <p>This view shows horizontal fading edges.</p> 1410 * {@hide} 1411 */ 1412 static final int FADING_EDGE_HORIZONTAL = 0x00001000; 1413 1414 /** 1415 * <p>This view shows vertical fading edges.</p> 1416 * {@hide} 1417 */ 1418 static final int FADING_EDGE_VERTICAL = 0x00002000; 1419 1420 /** 1421 * <p>Mask for use with setFlags indicating bits used for indicating which 1422 * fading edges are enabled.</p> 1423 * {@hide} 1424 */ 1425 static final int FADING_EDGE_MASK = 0x00003000; 1426 1427 /** 1428 * <p>Indicates this view can be clicked. When clickable, a View reacts 1429 * to clicks by notifying the OnClickListener.<p> 1430 * {@hide} 1431 */ 1432 static final int CLICKABLE = 0x00004000; 1433 1434 /** 1435 * <p>Indicates this view is caching its drawing into a bitmap.</p> 1436 * {@hide} 1437 */ 1438 static final int DRAWING_CACHE_ENABLED = 0x00008000; 1439 1440 /** 1441 * <p>Indicates that no icicle should be saved for this view.<p> 1442 * {@hide} 1443 */ 1444 static final int SAVE_DISABLED = 0x000010000; 1445 1446 /** 1447 * <p>Mask for use with setFlags indicating bits used for the saveEnabled 1448 * property.</p> 1449 * {@hide} 1450 */ 1451 static final int SAVE_DISABLED_MASK = 0x000010000; 1452 1453 /** 1454 * <p>Indicates that no drawing cache should ever be created for this view.<p> 1455 * {@hide} 1456 */ 1457 static final int WILL_NOT_CACHE_DRAWING = 0x000020000; 1458 1459 /** 1460 * <p>Indicates this view can take / keep focus when int touch mode.</p> 1461 * {@hide} 1462 */ 1463 static final int FOCUSABLE_IN_TOUCH_MODE = 0x00040000; 1464 1465 /** @hide */ 1466 @Retention(RetentionPolicy.SOURCE) 1467 @IntDef(prefix = { "DRAWING_CACHE_QUALITY_" }, value = { 1468 DRAWING_CACHE_QUALITY_LOW, 1469 DRAWING_CACHE_QUALITY_HIGH, 1470 DRAWING_CACHE_QUALITY_AUTO 1471 }) 1472 public @interface DrawingCacheQuality {} 1473 1474 /** 1475 * <p>Enables low quality mode for the drawing cache.</p> 1476 * 1477 * @deprecated The view drawing cache was largely made obsolete with the introduction of 1478 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 1479 * layers are largely unnecessary and can easily result in a net loss in performance due to the 1480 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 1481 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 1482 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 1483 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 1484 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 1485 * software-rendered usages are discouraged and have compatibility issues with hardware-only 1486 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 1487 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 1488 * reports or unit testing the {@link PixelCopy} API is recommended. 1489 */ 1490 @Deprecated 1491 public static final int DRAWING_CACHE_QUALITY_LOW = 0x00080000; 1492 1493 /** 1494 * <p>Enables high quality mode for the drawing cache.</p> 1495 * 1496 * @deprecated The view drawing cache was largely made obsolete with the introduction of 1497 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 1498 * layers are largely unnecessary and can easily result in a net loss in performance due to the 1499 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 1500 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 1501 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 1502 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 1503 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 1504 * software-rendered usages are discouraged and have compatibility issues with hardware-only 1505 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 1506 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 1507 * reports or unit testing the {@link PixelCopy} API is recommended. 1508 */ 1509 @Deprecated 1510 public static final int DRAWING_CACHE_QUALITY_HIGH = 0x00100000; 1511 1512 /** 1513 * <p>Enables automatic quality mode for the drawing cache.</p> 1514 * 1515 * @deprecated The view drawing cache was largely made obsolete with the introduction of 1516 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 1517 * layers are largely unnecessary and can easily result in a net loss in performance due to the 1518 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 1519 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 1520 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 1521 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 1522 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 1523 * software-rendered usages are discouraged and have compatibility issues with hardware-only 1524 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 1525 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 1526 * reports or unit testing the {@link PixelCopy} API is recommended. 1527 */ 1528 @Deprecated 1529 public static final int DRAWING_CACHE_QUALITY_AUTO = 0x00000000; 1530 1531 private static final int[] DRAWING_CACHE_QUALITY_FLAGS = { 1532 DRAWING_CACHE_QUALITY_AUTO, DRAWING_CACHE_QUALITY_LOW, DRAWING_CACHE_QUALITY_HIGH 1533 }; 1534 1535 /** 1536 * <p>Mask for use with setFlags indicating bits used for the cache 1537 * quality property.</p> 1538 * {@hide} 1539 */ 1540 static final int DRAWING_CACHE_QUALITY_MASK = 0x00180000; 1541 1542 /** 1543 * <p> 1544 * Indicates this view can be long clicked. When long clickable, a View 1545 * reacts to long clicks by notifying the OnLongClickListener or showing a 1546 * context menu. 1547 * </p> 1548 * {@hide} 1549 */ 1550 static final int LONG_CLICKABLE = 0x00200000; 1551 1552 /** 1553 * <p>Indicates that this view gets its drawable states from its direct parent 1554 * and ignores its original internal states.</p> 1555 * 1556 * @hide 1557 */ 1558 static final int DUPLICATE_PARENT_STATE = 0x00400000; 1559 1560 /** 1561 * <p> 1562 * Indicates this view can be context clicked. When context clickable, a View reacts to a 1563 * context click (e.g. a primary stylus button press or right mouse click) by notifying the 1564 * OnContextClickListener. 1565 * </p> 1566 * {@hide} 1567 */ 1568 static final int CONTEXT_CLICKABLE = 0x00800000; 1569 1570 /** @hide */ 1571 @IntDef(prefix = { "SCROLLBARS_" }, value = { 1572 SCROLLBARS_INSIDE_OVERLAY, 1573 SCROLLBARS_INSIDE_INSET, 1574 SCROLLBARS_OUTSIDE_OVERLAY, 1575 SCROLLBARS_OUTSIDE_INSET 1576 }) 1577 @Retention(RetentionPolicy.SOURCE) 1578 public @interface ScrollBarStyle {} 1579 1580 /** 1581 * The scrollbar style to display the scrollbars inside the content area, 1582 * without increasing the padding. The scrollbars will be overlaid with 1583 * translucency on the view's content. 1584 */ 1585 public static final int SCROLLBARS_INSIDE_OVERLAY = 0; 1586 1587 /** 1588 * The scrollbar style to display the scrollbars inside the padded area, 1589 * increasing the padding of the view. The scrollbars will not overlap the 1590 * content area of the view. 1591 */ 1592 public static final int SCROLLBARS_INSIDE_INSET = 0x01000000; 1593 1594 /** 1595 * The scrollbar style to display the scrollbars at the edge of the view, 1596 * without increasing the padding. The scrollbars will be overlaid with 1597 * translucency. 1598 */ 1599 public static final int SCROLLBARS_OUTSIDE_OVERLAY = 0x02000000; 1600 1601 /** 1602 * The scrollbar style to display the scrollbars at the edge of the view, 1603 * increasing the padding of the view. The scrollbars will only overlap the 1604 * background, if any. 1605 */ 1606 public static final int SCROLLBARS_OUTSIDE_INSET = 0x03000000; 1607 1608 /** 1609 * Mask to check if the scrollbar style is overlay or inset. 1610 * {@hide} 1611 */ 1612 static final int SCROLLBARS_INSET_MASK = 0x01000000; 1613 1614 /** 1615 * Mask to check if the scrollbar style is inside or outside. 1616 * {@hide} 1617 */ 1618 static final int SCROLLBARS_OUTSIDE_MASK = 0x02000000; 1619 1620 /** 1621 * Mask for scrollbar style. 1622 * {@hide} 1623 */ 1624 static final int SCROLLBARS_STYLE_MASK = 0x03000000; 1625 1626 /** 1627 * View flag indicating that the screen should remain on while the 1628 * window containing this view is visible to the user. This effectively 1629 * takes care of automatically setting the WindowManager's 1630 * {@link WindowManager.LayoutParams#FLAG_KEEP_SCREEN_ON}. 1631 */ 1632 public static final int KEEP_SCREEN_ON = 0x04000000; 1633 1634 /** 1635 * View flag indicating whether this view should have sound effects enabled 1636 * for events such as clicking and touching. 1637 */ 1638 public static final int SOUND_EFFECTS_ENABLED = 0x08000000; 1639 1640 /** 1641 * View flag indicating whether this view should have haptic feedback 1642 * enabled for events such as long presses. 1643 */ 1644 public static final int HAPTIC_FEEDBACK_ENABLED = 0x10000000; 1645 1646 /** 1647 * <p>Indicates that the view hierarchy should stop saving state when 1648 * it reaches this view. If state saving is initiated immediately at 1649 * the view, it will be allowed. 1650 * {@hide} 1651 */ 1652 static final int PARENT_SAVE_DISABLED = 0x20000000; 1653 1654 /** 1655 * <p>Mask for use with setFlags indicating bits used for PARENT_SAVE_DISABLED.</p> 1656 * {@hide} 1657 */ 1658 static final int PARENT_SAVE_DISABLED_MASK = 0x20000000; 1659 1660 private static Paint sDebugPaint; 1661 1662 /** 1663 * <p>Indicates this view can display a tooltip on hover or long press.</p> 1664 * {@hide} 1665 */ 1666 static final int TOOLTIP = 0x40000000; 1667 1668 /** @hide */ 1669 @IntDef(flag = true, prefix = { "FOCUSABLES_" }, value = { 1670 FOCUSABLES_ALL, 1671 FOCUSABLES_TOUCH_MODE 1672 }) 1673 @Retention(RetentionPolicy.SOURCE) 1674 public @interface FocusableMode {} 1675 1676 /** 1677 * View flag indicating whether {@link #addFocusables(ArrayList, int, int)} 1678 * should add all focusable Views regardless if they are focusable in touch mode. 1679 */ 1680 public static final int FOCUSABLES_ALL = 0x00000000; 1681 1682 /** 1683 * View flag indicating whether {@link #addFocusables(ArrayList, int, int)} 1684 * should add only Views focusable in touch mode. 1685 */ 1686 public static final int FOCUSABLES_TOUCH_MODE = 0x00000001; 1687 1688 /** @hide */ 1689 @IntDef(prefix = { "FOCUS_" }, value = { 1690 FOCUS_BACKWARD, 1691 FOCUS_FORWARD, 1692 FOCUS_LEFT, 1693 FOCUS_UP, 1694 FOCUS_RIGHT, 1695 FOCUS_DOWN 1696 }) 1697 @Retention(RetentionPolicy.SOURCE) 1698 public @interface FocusDirection {} 1699 1700 /** @hide */ 1701 @IntDef(prefix = { "FOCUS_" }, value = { 1702 FOCUS_LEFT, 1703 FOCUS_UP, 1704 FOCUS_RIGHT, 1705 FOCUS_DOWN 1706 }) 1707 @Retention(RetentionPolicy.SOURCE) 1708 public @interface FocusRealDirection {} // Like @FocusDirection, but without forward/backward 1709 1710 /** 1711 * Use with {@link #focusSearch(int)}. Move focus to the previous selectable 1712 * item. 1713 */ 1714 public static final int FOCUS_BACKWARD = 0x00000001; 1715 1716 /** 1717 * Use with {@link #focusSearch(int)}. Move focus to the next selectable 1718 * item. 1719 */ 1720 public static final int FOCUS_FORWARD = 0x00000002; 1721 1722 /** 1723 * Use with {@link #focusSearch(int)}. Move focus to the left. 1724 */ 1725 public static final int FOCUS_LEFT = 0x00000011; 1726 1727 /** 1728 * Use with {@link #focusSearch(int)}. Move focus up. 1729 */ 1730 public static final int FOCUS_UP = 0x00000021; 1731 1732 /** 1733 * Use with {@link #focusSearch(int)}. Move focus to the right. 1734 */ 1735 public static final int FOCUS_RIGHT = 0x00000042; 1736 1737 /** 1738 * Use with {@link #focusSearch(int)}. Move focus down. 1739 */ 1740 public static final int FOCUS_DOWN = 0x00000082; 1741 1742 /** 1743 * Bits of {@link #getMeasuredWidthAndState()} and 1744 * {@link #getMeasuredWidthAndState()} that provide the actual measured size. 1745 */ 1746 public static final int MEASURED_SIZE_MASK = 0x00ffffff; 1747 1748 /** 1749 * Bits of {@link #getMeasuredWidthAndState()} and 1750 * {@link #getMeasuredWidthAndState()} that provide the additional state bits. 1751 */ 1752 public static final int MEASURED_STATE_MASK = 0xff000000; 1753 1754 /** 1755 * Bit shift of {@link #MEASURED_STATE_MASK} to get to the height bits 1756 * for functions that combine both width and height into a single int, 1757 * such as {@link #getMeasuredState()} and the childState argument of 1758 * {@link #resolveSizeAndState(int, int, int)}. 1759 */ 1760 public static final int MEASURED_HEIGHT_STATE_SHIFT = 16; 1761 1762 /** 1763 * Bit of {@link #getMeasuredWidthAndState()} and 1764 * {@link #getMeasuredWidthAndState()} that indicates the measured size 1765 * is smaller that the space the view would like to have. 1766 */ 1767 public static final int MEASURED_STATE_TOO_SMALL = 0x01000000; 1768 1769 /** 1770 * Base View state sets 1771 */ 1772 // Singles 1773 /** 1774 * Indicates the view has no states set. States are used with 1775 * {@link android.graphics.drawable.Drawable} to change the drawing of the 1776 * view depending on its state. 1777 * 1778 * @see android.graphics.drawable.Drawable 1779 * @see #getDrawableState() 1780 */ 1781 protected static final int[] EMPTY_STATE_SET; 1782 /** 1783 * Indicates the view is enabled. States are used with 1784 * {@link android.graphics.drawable.Drawable} to change the drawing of the 1785 * view depending on its state. 1786 * 1787 * @see android.graphics.drawable.Drawable 1788 * @see #getDrawableState() 1789 */ 1790 protected static final int[] ENABLED_STATE_SET; 1791 /** 1792 * Indicates the view is focused. States are used with 1793 * {@link android.graphics.drawable.Drawable} to change the drawing of the 1794 * view depending on its state. 1795 * 1796 * @see android.graphics.drawable.Drawable 1797 * @see #getDrawableState() 1798 */ 1799 protected static final int[] FOCUSED_STATE_SET; 1800 /** 1801 * Indicates the view is selected. States are used with 1802 * {@link android.graphics.drawable.Drawable} to change the drawing of the 1803 * view depending on its state. 1804 * 1805 * @see android.graphics.drawable.Drawable 1806 * @see #getDrawableState() 1807 */ 1808 protected static final int[] SELECTED_STATE_SET; 1809 /** 1810 * Indicates the view is pressed. States are used with 1811 * {@link android.graphics.drawable.Drawable} to change the drawing of the 1812 * view depending on its state. 1813 * 1814 * @see android.graphics.drawable.Drawable 1815 * @see #getDrawableState() 1816 */ 1817 protected static final int[] PRESSED_STATE_SET; 1818 /** 1819 * Indicates the view's window has focus. States are used with 1820 * {@link android.graphics.drawable.Drawable} to change the drawing of the 1821 * view depending on its state. 1822 * 1823 * @see android.graphics.drawable.Drawable 1824 * @see #getDrawableState() 1825 */ 1826 protected static final int[] WINDOW_FOCUSED_STATE_SET; 1827 // Doubles 1828 /** 1829 * Indicates the view is enabled and has the focus. 1830 * 1831 * @see #ENABLED_STATE_SET 1832 * @see #FOCUSED_STATE_SET 1833 */ 1834 protected static final int[] ENABLED_FOCUSED_STATE_SET; 1835 /** 1836 * Indicates the view is enabled and selected. 1837 * 1838 * @see #ENABLED_STATE_SET 1839 * @see #SELECTED_STATE_SET 1840 */ 1841 protected static final int[] ENABLED_SELECTED_STATE_SET; 1842 /** 1843 * Indicates the view is enabled and that its window has focus. 1844 * 1845 * @see #ENABLED_STATE_SET 1846 * @see #WINDOW_FOCUSED_STATE_SET 1847 */ 1848 protected static final int[] ENABLED_WINDOW_FOCUSED_STATE_SET; 1849 /** 1850 * Indicates the view is focused and selected. 1851 * 1852 * @see #FOCUSED_STATE_SET 1853 * @see #SELECTED_STATE_SET 1854 */ 1855 protected static final int[] FOCUSED_SELECTED_STATE_SET; 1856 /** 1857 * Indicates the view has the focus and that its window has the focus. 1858 * 1859 * @see #FOCUSED_STATE_SET 1860 * @see #WINDOW_FOCUSED_STATE_SET 1861 */ 1862 protected static final int[] FOCUSED_WINDOW_FOCUSED_STATE_SET; 1863 /** 1864 * Indicates the view is selected and that its window has the focus. 1865 * 1866 * @see #SELECTED_STATE_SET 1867 * @see #WINDOW_FOCUSED_STATE_SET 1868 */ 1869 protected static final int[] SELECTED_WINDOW_FOCUSED_STATE_SET; 1870 // Triples 1871 /** 1872 * Indicates the view is enabled, focused and selected. 1873 * 1874 * @see #ENABLED_STATE_SET 1875 * @see #FOCUSED_STATE_SET 1876 * @see #SELECTED_STATE_SET 1877 */ 1878 protected static final int[] ENABLED_FOCUSED_SELECTED_STATE_SET; 1879 /** 1880 * Indicates the view is enabled, focused and its window has the focus. 1881 * 1882 * @see #ENABLED_STATE_SET 1883 * @see #FOCUSED_STATE_SET 1884 * @see #WINDOW_FOCUSED_STATE_SET 1885 */ 1886 protected static final int[] ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET; 1887 /** 1888 * Indicates the view is enabled, selected and its window has the focus. 1889 * 1890 * @see #ENABLED_STATE_SET 1891 * @see #SELECTED_STATE_SET 1892 * @see #WINDOW_FOCUSED_STATE_SET 1893 */ 1894 protected static final int[] ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET; 1895 /** 1896 * Indicates the view is focused, selected and its window has the focus. 1897 * 1898 * @see #FOCUSED_STATE_SET 1899 * @see #SELECTED_STATE_SET 1900 * @see #WINDOW_FOCUSED_STATE_SET 1901 */ 1902 protected static final int[] FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 1903 /** 1904 * Indicates the view is enabled, focused, selected and its window 1905 * has the focus. 1906 * 1907 * @see #ENABLED_STATE_SET 1908 * @see #FOCUSED_STATE_SET 1909 * @see #SELECTED_STATE_SET 1910 * @see #WINDOW_FOCUSED_STATE_SET 1911 */ 1912 protected static final int[] ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 1913 /** 1914 * Indicates the view is pressed and its window has the focus. 1915 * 1916 * @see #PRESSED_STATE_SET 1917 * @see #WINDOW_FOCUSED_STATE_SET 1918 */ 1919 protected static final int[] PRESSED_WINDOW_FOCUSED_STATE_SET; 1920 /** 1921 * Indicates the view is pressed and selected. 1922 * 1923 * @see #PRESSED_STATE_SET 1924 * @see #SELECTED_STATE_SET 1925 */ 1926 protected static final int[] PRESSED_SELECTED_STATE_SET; 1927 /** 1928 * Indicates the view is pressed, selected and its window has the focus. 1929 * 1930 * @see #PRESSED_STATE_SET 1931 * @see #SELECTED_STATE_SET 1932 * @see #WINDOW_FOCUSED_STATE_SET 1933 */ 1934 protected static final int[] PRESSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 1935 /** 1936 * Indicates the view is pressed and focused. 1937 * 1938 * @see #PRESSED_STATE_SET 1939 * @see #FOCUSED_STATE_SET 1940 */ 1941 protected static final int[] PRESSED_FOCUSED_STATE_SET; 1942 /** 1943 * Indicates the view is pressed, focused and its window has the focus. 1944 * 1945 * @see #PRESSED_STATE_SET 1946 * @see #FOCUSED_STATE_SET 1947 * @see #WINDOW_FOCUSED_STATE_SET 1948 */ 1949 protected static final int[] PRESSED_FOCUSED_WINDOW_FOCUSED_STATE_SET; 1950 /** 1951 * Indicates the view is pressed, focused and selected. 1952 * 1953 * @see #PRESSED_STATE_SET 1954 * @see #SELECTED_STATE_SET 1955 * @see #FOCUSED_STATE_SET 1956 */ 1957 protected static final int[] PRESSED_FOCUSED_SELECTED_STATE_SET; 1958 /** 1959 * Indicates the view is pressed, focused, selected and its window has the focus. 1960 * 1961 * @see #PRESSED_STATE_SET 1962 * @see #FOCUSED_STATE_SET 1963 * @see #SELECTED_STATE_SET 1964 * @see #WINDOW_FOCUSED_STATE_SET 1965 */ 1966 protected static final int[] PRESSED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 1967 /** 1968 * Indicates the view is pressed and enabled. 1969 * 1970 * @see #PRESSED_STATE_SET 1971 * @see #ENABLED_STATE_SET 1972 */ 1973 protected static final int[] PRESSED_ENABLED_STATE_SET; 1974 /** 1975 * Indicates the view is pressed, enabled and its window has the focus. 1976 * 1977 * @see #PRESSED_STATE_SET 1978 * @see #ENABLED_STATE_SET 1979 * @see #WINDOW_FOCUSED_STATE_SET 1980 */ 1981 protected static final int[] PRESSED_ENABLED_WINDOW_FOCUSED_STATE_SET; 1982 /** 1983 * Indicates the view is pressed, enabled and selected. 1984 * 1985 * @see #PRESSED_STATE_SET 1986 * @see #ENABLED_STATE_SET 1987 * @see #SELECTED_STATE_SET 1988 */ 1989 protected static final int[] PRESSED_ENABLED_SELECTED_STATE_SET; 1990 /** 1991 * Indicates the view is pressed, enabled, selected and its window has the 1992 * focus. 1993 * 1994 * @see #PRESSED_STATE_SET 1995 * @see #ENABLED_STATE_SET 1996 * @see #SELECTED_STATE_SET 1997 * @see #WINDOW_FOCUSED_STATE_SET 1998 */ 1999 protected static final int[] PRESSED_ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET; 2000 /** 2001 * Indicates the view is pressed, enabled and focused. 2002 * 2003 * @see #PRESSED_STATE_SET 2004 * @see #ENABLED_STATE_SET 2005 * @see #FOCUSED_STATE_SET 2006 */ 2007 protected static final int[] PRESSED_ENABLED_FOCUSED_STATE_SET; 2008 /** 2009 * Indicates the view is pressed, enabled, focused and its window has the 2010 * focus. 2011 * 2012 * @see #PRESSED_STATE_SET 2013 * @see #ENABLED_STATE_SET 2014 * @see #FOCUSED_STATE_SET 2015 * @see #WINDOW_FOCUSED_STATE_SET 2016 */ 2017 protected static final int[] PRESSED_ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET; 2018 /** 2019 * Indicates the view is pressed, enabled, focused and selected. 2020 * 2021 * @see #PRESSED_STATE_SET 2022 * @see #ENABLED_STATE_SET 2023 * @see #SELECTED_STATE_SET 2024 * @see #FOCUSED_STATE_SET 2025 */ 2026 protected static final int[] PRESSED_ENABLED_FOCUSED_SELECTED_STATE_SET; 2027 /** 2028 * Indicates the view is pressed, enabled, focused, selected and its window 2029 * has the focus. 2030 * 2031 * @see #PRESSED_STATE_SET 2032 * @see #ENABLED_STATE_SET 2033 * @see #SELECTED_STATE_SET 2034 * @see #FOCUSED_STATE_SET 2035 * @see #WINDOW_FOCUSED_STATE_SET 2036 */ 2037 protected static final int[] PRESSED_ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 2038 2039 static { 2040 EMPTY_STATE_SET = StateSet.get(0); 2041 2042 WINDOW_FOCUSED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_WINDOW_FOCUSED); 2043 2044 SELECTED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_SELECTED); 2045 SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2046 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED); 2047 2048 FOCUSED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_FOCUSED); 2049 FOCUSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2050 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_FOCUSED); 2051 FOCUSED_SELECTED_STATE_SET = StateSet.get( 2052 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_FOCUSED); 2053 FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2054 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 2055 | StateSet.VIEW_STATE_FOCUSED); 2056 2057 ENABLED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_ENABLED); 2058 ENABLED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2059 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_ENABLED); 2060 ENABLED_SELECTED_STATE_SET = StateSet.get( 2061 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_ENABLED); 2062 ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2063 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 2064 | StateSet.VIEW_STATE_ENABLED); 2065 ENABLED_FOCUSED_STATE_SET = StateSet.get( 2066 StateSet.VIEW_STATE_FOCUSED | StateSet.VIEW_STATE_ENABLED); 2067 ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2068 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_FOCUSED 2069 | StateSet.VIEW_STATE_ENABLED); 2070 ENABLED_FOCUSED_SELECTED_STATE_SET = StateSet.get( 2071 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_FOCUSED 2072 | StateSet.VIEW_STATE_ENABLED); 2073 ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2074 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 2075 | StateSet.VIEW_STATE_FOCUSED| StateSet.VIEW_STATE_ENABLED); 2076 2077 PRESSED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_PRESSED); 2078 PRESSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2079 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_PRESSED); 2080 PRESSED_SELECTED_STATE_SET = StateSet.get( 2081 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_PRESSED); 2082 PRESSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2083 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 2084 | StateSet.VIEW_STATE_PRESSED); 2085 PRESSED_FOCUSED_STATE_SET = StateSet.get( 2086 StateSet.VIEW_STATE_FOCUSED | StateSet.VIEW_STATE_PRESSED); 2087 PRESSED_FOCUSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2088 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_FOCUSED 2089 | StateSet.VIEW_STATE_PRESSED); 2090 PRESSED_FOCUSED_SELECTED_STATE_SET = StateSet.get( 2091 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_FOCUSED 2092 | StateSet.VIEW_STATE_PRESSED); 2093 PRESSED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2094 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 2095 | StateSet.VIEW_STATE_FOCUSED | StateSet.VIEW_STATE_PRESSED); 2096 PRESSED_ENABLED_STATE_SET = StateSet.get( 2097 StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_PRESSED); 2098 PRESSED_ENABLED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2099 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_ENABLED 2100 | StateSet.VIEW_STATE_PRESSED); 2101 PRESSED_ENABLED_SELECTED_STATE_SET = StateSet.get( 2102 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_ENABLED 2103 | StateSet.VIEW_STATE_PRESSED); 2104 PRESSED_ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2105 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 2106 | StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_PRESSED); 2107 PRESSED_ENABLED_FOCUSED_STATE_SET = StateSet.get( 2108 StateSet.VIEW_STATE_FOCUSED | StateSet.VIEW_STATE_ENABLED 2109 | StateSet.VIEW_STATE_PRESSED); 2110 PRESSED_ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2111 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_FOCUSED 2112 | StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_PRESSED); 2113 PRESSED_ENABLED_FOCUSED_SELECTED_STATE_SET = StateSet.get( 2114 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_FOCUSED 2115 | StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_PRESSED); 2116 PRESSED_ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2117 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 2118 | StateSet.VIEW_STATE_FOCUSED| StateSet.VIEW_STATE_ENABLED 2119 | StateSet.VIEW_STATE_PRESSED); 2120 } 2121 2122 /** 2123 * Accessibility event types that are dispatched for text population. 2124 */ 2125 private static final int POPULATING_ACCESSIBILITY_EVENT_TYPES = 2126 AccessibilityEvent.TYPE_VIEW_CLICKED 2127 | AccessibilityEvent.TYPE_VIEW_LONG_CLICKED 2128 | AccessibilityEvent.TYPE_VIEW_SELECTED 2129 | AccessibilityEvent.TYPE_VIEW_FOCUSED 2130 | AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED 2131 | AccessibilityEvent.TYPE_VIEW_HOVER_ENTER 2132 | AccessibilityEvent.TYPE_VIEW_HOVER_EXIT 2133 | AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED 2134 | AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED 2135 | AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED 2136 | AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY; 2137 2138 static final int DEBUG_CORNERS_COLOR = Color.rgb(63, 127, 255); 2139 2140 static final int DEBUG_CORNERS_SIZE_DIP = 8; 2141 2142 /** 2143 * Temporary Rect currently for use in setBackground(). This will probably 2144 * be extended in the future to hold our own class with more than just 2145 * a Rect. :) 2146 */ 2147 static final ThreadLocal<Rect> sThreadLocal = new ThreadLocal<Rect>(); 2148 2149 /** 2150 * Map used to store views' tags. 2151 */ 2152 private SparseArray<Object> mKeyedTags; 2153 2154 /** 2155 * The next available accessibility id. 2156 */ 2157 private static int sNextAccessibilityViewId; 2158 2159 /** 2160 * The animation currently associated with this view. 2161 * @hide 2162 */ 2163 protected Animation mCurrentAnimation = null; 2164 2165 /** 2166 * Width as measured during measure pass. 2167 * {@hide} 2168 */ 2169 @ViewDebug.ExportedProperty(category = "measurement") 2170 int mMeasuredWidth; 2171 2172 /** 2173 * Height as measured during measure pass. 2174 * {@hide} 2175 */ 2176 @ViewDebug.ExportedProperty(category = "measurement") 2177 int mMeasuredHeight; 2178 2179 /** 2180 * Flag to indicate that this view was marked INVALIDATED, or had its display list 2181 * invalidated, prior to the current drawing iteration. If true, the view must re-draw 2182 * its display list. This flag, used only when hw accelerated, allows us to clear the 2183 * flag while retaining this information until it's needed (at getDisplayList() time and 2184 * in drawChild(), when we decide to draw a view's children's display lists into our own). 2185 * 2186 * {@hide} 2187 */ 2188 boolean mRecreateDisplayList = false; 2189 2190 /** 2191 * The view's identifier. 2192 * {@hide} 2193 * 2194 * @see #setId(int) 2195 * @see #getId() 2196 */ 2197 @IdRes 2198 @ViewDebug.ExportedProperty(resolveId = true) 2199 int mID = NO_ID; 2200 2201 /** The ID of this view for autofill purposes. 2202 * <ul> 2203 * <li>== {@link #NO_ID}: ID has not been assigned yet 2204 * <li>≤ {@link #LAST_APP_AUTOFILL_ID}: View is not part of a activity. The ID is 2205 * unique in the process. This might change 2206 * over activity lifecycle events. 2207 * <li>> {@link #LAST_APP_AUTOFILL_ID}: View is part of a activity. The ID is 2208 * unique in the activity. This stays the same 2209 * over activity lifecycle events. 2210 */ 2211 private int mAutofillViewId = NO_ID; 2212 2213 // ID for accessibility purposes. This ID must be unique for every window 2214 private int mAccessibilityViewId = NO_ID; 2215 2216 private int mAccessibilityCursorPosition = ACCESSIBILITY_CURSOR_POSITION_UNDEFINED; 2217 2218 /** 2219 * The view's tag. 2220 * {@hide} 2221 * 2222 * @see #setTag(Object) 2223 * @see #getTag() 2224 */ 2225 protected Object mTag = null; 2226 2227 // for mPrivateFlags: 2228 /** {@hide} */ 2229 static final int PFLAG_WANTS_FOCUS = 0x00000001; 2230 /** {@hide} */ 2231 static final int PFLAG_FOCUSED = 0x00000002; 2232 /** {@hide} */ 2233 static final int PFLAG_SELECTED = 0x00000004; 2234 /** {@hide} */ 2235 static final int PFLAG_IS_ROOT_NAMESPACE = 0x00000008; 2236 /** {@hide} */ 2237 static final int PFLAG_HAS_BOUNDS = 0x00000010; 2238 /** {@hide} */ 2239 static final int PFLAG_DRAWN = 0x00000020; 2240 /** 2241 * When this flag is set, this view is running an animation on behalf of its 2242 * children and should therefore not cancel invalidate requests, even if they 2243 * lie outside of this view's bounds. 2244 * 2245 * {@hide} 2246 */ 2247 static final int PFLAG_DRAW_ANIMATION = 0x00000040; 2248 /** {@hide} */ 2249 static final int PFLAG_SKIP_DRAW = 0x00000080; 2250 /** {@hide} */ 2251 static final int PFLAG_REQUEST_TRANSPARENT_REGIONS = 0x00000200; 2252 /** {@hide} */ 2253 static final int PFLAG_DRAWABLE_STATE_DIRTY = 0x00000400; 2254 /** {@hide} */ 2255 static final int PFLAG_MEASURED_DIMENSION_SET = 0x00000800; 2256 /** {@hide} */ 2257 static final int PFLAG_FORCE_LAYOUT = 0x00001000; 2258 /** {@hide} */ 2259 static final int PFLAG_LAYOUT_REQUIRED = 0x00002000; 2260 2261 private static final int PFLAG_PRESSED = 0x00004000; 2262 2263 /** {@hide} */ 2264 static final int PFLAG_DRAWING_CACHE_VALID = 0x00008000; 2265 /** 2266 * Flag used to indicate that this view should be drawn once more (and only once 2267 * more) after its animation has completed. 2268 * {@hide} 2269 */ 2270 static final int PFLAG_ANIMATION_STARTED = 0x00010000; 2271 2272 private static final int PFLAG_SAVE_STATE_CALLED = 0x00020000; 2273 2274 /** 2275 * Indicates that the View returned true when onSetAlpha() was called and that 2276 * the alpha must be restored. 2277 * {@hide} 2278 */ 2279 static final int PFLAG_ALPHA_SET = 0x00040000; 2280 2281 /** 2282 * Set by {@link #setScrollContainer(boolean)}. 2283 */ 2284 static final int PFLAG_SCROLL_CONTAINER = 0x00080000; 2285 2286 /** 2287 * Set by {@link #setScrollContainer(boolean)}. 2288 */ 2289 static final int PFLAG_SCROLL_CONTAINER_ADDED = 0x00100000; 2290 2291 /** 2292 * View flag indicating whether this view was invalidated (fully or partially.) 2293 * 2294 * @hide 2295 */ 2296 static final int PFLAG_DIRTY = 0x00200000; 2297 2298 /** 2299 * View flag indicating whether this view was invalidated by an opaque 2300 * invalidate request. 2301 * 2302 * @hide 2303 */ 2304 static final int PFLAG_DIRTY_OPAQUE = 0x00400000; 2305 2306 /** 2307 * Mask for {@link #PFLAG_DIRTY} and {@link #PFLAG_DIRTY_OPAQUE}. 2308 * 2309 * @hide 2310 */ 2311 static final int PFLAG_DIRTY_MASK = 0x00600000; 2312 2313 /** 2314 * Indicates whether the background is opaque. 2315 * 2316 * @hide 2317 */ 2318 static final int PFLAG_OPAQUE_BACKGROUND = 0x00800000; 2319 2320 /** 2321 * Indicates whether the scrollbars are opaque. 2322 * 2323 * @hide 2324 */ 2325 static final int PFLAG_OPAQUE_SCROLLBARS = 0x01000000; 2326 2327 /** 2328 * Indicates whether the view is opaque. 2329 * 2330 * @hide 2331 */ 2332 static final int PFLAG_OPAQUE_MASK = 0x01800000; 2333 2334 /** 2335 * Indicates a prepressed state; 2336 * the short time between ACTION_DOWN and recognizing 2337 * a 'real' press. Prepressed is used to recognize quick taps 2338 * even when they are shorter than ViewConfiguration.getTapTimeout(). 2339 * 2340 * @hide 2341 */ 2342 private static final int PFLAG_PREPRESSED = 0x02000000; 2343 2344 /** 2345 * Indicates whether the view is temporarily detached. 2346 * 2347 * @hide 2348 */ 2349 static final int PFLAG_CANCEL_NEXT_UP_EVENT = 0x04000000; 2350 2351 /** 2352 * Indicates that we should awaken scroll bars once attached 2353 * 2354 * PLEASE NOTE: This flag is now unused as we now send onVisibilityChanged 2355 * during window attachment and it is no longer needed. Feel free to repurpose it. 2356 * 2357 * @hide 2358 */ 2359 private static final int PFLAG_AWAKEN_SCROLL_BARS_ON_ATTACH = 0x08000000; 2360 2361 /** 2362 * Indicates that the view has received HOVER_ENTER. Cleared on HOVER_EXIT. 2363 * @hide 2364 */ 2365 private static final int PFLAG_HOVERED = 0x10000000; 2366 2367 /** 2368 * Flag set by {@link AutofillManager} if it needs to be notified when this view is clicked. 2369 */ 2370 private static final int PFLAG_NOTIFY_AUTOFILL_MANAGER_ON_CLICK = 0x20000000; 2371 2372 /** {@hide} */ 2373 static final int PFLAG_ACTIVATED = 0x40000000; 2374 2375 /** 2376 * Indicates that this view was specifically invalidated, not just dirtied because some 2377 * child view was invalidated. The flag is used to determine when we need to recreate 2378 * a view's display list (as opposed to just returning a reference to its existing 2379 * display list). 2380 * 2381 * @hide 2382 */ 2383 static final int PFLAG_INVALIDATED = 0x80000000; 2384 2385 /** 2386 * Masks for mPrivateFlags2, as generated by dumpFlags(): 2387 * 2388 * |-------|-------|-------|-------| 2389 * 1 PFLAG2_DRAG_CAN_ACCEPT 2390 * 1 PFLAG2_DRAG_HOVERED 2391 * 11 PFLAG2_LAYOUT_DIRECTION_MASK 2392 * 1 PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL 2393 * 1 PFLAG2_LAYOUT_DIRECTION_RESOLVED 2394 * 11 PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK 2395 * 1 PFLAG2_TEXT_DIRECTION_FLAGS[1] 2396 * 1 PFLAG2_TEXT_DIRECTION_FLAGS[2] 2397 * 11 PFLAG2_TEXT_DIRECTION_FLAGS[3] 2398 * 1 PFLAG2_TEXT_DIRECTION_FLAGS[4] 2399 * 1 1 PFLAG2_TEXT_DIRECTION_FLAGS[5] 2400 * 11 PFLAG2_TEXT_DIRECTION_FLAGS[6] 2401 * 111 PFLAG2_TEXT_DIRECTION_FLAGS[7] 2402 * 111 PFLAG2_TEXT_DIRECTION_MASK 2403 * 1 PFLAG2_TEXT_DIRECTION_RESOLVED 2404 * 1 PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT 2405 * 111 PFLAG2_TEXT_DIRECTION_RESOLVED_MASK 2406 * 1 PFLAG2_TEXT_ALIGNMENT_FLAGS[1] 2407 * 1 PFLAG2_TEXT_ALIGNMENT_FLAGS[2] 2408 * 11 PFLAG2_TEXT_ALIGNMENT_FLAGS[3] 2409 * 1 PFLAG2_TEXT_ALIGNMENT_FLAGS[4] 2410 * 1 1 PFLAG2_TEXT_ALIGNMENT_FLAGS[5] 2411 * 11 PFLAG2_TEXT_ALIGNMENT_FLAGS[6] 2412 * 111 PFLAG2_TEXT_ALIGNMENT_MASK 2413 * 1 PFLAG2_TEXT_ALIGNMENT_RESOLVED 2414 * 1 PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT 2415 * 111 PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK 2416 * 111 PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK 2417 * 11 PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK 2418 * 1 PFLAG2_ACCESSIBILITY_FOCUSED 2419 * 1 PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED 2420 * 1 PFLAG2_VIEW_QUICK_REJECTED 2421 * 1 PFLAG2_PADDING_RESOLVED 2422 * 1 PFLAG2_DRAWABLE_RESOLVED 2423 * 1 PFLAG2_HAS_TRANSIENT_STATE 2424 * |-------|-------|-------|-------| 2425 */ 2426 2427 /** 2428 * Indicates that this view has reported that it can accept the current drag's content. 2429 * Cleared when the drag operation concludes. 2430 * @hide 2431 */ 2432 static final int PFLAG2_DRAG_CAN_ACCEPT = 0x00000001; 2433 2434 /** 2435 * Indicates that this view is currently directly under the drag location in a 2436 * drag-and-drop operation involving content that it can accept. Cleared when 2437 * the drag exits the view, or when the drag operation concludes. 2438 * @hide 2439 */ 2440 static final int PFLAG2_DRAG_HOVERED = 0x00000002; 2441 2442 /** @hide */ 2443 @IntDef(prefix = { "LAYOUT_DIRECTION_" }, value = { 2444 LAYOUT_DIRECTION_LTR, 2445 LAYOUT_DIRECTION_RTL, 2446 LAYOUT_DIRECTION_INHERIT, 2447 LAYOUT_DIRECTION_LOCALE 2448 }) 2449 @Retention(RetentionPolicy.SOURCE) 2450 // Not called LayoutDirection to avoid conflict with android.util.LayoutDirection 2451 public @interface LayoutDir {} 2452 2453 /** @hide */ 2454 @IntDef(prefix = { "LAYOUT_DIRECTION_" }, value = { 2455 LAYOUT_DIRECTION_LTR, 2456 LAYOUT_DIRECTION_RTL 2457 }) 2458 @Retention(RetentionPolicy.SOURCE) 2459 public @interface ResolvedLayoutDir {} 2460 2461 /** 2462 * A flag to indicate that the layout direction of this view has not been defined yet. 2463 * @hide 2464 */ 2465 public static final int LAYOUT_DIRECTION_UNDEFINED = LayoutDirection.UNDEFINED; 2466 2467 /** 2468 * Horizontal layout direction of this view is from Left to Right. 2469 * Use with {@link #setLayoutDirection}. 2470 */ 2471 public static final int LAYOUT_DIRECTION_LTR = LayoutDirection.LTR; 2472 2473 /** 2474 * Horizontal layout direction of this view is from Right to Left. 2475 * Use with {@link #setLayoutDirection}. 2476 */ 2477 public static final int LAYOUT_DIRECTION_RTL = LayoutDirection.RTL; 2478 2479 /** 2480 * Horizontal layout direction of this view is inherited from its parent. 2481 * Use with {@link #setLayoutDirection}. 2482 */ 2483 public static final int LAYOUT_DIRECTION_INHERIT = LayoutDirection.INHERIT; 2484 2485 /** 2486 * Horizontal layout direction of this view is from deduced from the default language 2487 * script for the locale. Use with {@link #setLayoutDirection}. 2488 */ 2489 public static final int LAYOUT_DIRECTION_LOCALE = LayoutDirection.LOCALE; 2490 2491 /** 2492 * Bit shift to get the horizontal layout direction. (bits after DRAG_HOVERED) 2493 * @hide 2494 */ 2495 static final int PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT = 2; 2496 2497 /** 2498 * Mask for use with private flags indicating bits used for horizontal layout direction. 2499 * @hide 2500 */ 2501 static final int PFLAG2_LAYOUT_DIRECTION_MASK = 0x00000003 << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 2502 2503 /** 2504 * Indicates whether the view horizontal layout direction has been resolved and drawn to the 2505 * right-to-left direction. 2506 * @hide 2507 */ 2508 static final int PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL = 4 << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 2509 2510 /** 2511 * Indicates whether the view horizontal layout direction has been resolved. 2512 * @hide 2513 */ 2514 static final int PFLAG2_LAYOUT_DIRECTION_RESOLVED = 8 << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 2515 2516 /** 2517 * Mask for use with private flags indicating bits used for resolved horizontal layout direction. 2518 * @hide 2519 */ 2520 static final int PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK = 0x0000000C 2521 << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 2522 2523 /* 2524 * Array of horizontal layout direction flags for mapping attribute "layoutDirection" to correct 2525 * flag value. 2526 * @hide 2527 */ 2528 private static final int[] LAYOUT_DIRECTION_FLAGS = { 2529 LAYOUT_DIRECTION_LTR, 2530 LAYOUT_DIRECTION_RTL, 2531 LAYOUT_DIRECTION_INHERIT, 2532 LAYOUT_DIRECTION_LOCALE 2533 }; 2534 2535 /** 2536 * Default horizontal layout direction. 2537 */ 2538 private static final int LAYOUT_DIRECTION_DEFAULT = LAYOUT_DIRECTION_INHERIT; 2539 2540 /** 2541 * Default horizontal layout direction. 2542 * @hide 2543 */ 2544 static final int LAYOUT_DIRECTION_RESOLVED_DEFAULT = LAYOUT_DIRECTION_LTR; 2545 2546 /** 2547 * Text direction is inherited through {@link ViewGroup} 2548 */ 2549 public static final int TEXT_DIRECTION_INHERIT = 0; 2550 2551 /** 2552 * Text direction is using "first strong algorithm". The first strong directional character 2553 * determines the paragraph direction. If there is no strong directional character, the 2554 * paragraph direction is the view's resolved layout direction. 2555 */ 2556 public static final int TEXT_DIRECTION_FIRST_STRONG = 1; 2557 2558 /** 2559 * Text direction is using "any-RTL" algorithm. The paragraph direction is RTL if it contains 2560 * any strong RTL character, otherwise it is LTR if it contains any strong LTR characters. 2561 * If there are neither, the paragraph direction is the view's resolved layout direction. 2562 */ 2563 public static final int TEXT_DIRECTION_ANY_RTL = 2; 2564 2565 /** 2566 * Text direction is forced to LTR. 2567 */ 2568 public static final int TEXT_DIRECTION_LTR = 3; 2569 2570 /** 2571 * Text direction is forced to RTL. 2572 */ 2573 public static final int TEXT_DIRECTION_RTL = 4; 2574 2575 /** 2576 * Text direction is coming from the system Locale. 2577 */ 2578 public static final int TEXT_DIRECTION_LOCALE = 5; 2579 2580 /** 2581 * Text direction is using "first strong algorithm". The first strong directional character 2582 * determines the paragraph direction. If there is no strong directional character, the 2583 * paragraph direction is LTR. 2584 */ 2585 public static final int TEXT_DIRECTION_FIRST_STRONG_LTR = 6; 2586 2587 /** 2588 * Text direction is using "first strong algorithm". The first strong directional character 2589 * determines the paragraph direction. If there is no strong directional character, the 2590 * paragraph direction is RTL. 2591 */ 2592 public static final int TEXT_DIRECTION_FIRST_STRONG_RTL = 7; 2593 2594 /** 2595 * Default text direction is inherited 2596 */ 2597 private static final int TEXT_DIRECTION_DEFAULT = TEXT_DIRECTION_INHERIT; 2598 2599 /** 2600 * Default resolved text direction 2601 * @hide 2602 */ 2603 static final int TEXT_DIRECTION_RESOLVED_DEFAULT = TEXT_DIRECTION_FIRST_STRONG; 2604 2605 /** 2606 * Bit shift to get the horizontal layout direction. (bits after LAYOUT_DIRECTION_RESOLVED) 2607 * @hide 2608 */ 2609 static final int PFLAG2_TEXT_DIRECTION_MASK_SHIFT = 6; 2610 2611 /** 2612 * Mask for use with private flags indicating bits used for text direction. 2613 * @hide 2614 */ 2615 static final int PFLAG2_TEXT_DIRECTION_MASK = 0x00000007 2616 << PFLAG2_TEXT_DIRECTION_MASK_SHIFT; 2617 2618 /** 2619 * Array of text direction flags for mapping attribute "textDirection" to correct 2620 * flag value. 2621 * @hide 2622 */ 2623 private static final int[] PFLAG2_TEXT_DIRECTION_FLAGS = { 2624 TEXT_DIRECTION_INHERIT << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2625 TEXT_DIRECTION_FIRST_STRONG << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2626 TEXT_DIRECTION_ANY_RTL << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2627 TEXT_DIRECTION_LTR << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2628 TEXT_DIRECTION_RTL << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2629 TEXT_DIRECTION_LOCALE << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2630 TEXT_DIRECTION_FIRST_STRONG_LTR << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2631 TEXT_DIRECTION_FIRST_STRONG_RTL << PFLAG2_TEXT_DIRECTION_MASK_SHIFT 2632 }; 2633 2634 /** 2635 * Indicates whether the view text direction has been resolved. 2636 * @hide 2637 */ 2638 static final int PFLAG2_TEXT_DIRECTION_RESOLVED = 0x00000008 2639 << PFLAG2_TEXT_DIRECTION_MASK_SHIFT; 2640 2641 /** 2642 * Bit shift to get the horizontal layout direction. (bits after DRAG_HOVERED) 2643 * @hide 2644 */ 2645 static final int PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT = 10; 2646 2647 /** 2648 * Mask for use with private flags indicating bits used for resolved text direction. 2649 * @hide 2650 */ 2651 static final int PFLAG2_TEXT_DIRECTION_RESOLVED_MASK = 0x00000007 2652 << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT; 2653 2654 /** 2655 * Indicates whether the view text direction has been resolved to the "first strong" heuristic. 2656 * @hide 2657 */ 2658 static final int PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT = 2659 TEXT_DIRECTION_RESOLVED_DEFAULT << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT; 2660 2661 /** @hide */ 2662 @IntDef(prefix = { "TEXT_ALIGNMENT_" }, value = { 2663 TEXT_ALIGNMENT_INHERIT, 2664 TEXT_ALIGNMENT_GRAVITY, 2665 TEXT_ALIGNMENT_CENTER, 2666 TEXT_ALIGNMENT_TEXT_START, 2667 TEXT_ALIGNMENT_TEXT_END, 2668 TEXT_ALIGNMENT_VIEW_START, 2669 TEXT_ALIGNMENT_VIEW_END 2670 }) 2671 @Retention(RetentionPolicy.SOURCE) 2672 public @interface TextAlignment {} 2673 2674 /** 2675 * Default text alignment. The text alignment of this View is inherited from its parent. 2676 * Use with {@link #setTextAlignment(int)} 2677 */ 2678 public static final int TEXT_ALIGNMENT_INHERIT = 0; 2679 2680 /** 2681 * Default for the root view. The gravity determines the text alignment, ALIGN_NORMAL, 2682 * ALIGN_CENTER, or ALIGN_OPPOSITE, which are relative to each paragraph’s text direction. 2683 * 2684 * Use with {@link #setTextAlignment(int)} 2685 */ 2686 public static final int TEXT_ALIGNMENT_GRAVITY = 1; 2687 2688 /** 2689 * Align to the start of the paragraph, e.g. ALIGN_NORMAL. 2690 * 2691 * Use with {@link #setTextAlignment(int)} 2692 */ 2693 public static final int TEXT_ALIGNMENT_TEXT_START = 2; 2694 2695 /** 2696 * Align to the end of the paragraph, e.g. ALIGN_OPPOSITE. 2697 * 2698 * Use with {@link #setTextAlignment(int)} 2699 */ 2700 public static final int TEXT_ALIGNMENT_TEXT_END = 3; 2701 2702 /** 2703 * Center the paragraph, e.g. ALIGN_CENTER. 2704 * 2705 * Use with {@link #setTextAlignment(int)} 2706 */ 2707 public static final int TEXT_ALIGNMENT_CENTER = 4; 2708 2709 /** 2710 * Align to the start of the view, which is ALIGN_LEFT if the view’s resolved 2711 * layoutDirection is LTR, and ALIGN_RIGHT otherwise. 2712 * 2713 * Use with {@link #setTextAlignment(int)} 2714 */ 2715 public static final int TEXT_ALIGNMENT_VIEW_START = 5; 2716 2717 /** 2718 * Align to the end of the view, which is ALIGN_RIGHT if the view’s resolved 2719 * layoutDirection is LTR, and ALIGN_LEFT otherwise. 2720 * 2721 * Use with {@link #setTextAlignment(int)} 2722 */ 2723 public static final int TEXT_ALIGNMENT_VIEW_END = 6; 2724 2725 /** 2726 * Default text alignment is inherited 2727 */ 2728 private static final int TEXT_ALIGNMENT_DEFAULT = TEXT_ALIGNMENT_GRAVITY; 2729 2730 /** 2731 * Default resolved text alignment 2732 * @hide 2733 */ 2734 static final int TEXT_ALIGNMENT_RESOLVED_DEFAULT = TEXT_ALIGNMENT_GRAVITY; 2735 2736 /** 2737 * Bit shift to get the horizontal layout direction. (bits after DRAG_HOVERED) 2738 * @hide 2739 */ 2740 static final int PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT = 13; 2741 2742 /** 2743 * Mask for use with private flags indicating bits used for text alignment. 2744 * @hide 2745 */ 2746 static final int PFLAG2_TEXT_ALIGNMENT_MASK = 0x00000007 << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT; 2747 2748 /** 2749 * Array of text direction flags for mapping attribute "textAlignment" to correct 2750 * flag value. 2751 * @hide 2752 */ 2753 private static final int[] PFLAG2_TEXT_ALIGNMENT_FLAGS = { 2754 TEXT_ALIGNMENT_INHERIT << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 2755 TEXT_ALIGNMENT_GRAVITY << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 2756 TEXT_ALIGNMENT_TEXT_START << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 2757 TEXT_ALIGNMENT_TEXT_END << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 2758 TEXT_ALIGNMENT_CENTER << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 2759 TEXT_ALIGNMENT_VIEW_START << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 2760 TEXT_ALIGNMENT_VIEW_END << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT 2761 }; 2762 2763 /** 2764 * Indicates whether the view text alignment has been resolved. 2765 * @hide 2766 */ 2767 static final int PFLAG2_TEXT_ALIGNMENT_RESOLVED = 0x00000008 << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT; 2768 2769 /** 2770 * Bit shift to get the resolved text alignment. 2771 * @hide 2772 */ 2773 static final int PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT = 17; 2774 2775 /** 2776 * Mask for use with private flags indicating bits used for text alignment. 2777 * @hide 2778 */ 2779 static final int PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK = 0x00000007 2780 << PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT; 2781 2782 /** 2783 * Indicates whether if the view text alignment has been resolved to gravity 2784 */ 2785 private static final int PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT = 2786 TEXT_ALIGNMENT_RESOLVED_DEFAULT << PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT; 2787 2788 // Accessiblity constants for mPrivateFlags2 2789 2790 /** 2791 * Shift for the bits in {@link #mPrivateFlags2} related to the 2792 * "importantForAccessibility" attribute. 2793 */ 2794 static final int PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT = 20; 2795 2796 /** 2797 * Automatically determine whether a view is important for accessibility. 2798 */ 2799 public static final int IMPORTANT_FOR_ACCESSIBILITY_AUTO = 0x00000000; 2800 2801 /** 2802 * The view is important for accessibility. 2803 */ 2804 public static final int IMPORTANT_FOR_ACCESSIBILITY_YES = 0x00000001; 2805 2806 /** 2807 * The view is not important for accessibility. 2808 */ 2809 public static final int IMPORTANT_FOR_ACCESSIBILITY_NO = 0x00000002; 2810 2811 /** 2812 * The view is not important for accessibility, nor are any of its 2813 * descendant views. 2814 */ 2815 public static final int IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS = 0x00000004; 2816 2817 /** 2818 * The default whether the view is important for accessibility. 2819 */ 2820 static final int IMPORTANT_FOR_ACCESSIBILITY_DEFAULT = IMPORTANT_FOR_ACCESSIBILITY_AUTO; 2821 2822 /** 2823 * Mask for obtaining the bits which specify how to determine 2824 * whether a view is important for accessibility. 2825 */ 2826 static final int PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK = (IMPORTANT_FOR_ACCESSIBILITY_AUTO 2827 | IMPORTANT_FOR_ACCESSIBILITY_YES | IMPORTANT_FOR_ACCESSIBILITY_NO 2828 | IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS) 2829 << PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT; 2830 2831 /** 2832 * Shift for the bits in {@link #mPrivateFlags2} related to the 2833 * "accessibilityLiveRegion" attribute. 2834 */ 2835 static final int PFLAG2_ACCESSIBILITY_LIVE_REGION_SHIFT = 23; 2836 2837 /** 2838 * Live region mode specifying that accessibility services should not 2839 * automatically announce changes to this view. This is the default live 2840 * region mode for most views. 2841 * <p> 2842 * Use with {@link #setAccessibilityLiveRegion(int)}. 2843 */ 2844 public static final int ACCESSIBILITY_LIVE_REGION_NONE = 0x00000000; 2845 2846 /** 2847 * Live region mode specifying that accessibility services should announce 2848 * changes to this view. 2849 * <p> 2850 * Use with {@link #setAccessibilityLiveRegion(int)}. 2851 */ 2852 public static final int ACCESSIBILITY_LIVE_REGION_POLITE = 0x00000001; 2853 2854 /** 2855 * Live region mode specifying that accessibility services should interrupt 2856 * ongoing speech to immediately announce changes to this view. 2857 * <p> 2858 * Use with {@link #setAccessibilityLiveRegion(int)}. 2859 */ 2860 public static final int ACCESSIBILITY_LIVE_REGION_ASSERTIVE = 0x00000002; 2861 2862 /** 2863 * The default whether the view is important for accessibility. 2864 */ 2865 static final int ACCESSIBILITY_LIVE_REGION_DEFAULT = ACCESSIBILITY_LIVE_REGION_NONE; 2866 2867 /** 2868 * Mask for obtaining the bits which specify a view's accessibility live 2869 * region mode. 2870 */ 2871 static final int PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK = (ACCESSIBILITY_LIVE_REGION_NONE 2872 | ACCESSIBILITY_LIVE_REGION_POLITE | ACCESSIBILITY_LIVE_REGION_ASSERTIVE) 2873 << PFLAG2_ACCESSIBILITY_LIVE_REGION_SHIFT; 2874 2875 /** 2876 * Flag indicating whether a view has accessibility focus. 2877 */ 2878 static final int PFLAG2_ACCESSIBILITY_FOCUSED = 0x04000000; 2879 2880 /** 2881 * Flag whether the accessibility state of the subtree rooted at this view changed. 2882 */ 2883 static final int PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED = 0x08000000; 2884 2885 /** 2886 * Flag indicating whether a view failed the quickReject() check in draw(). This condition 2887 * is used to check whether later changes to the view's transform should invalidate the 2888 * view to force the quickReject test to run again. 2889 */ 2890 static final int PFLAG2_VIEW_QUICK_REJECTED = 0x10000000; 2891 2892 /** 2893 * Flag indicating that start/end padding has been resolved into left/right padding 2894 * for use in measurement, layout, drawing, etc. This is set by {@link #resolvePadding()} 2895 * and checked by {@link #measure(int, int)} to determine if padding needs to be resolved 2896 * during measurement. In some special cases this is required such as when an adapter-based 2897 * view measures prospective children without attaching them to a window. 2898 */ 2899 static final int PFLAG2_PADDING_RESOLVED = 0x20000000; 2900 2901 /** 2902 * Flag indicating that the start/end drawables has been resolved into left/right ones. 2903 */ 2904 static final int PFLAG2_DRAWABLE_RESOLVED = 0x40000000; 2905 2906 /** 2907 * Indicates that the view is tracking some sort of transient state 2908 * that the app should not need to be aware of, but that the framework 2909 * should take special care to preserve. 2910 */ 2911 static final int PFLAG2_HAS_TRANSIENT_STATE = 0x80000000; 2912 2913 /** 2914 * Group of bits indicating that RTL properties resolution is done. 2915 */ 2916 static final int ALL_RTL_PROPERTIES_RESOLVED = PFLAG2_LAYOUT_DIRECTION_RESOLVED | 2917 PFLAG2_TEXT_DIRECTION_RESOLVED | 2918 PFLAG2_TEXT_ALIGNMENT_RESOLVED | 2919 PFLAG2_PADDING_RESOLVED | 2920 PFLAG2_DRAWABLE_RESOLVED; 2921 2922 // There are a couple of flags left in mPrivateFlags2 2923 2924 /* End of masks for mPrivateFlags2 */ 2925 2926 /** 2927 * Masks for mPrivateFlags3, as generated by dumpFlags(): 2928 * 2929 * |-------|-------|-------|-------| 2930 * 1 PFLAG3_VIEW_IS_ANIMATING_TRANSFORM 2931 * 1 PFLAG3_VIEW_IS_ANIMATING_ALPHA 2932 * 1 PFLAG3_IS_LAID_OUT 2933 * 1 PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT 2934 * 1 PFLAG3_CALLED_SUPER 2935 * 1 PFLAG3_APPLYING_INSETS 2936 * 1 PFLAG3_FITTING_SYSTEM_WINDOWS 2937 * 1 PFLAG3_NESTED_SCROLLING_ENABLED 2938 * 1 PFLAG3_SCROLL_INDICATOR_TOP 2939 * 1 PFLAG3_SCROLL_INDICATOR_BOTTOM 2940 * 1 PFLAG3_SCROLL_INDICATOR_LEFT 2941 * 1 PFLAG3_SCROLL_INDICATOR_RIGHT 2942 * 1 PFLAG3_SCROLL_INDICATOR_START 2943 * 1 PFLAG3_SCROLL_INDICATOR_END 2944 * 1 PFLAG3_ASSIST_BLOCKED 2945 * 1 PFLAG3_CLUSTER 2946 * 1 PFLAG3_IS_AUTOFILLED 2947 * 1 PFLAG3_FINGER_DOWN 2948 * 1 PFLAG3_FOCUSED_BY_DEFAULT 2949 * 1111 PFLAG3_IMPORTANT_FOR_AUTOFILL 2950 * 1 PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE 2951 * 1 PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED 2952 * 1 PFLAG3_TEMPORARY_DETACH 2953 * 1 PFLAG3_NO_REVEAL_ON_FOCUS 2954 * 1 PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT 2955 * 1 PFLAG3_SCREEN_READER_FOCUSABLE 2956 * 1 PFLAG3_AGGREGATED_VISIBLE 2957 * 1 PFLAG3_AUTOFILLID_EXPLICITLY_SET 2958 * 1 available 2959 * |-------|-------|-------|-------| 2960 */ 2961 2962 /** 2963 * Flag indicating that view has a transform animation set on it. This is used to track whether 2964 * an animation is cleared between successive frames, in order to tell the associated 2965 * DisplayList to clear its animation matrix. 2966 */ 2967 static final int PFLAG3_VIEW_IS_ANIMATING_TRANSFORM = 0x1; 2968 2969 /** 2970 * Flag indicating that view has an alpha animation set on it. This is used to track whether an 2971 * animation is cleared between successive frames, in order to tell the associated 2972 * DisplayList to restore its alpha value. 2973 */ 2974 static final int PFLAG3_VIEW_IS_ANIMATING_ALPHA = 0x2; 2975 2976 /** 2977 * Flag indicating that the view has been through at least one layout since it 2978 * was last attached to a window. 2979 */ 2980 static final int PFLAG3_IS_LAID_OUT = 0x4; 2981 2982 /** 2983 * Flag indicating that a call to measure() was skipped and should be done 2984 * instead when layout() is invoked. 2985 */ 2986 static final int PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT = 0x8; 2987 2988 /** 2989 * Flag indicating that an overridden method correctly called down to 2990 * the superclass implementation as required by the API spec. 2991 */ 2992 static final int PFLAG3_CALLED_SUPER = 0x10; 2993 2994 /** 2995 * Flag indicating that we're in the process of applying window insets. 2996 */ 2997 static final int PFLAG3_APPLYING_INSETS = 0x20; 2998 2999 /** 3000 * Flag indicating that we're in the process of fitting system windows using the old method. 3001 */ 3002 static final int PFLAG3_FITTING_SYSTEM_WINDOWS = 0x40; 3003 3004 /** 3005 * Flag indicating that nested scrolling is enabled for this view. 3006 * The view will optionally cooperate with views up its parent chain to allow for 3007 * integrated nested scrolling along the same axis. 3008 */ 3009 static final int PFLAG3_NESTED_SCROLLING_ENABLED = 0x80; 3010 3011 /** 3012 * Flag indicating that the bottom scroll indicator should be displayed 3013 * when this view can scroll up. 3014 */ 3015 static final int PFLAG3_SCROLL_INDICATOR_TOP = 0x0100; 3016 3017 /** 3018 * Flag indicating that the bottom scroll indicator should be displayed 3019 * when this view can scroll down. 3020 */ 3021 static final int PFLAG3_SCROLL_INDICATOR_BOTTOM = 0x0200; 3022 3023 /** 3024 * Flag indicating that the left scroll indicator should be displayed 3025 * when this view can scroll left. 3026 */ 3027 static final int PFLAG3_SCROLL_INDICATOR_LEFT = 0x0400; 3028 3029 /** 3030 * Flag indicating that the right scroll indicator should be displayed 3031 * when this view can scroll right. 3032 */ 3033 static final int PFLAG3_SCROLL_INDICATOR_RIGHT = 0x0800; 3034 3035 /** 3036 * Flag indicating that the start scroll indicator should be displayed 3037 * when this view can scroll in the start direction. 3038 */ 3039 static final int PFLAG3_SCROLL_INDICATOR_START = 0x1000; 3040 3041 /** 3042 * Flag indicating that the end scroll indicator should be displayed 3043 * when this view can scroll in the end direction. 3044 */ 3045 static final int PFLAG3_SCROLL_INDICATOR_END = 0x2000; 3046 3047 static final int DRAG_MASK = PFLAG2_DRAG_CAN_ACCEPT | PFLAG2_DRAG_HOVERED; 3048 3049 static final int SCROLL_INDICATORS_NONE = 0x0000; 3050 3051 /** 3052 * Mask for use with setFlags indicating bits used for indicating which 3053 * scroll indicators are enabled. 3054 */ 3055 static final int SCROLL_INDICATORS_PFLAG3_MASK = PFLAG3_SCROLL_INDICATOR_TOP 3056 | PFLAG3_SCROLL_INDICATOR_BOTTOM | PFLAG3_SCROLL_INDICATOR_LEFT 3057 | PFLAG3_SCROLL_INDICATOR_RIGHT | PFLAG3_SCROLL_INDICATOR_START 3058 | PFLAG3_SCROLL_INDICATOR_END; 3059 3060 /** 3061 * Left-shift required to translate between public scroll indicator flags 3062 * and internal PFLAGS3 flags. When used as a right-shift, translates 3063 * PFLAGS3 flags to public flags. 3064 */ 3065 static final int SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT = 8; 3066 3067 /** @hide */ 3068 @Retention(RetentionPolicy.SOURCE) 3069 @IntDef(flag = true, prefix = { "SCROLL_INDICATOR_" }, value = { 3070 SCROLL_INDICATOR_TOP, 3071 SCROLL_INDICATOR_BOTTOM, 3072 SCROLL_INDICATOR_LEFT, 3073 SCROLL_INDICATOR_RIGHT, 3074 SCROLL_INDICATOR_START, 3075 SCROLL_INDICATOR_END, 3076 }) 3077 public @interface ScrollIndicators {} 3078 3079 /** 3080 * Scroll indicator direction for the top edge of the view. 3081 * 3082 * @see #setScrollIndicators(int) 3083 * @see #setScrollIndicators(int, int) 3084 * @see #getScrollIndicators() 3085 */ 3086 public static final int SCROLL_INDICATOR_TOP = 3087 PFLAG3_SCROLL_INDICATOR_TOP >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 3088 3089 /** 3090 * Scroll indicator direction for the bottom edge of the view. 3091 * 3092 * @see #setScrollIndicators(int) 3093 * @see #setScrollIndicators(int, int) 3094 * @see #getScrollIndicators() 3095 */ 3096 public static final int SCROLL_INDICATOR_BOTTOM = 3097 PFLAG3_SCROLL_INDICATOR_BOTTOM >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 3098 3099 /** 3100 * Scroll indicator direction for the left edge of the view. 3101 * 3102 * @see #setScrollIndicators(int) 3103 * @see #setScrollIndicators(int, int) 3104 * @see #getScrollIndicators() 3105 */ 3106 public static final int SCROLL_INDICATOR_LEFT = 3107 PFLAG3_SCROLL_INDICATOR_LEFT >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 3108 3109 /** 3110 * Scroll indicator direction for the right edge of the view. 3111 * 3112 * @see #setScrollIndicators(int) 3113 * @see #setScrollIndicators(int, int) 3114 * @see #getScrollIndicators() 3115 */ 3116 public static final int SCROLL_INDICATOR_RIGHT = 3117 PFLAG3_SCROLL_INDICATOR_RIGHT >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 3118 3119 /** 3120 * Scroll indicator direction for the starting edge of the view. 3121 * <p> 3122 * Resolved according to the view's layout direction, see 3123 * {@link #getLayoutDirection()} for more information. 3124 * 3125 * @see #setScrollIndicators(int) 3126 * @see #setScrollIndicators(int, int) 3127 * @see #getScrollIndicators() 3128 */ 3129 public static final int SCROLL_INDICATOR_START = 3130 PFLAG3_SCROLL_INDICATOR_START >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 3131 3132 /** 3133 * Scroll indicator direction for the ending edge of the view. 3134 * <p> 3135 * Resolved according to the view's layout direction, see 3136 * {@link #getLayoutDirection()} for more information. 3137 * 3138 * @see #setScrollIndicators(int) 3139 * @see #setScrollIndicators(int, int) 3140 * @see #getScrollIndicators() 3141 */ 3142 public static final int SCROLL_INDICATOR_END = 3143 PFLAG3_SCROLL_INDICATOR_END >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 3144 3145 /** 3146 * <p>Indicates that we are allowing {@link ViewStructure} to traverse 3147 * into this view.<p> 3148 */ 3149 static final int PFLAG3_ASSIST_BLOCKED = 0x4000; 3150 3151 /** 3152 * Flag indicating that the view is a root of a keyboard navigation cluster. 3153 * 3154 * @see #isKeyboardNavigationCluster() 3155 * @see #setKeyboardNavigationCluster(boolean) 3156 */ 3157 private static final int PFLAG3_CLUSTER = 0x8000; 3158 3159 /** 3160 * Flag indicating that the view is autofilled 3161 * 3162 * @see #isAutofilled() 3163 * @see #setAutofilled(boolean) 3164 */ 3165 private static final int PFLAG3_IS_AUTOFILLED = 0x10000; 3166 3167 /** 3168 * Indicates that the user is currently touching the screen. 3169 * Currently used for the tooltip positioning only. 3170 */ 3171 private static final int PFLAG3_FINGER_DOWN = 0x20000; 3172 3173 /** 3174 * Flag indicating that this view is the default-focus view. 3175 * 3176 * @see #isFocusedByDefault() 3177 * @see #setFocusedByDefault(boolean) 3178 */ 3179 private static final int PFLAG3_FOCUSED_BY_DEFAULT = 0x40000; 3180 3181 /** 3182 * Shift for the bits in {@link #mPrivateFlags3} related to the 3183 * "importantForAutofill" attribute. 3184 */ 3185 static final int PFLAG3_IMPORTANT_FOR_AUTOFILL_SHIFT = 19; 3186 3187 /** 3188 * Mask for obtaining the bits which specify how to determine 3189 * whether a view is important for autofill. 3190 */ 3191 static final int PFLAG3_IMPORTANT_FOR_AUTOFILL_MASK = (IMPORTANT_FOR_AUTOFILL_AUTO 3192 | IMPORTANT_FOR_AUTOFILL_YES | IMPORTANT_FOR_AUTOFILL_NO 3193 | IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS 3194 | IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS) 3195 << PFLAG3_IMPORTANT_FOR_AUTOFILL_SHIFT; 3196 3197 /** 3198 * Whether this view has rendered elements that overlap (see {@link 3199 * #hasOverlappingRendering()}, {@link #forceHasOverlappingRendering(boolean)}, and 3200 * {@link #getHasOverlappingRendering()} ). The value in this bit is only valid when 3201 * PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED has been set. Otherwise, the value is 3202 * determined by whatever {@link #hasOverlappingRendering()} returns. 3203 */ 3204 private static final int PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE = 0x800000; 3205 3206 /** 3207 * Whether {@link #forceHasOverlappingRendering(boolean)} has been called. When true, value 3208 * in PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE is valid. 3209 */ 3210 private static final int PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED = 0x1000000; 3211 3212 /** 3213 * Flag indicating that the view is temporarily detached from the parent view. 3214 * 3215 * @see #onStartTemporaryDetach() 3216 * @see #onFinishTemporaryDetach() 3217 */ 3218 static final int PFLAG3_TEMPORARY_DETACH = 0x2000000; 3219 3220 /** 3221 * Flag indicating that the view does not wish to be revealed within its parent 3222 * hierarchy when it gains focus. Expressed in the negative since the historical 3223 * default behavior is to reveal on focus; this flag suppresses that behavior. 3224 * 3225 * @see #setRevealOnFocusHint(boolean) 3226 * @see #getRevealOnFocusHint() 3227 */ 3228 private static final int PFLAG3_NO_REVEAL_ON_FOCUS = 0x4000000; 3229 3230 /** 3231 * Flag indicating that when layout is completed we should notify 3232 * that the view was entered for autofill purposes. To minimize 3233 * showing autofill for views not visible to the user we evaluate 3234 * user visibility which cannot be done until the view is laid out. 3235 */ 3236 static final int PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT = 0x8000000; 3237 3238 /** 3239 * Works like focusable for screen readers, but without the side effects on input focus. 3240 * @see #setScreenReaderFocusable(boolean) 3241 */ 3242 private static final int PFLAG3_SCREEN_READER_FOCUSABLE = 0x10000000; 3243 3244 /** 3245 * The last aggregated visibility. Used to detect when it truly changes. 3246 */ 3247 private static final int PFLAG3_AGGREGATED_VISIBLE = 0x20000000; 3248 3249 /** 3250 * Used to indicate that {@link #mAutofillId} was explicitly set through 3251 * {@link #setAutofillId(AutofillId)}. 3252 */ 3253 private static final int PFLAG3_AUTOFILLID_EXPLICITLY_SET = 0x40000000; 3254 3255 /* End of masks for mPrivateFlags3 */ 3256 3257 /** 3258 * Always allow a user to over-scroll this view, provided it is a 3259 * view that can scroll. 3260 * 3261 * @see #getOverScrollMode() 3262 * @see #setOverScrollMode(int) 3263 */ 3264 public static final int OVER_SCROLL_ALWAYS = 0; 3265 3266 /** 3267 * Allow a user to over-scroll this view only if the content is large 3268 * enough to meaningfully scroll, provided it is a view that can scroll. 3269 * 3270 * @see #getOverScrollMode() 3271 * @see #setOverScrollMode(int) 3272 */ 3273 public static final int OVER_SCROLL_IF_CONTENT_SCROLLS = 1; 3274 3275 /** 3276 * Never allow a user to over-scroll this view. 3277 * 3278 * @see #getOverScrollMode() 3279 * @see #setOverScrollMode(int) 3280 */ 3281 public static final int OVER_SCROLL_NEVER = 2; 3282 3283 /** 3284 * Special constant for {@link #setSystemUiVisibility(int)}: View has 3285 * requested the system UI (status bar) to be visible (the default). 3286 * 3287 * @see #setSystemUiVisibility(int) 3288 */ 3289 public static final int SYSTEM_UI_FLAG_VISIBLE = 0; 3290 3291 /** 3292 * Flag for {@link #setSystemUiVisibility(int)}: View has requested the 3293 * system UI to enter an unobtrusive "low profile" mode. 3294 * 3295 * <p>This is for use in games, book readers, video players, or any other 3296 * "immersive" application where the usual system chrome is deemed too distracting. 3297 * 3298 * <p>In low profile mode, the status bar and/or navigation icons may dim. 3299 * 3300 * @see #setSystemUiVisibility(int) 3301 */ 3302 public static final int SYSTEM_UI_FLAG_LOW_PROFILE = 0x00000001; 3303 3304 /** 3305 * Flag for {@link #setSystemUiVisibility(int)}: View has requested that the 3306 * system navigation be temporarily hidden. 3307 * 3308 * <p>This is an even less obtrusive state than that called for by 3309 * {@link #SYSTEM_UI_FLAG_LOW_PROFILE}; on devices that draw essential navigation controls 3310 * (Home, Back, and the like) on screen, <code>SYSTEM_UI_FLAG_HIDE_NAVIGATION</code> will cause 3311 * those to disappear. This is useful (in conjunction with the 3312 * {@link android.view.WindowManager.LayoutParams#FLAG_FULLSCREEN FLAG_FULLSCREEN} and 3313 * {@link android.view.WindowManager.LayoutParams#FLAG_LAYOUT_IN_SCREEN FLAG_LAYOUT_IN_SCREEN} 3314 * window flags) for displaying content using every last pixel on the display. 3315 * 3316 * <p>There is a limitation: because navigation controls are so important, the least user 3317 * interaction will cause them to reappear immediately. When this happens, both 3318 * this flag and {@link #SYSTEM_UI_FLAG_FULLSCREEN} will be cleared automatically, 3319 * so that both elements reappear at the same time. 3320 * 3321 * @see #setSystemUiVisibility(int) 3322 */ 3323 public static final int SYSTEM_UI_FLAG_HIDE_NAVIGATION = 0x00000002; 3324 3325 /** 3326 * Flag for {@link #setSystemUiVisibility(int)}: View has requested to go 3327 * into the normal fullscreen mode so that its content can take over the screen 3328 * while still allowing the user to interact with the application. 3329 * 3330 * <p>This has the same visual effect as 3331 * {@link android.view.WindowManager.LayoutParams#FLAG_FULLSCREEN 3332 * WindowManager.LayoutParams.FLAG_FULLSCREEN}, 3333 * meaning that non-critical screen decorations (such as the status bar) will be 3334 * hidden while the user is in the View's window, focusing the experience on 3335 * that content. Unlike the window flag, if you are using ActionBar in 3336 * overlay mode with {@link Window#FEATURE_ACTION_BAR_OVERLAY 3337 * Window.FEATURE_ACTION_BAR_OVERLAY}, then enabling this flag will also 3338 * hide the action bar. 3339 * 3340 * <p>This approach to going fullscreen is best used over the window flag when 3341 * it is a transient state -- that is, the application does this at certain 3342 * points in its user interaction where it wants to allow the user to focus 3343 * on content, but not as a continuous state. For situations where the application 3344 * would like to simply stay full screen the entire time (such as a game that 3345 * wants to take over the screen), the 3346 * {@link android.view.WindowManager.LayoutParams#FLAG_FULLSCREEN window flag} 3347 * is usually a better approach. The state set here will be removed by the system 3348 * in various situations (such as the user moving to another application) like 3349 * the other system UI states. 3350 * 3351 * <p>When using this flag, the application should provide some easy facility 3352 * for the user to go out of it. A common example would be in an e-book 3353 * reader, where tapping on the screen brings back whatever screen and UI 3354 * decorations that had been hidden while the user was immersed in reading 3355 * the book. 3356 * 3357 * @see #setSystemUiVisibility(int) 3358 */ 3359 public static final int SYSTEM_UI_FLAG_FULLSCREEN = 0x00000004; 3360 3361 /** 3362 * Flag for {@link #setSystemUiVisibility(int)}: When using other layout 3363 * flags, we would like a stable view of the content insets given to 3364 * {@link #fitSystemWindows(Rect)}. This means that the insets seen there 3365 * will always represent the worst case that the application can expect 3366 * as a continuous state. In the stock Android UI this is the space for 3367 * the system bar, nav bar, and status bar, but not more transient elements 3368 * such as an input method. 3369 * 3370 * The stable layout your UI sees is based on the system UI modes you can 3371 * switch to. That is, if you specify {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN} 3372 * then you will get a stable layout for changes of the 3373 * {@link #SYSTEM_UI_FLAG_FULLSCREEN} mode; if you specify 3374 * {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN} and 3375 * {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION}, then you can transition 3376 * to {@link #SYSTEM_UI_FLAG_FULLSCREEN} and {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION} 3377 * with a stable layout. (Note that you should avoid using 3378 * {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION} by itself.) 3379 * 3380 * If you have set the window flag {@link WindowManager.LayoutParams#FLAG_FULLSCREEN} 3381 * to hide the status bar (instead of using {@link #SYSTEM_UI_FLAG_FULLSCREEN}), 3382 * then a hidden status bar will be considered a "stable" state for purposes 3383 * here. This allows your UI to continually hide the status bar, while still 3384 * using the system UI flags to hide the action bar while still retaining 3385 * a stable layout. Note that changing the window fullscreen flag will never 3386 * provide a stable layout for a clean transition. 3387 * 3388 * <p>If you are using ActionBar in 3389 * overlay mode with {@link Window#FEATURE_ACTION_BAR_OVERLAY 3390 * Window.FEATURE_ACTION_BAR_OVERLAY}, this flag will also impact the 3391 * insets it adds to those given to the application. 3392 */ 3393 public static final int SYSTEM_UI_FLAG_LAYOUT_STABLE = 0x00000100; 3394 3395 /** 3396 * Flag for {@link #setSystemUiVisibility(int)}: View would like its window 3397 * to be laid out as if it has requested 3398 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, even if it currently hasn't. This 3399 * allows it to avoid artifacts when switching in and out of that mode, at 3400 * the expense that some of its user interface may be covered by screen 3401 * decorations when they are shown. You can perform layout of your inner 3402 * UI elements to account for the navigation system UI through the 3403 * {@link #fitSystemWindows(Rect)} method. 3404 */ 3405 public static final int SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION = 0x00000200; 3406 3407 /** 3408 * Flag for {@link #setSystemUiVisibility(int)}: View would like its window 3409 * to be laid out as if it has requested 3410 * {@link #SYSTEM_UI_FLAG_FULLSCREEN}, even if it currently hasn't. This 3411 * allows it to avoid artifacts when switching in and out of that mode, at 3412 * the expense that some of its user interface may be covered by screen 3413 * decorations when they are shown. You can perform layout of your inner 3414 * UI elements to account for non-fullscreen system UI through the 3415 * {@link #fitSystemWindows(Rect)} method. 3416 * 3417 * <p>Note: on displays that have a {@link DisplayCutout}, the window may still be placed 3418 * differently than if {@link #SYSTEM_UI_FLAG_FULLSCREEN} was set, if the 3419 * window's {@link WindowManager.LayoutParams#layoutInDisplayCutoutMode 3420 * layoutInDisplayCutoutMode} is 3421 * {@link WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT 3422 * LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT}. To avoid this, use either of the other modes. 3423 * 3424 * @see WindowManager.LayoutParams#layoutInDisplayCutoutMode 3425 * @see WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT 3426 * @see WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS 3427 * @see WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER 3428 */ 3429 public static final int SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN = 0x00000400; 3430 3431 /** 3432 * Flag for {@link #setSystemUiVisibility(int)}: View would like to remain interactive when 3433 * hiding the navigation bar with {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}. If this flag is 3434 * not set, {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION} will be force cleared by the system on any 3435 * user interaction. 3436 * <p>Since this flag is a modifier for {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, it only 3437 * has an effect when used in combination with that flag.</p> 3438 */ 3439 public static final int SYSTEM_UI_FLAG_IMMERSIVE = 0x00000800; 3440 3441 /** 3442 * Flag for {@link #setSystemUiVisibility(int)}: View would like to remain interactive when 3443 * hiding the status bar with {@link #SYSTEM_UI_FLAG_FULLSCREEN} and/or hiding the navigation 3444 * bar with {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}. Use this flag to create an immersive 3445 * experience while also hiding the system bars. If this flag is not set, 3446 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION} will be force cleared by the system on any user 3447 * interaction, and {@link #SYSTEM_UI_FLAG_FULLSCREEN} will be force-cleared by the system 3448 * if the user swipes from the top of the screen. 3449 * <p>When system bars are hidden in immersive mode, they can be revealed temporarily with 3450 * system gestures, such as swiping from the top of the screen. These transient system bars 3451 * will overlay app’s content, may have some degree of transparency, and will automatically 3452 * hide after a short timeout. 3453 * </p><p>Since this flag is a modifier for {@link #SYSTEM_UI_FLAG_FULLSCREEN} and 3454 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, it only has an effect when used in combination 3455 * with one or both of those flags.</p> 3456 */ 3457 public static final int SYSTEM_UI_FLAG_IMMERSIVE_STICKY = 0x00001000; 3458 3459 /** 3460 * Flag for {@link #setSystemUiVisibility(int)}: Requests the status bar to draw in a mode that 3461 * is compatible with light status bar backgrounds. 3462 * 3463 * <p>For this to take effect, the window must request 3464 * {@link android.view.WindowManager.LayoutParams#FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS 3465 * FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS} but not 3466 * {@link android.view.WindowManager.LayoutParams#FLAG_TRANSLUCENT_STATUS 3467 * FLAG_TRANSLUCENT_STATUS}. 3468 * 3469 * @see android.R.attr#windowLightStatusBar 3470 */ 3471 public static final int SYSTEM_UI_FLAG_LIGHT_STATUS_BAR = 0x00002000; 3472 3473 /** 3474 * This flag was previously used for a private API. DO NOT reuse it for a public API as it might 3475 * trigger undefined behavior on older platforms with apps compiled against a new SDK. 3476 */ 3477 private static final int SYSTEM_UI_RESERVED_LEGACY1 = 0x00004000; 3478 3479 /** 3480 * This flag was previously used for a private API. DO NOT reuse it for a public API as it might 3481 * trigger undefined behavior on older platforms with apps compiled against a new SDK. 3482 */ 3483 private static final int SYSTEM_UI_RESERVED_LEGACY2 = 0x00010000; 3484 3485 /** 3486 * Flag for {@link #setSystemUiVisibility(int)}: Requests the navigation bar to draw in a mode 3487 * that is compatible with light navigation bar backgrounds. 3488 * 3489 * <p>For this to take effect, the window must request 3490 * {@link android.view.WindowManager.LayoutParams#FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS 3491 * FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS} but not 3492 * {@link android.view.WindowManager.LayoutParams#FLAG_TRANSLUCENT_NAVIGATION 3493 * FLAG_TRANSLUCENT_NAVIGATION}. 3494 * 3495 * @see android.R.attr#windowLightNavigationBar 3496 */ 3497 public static final int SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR = 0x00000010; 3498 3499 /** 3500 * @deprecated Use {@link #SYSTEM_UI_FLAG_LOW_PROFILE} instead. 3501 */ 3502 @Deprecated 3503 public static final int STATUS_BAR_HIDDEN = SYSTEM_UI_FLAG_LOW_PROFILE; 3504 3505 /** 3506 * @deprecated Use {@link #SYSTEM_UI_FLAG_VISIBLE} instead. 3507 */ 3508 @Deprecated 3509 public static final int STATUS_BAR_VISIBLE = SYSTEM_UI_FLAG_VISIBLE; 3510 3511 /** 3512 * @hide 3513 * 3514 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3515 * out of the public fields to keep the undefined bits out of the developer's way. 3516 * 3517 * Flag to make the status bar not expandable. Unless you also 3518 * set {@link #STATUS_BAR_DISABLE_NOTIFICATION_ICONS}, new notifications will continue to show. 3519 */ 3520 public static final int STATUS_BAR_DISABLE_EXPAND = 0x00010000; 3521 3522 /** 3523 * @hide 3524 * 3525 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3526 * out of the public fields to keep the undefined bits out of the developer's way. 3527 * 3528 * Flag to hide notification icons and scrolling ticker text. 3529 */ 3530 public static final int STATUS_BAR_DISABLE_NOTIFICATION_ICONS = 0x00020000; 3531 3532 /** 3533 * @hide 3534 * 3535 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3536 * out of the public fields to keep the undefined bits out of the developer's way. 3537 * 3538 * Flag to disable incoming notification alerts. This will not block 3539 * icons, but it will block sound, vibrating and other visual or aural notifications. 3540 */ 3541 public static final int STATUS_BAR_DISABLE_NOTIFICATION_ALERTS = 0x00040000; 3542 3543 /** 3544 * @hide 3545 * 3546 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3547 * out of the public fields to keep the undefined bits out of the developer's way. 3548 * 3549 * Flag to hide only the scrolling ticker. Note that 3550 * {@link #STATUS_BAR_DISABLE_NOTIFICATION_ICONS} implies 3551 * {@link #STATUS_BAR_DISABLE_NOTIFICATION_TICKER}. 3552 */ 3553 public static final int STATUS_BAR_DISABLE_NOTIFICATION_TICKER = 0x00080000; 3554 3555 /** 3556 * @hide 3557 * 3558 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3559 * out of the public fields to keep the undefined bits out of the developer's way. 3560 * 3561 * Flag to hide the center system info area. 3562 */ 3563 public static final int STATUS_BAR_DISABLE_SYSTEM_INFO = 0x00100000; 3564 3565 /** 3566 * @hide 3567 * 3568 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3569 * out of the public fields to keep the undefined bits out of the developer's way. 3570 * 3571 * Flag to hide only the home button. Don't use this 3572 * unless you're a special part of the system UI (i.e., setup wizard, keyguard). 3573 */ 3574 public static final int STATUS_BAR_DISABLE_HOME = 0x00200000; 3575 3576 /** 3577 * @hide 3578 * 3579 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3580 * out of the public fields to keep the undefined bits out of the developer's way. 3581 * 3582 * Flag to hide only the back button. Don't use this 3583 * unless you're a special part of the system UI (i.e., setup wizard, keyguard). 3584 */ 3585 public static final int STATUS_BAR_DISABLE_BACK = 0x00400000; 3586 3587 /** 3588 * @hide 3589 * 3590 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3591 * out of the public fields to keep the undefined bits out of the developer's way. 3592 * 3593 * Flag to hide only the clock. You might use this if your activity has 3594 * its own clock making the status bar's clock redundant. 3595 */ 3596 public static final int STATUS_BAR_DISABLE_CLOCK = 0x00800000; 3597 3598 /** 3599 * @hide 3600 * 3601 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3602 * out of the public fields to keep the undefined bits out of the developer's way. 3603 * 3604 * Flag to hide only the recent apps button. Don't use this 3605 * unless you're a special part of the system UI (i.e., setup wizard, keyguard). 3606 */ 3607 public static final int STATUS_BAR_DISABLE_RECENT = 0x01000000; 3608 3609 /** 3610 * @hide 3611 * 3612 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3613 * out of the public fields to keep the undefined bits out of the developer's way. 3614 * 3615 * Flag to disable the global search gesture. Don't use this 3616 * unless you're a special part of the system UI (i.e., setup wizard, keyguard). 3617 */ 3618 public static final int STATUS_BAR_DISABLE_SEARCH = 0x02000000; 3619 3620 /** 3621 * @hide 3622 * 3623 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3624 * out of the public fields to keep the undefined bits out of the developer's way. 3625 * 3626 * Flag to specify that the status bar is displayed in transient mode. 3627 */ 3628 public static final int STATUS_BAR_TRANSIENT = 0x04000000; 3629 3630 /** 3631 * @hide 3632 * 3633 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3634 * out of the public fields to keep the undefined bits out of the developer's way. 3635 * 3636 * Flag to specify that the navigation bar is displayed in transient mode. 3637 */ 3638 public static final int NAVIGATION_BAR_TRANSIENT = 0x08000000; 3639 3640 /** 3641 * @hide 3642 * 3643 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3644 * out of the public fields to keep the undefined bits out of the developer's way. 3645 * 3646 * Flag to specify that the hidden status bar would like to be shown. 3647 */ 3648 public static final int STATUS_BAR_UNHIDE = 0x10000000; 3649 3650 /** 3651 * @hide 3652 * 3653 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3654 * out of the public fields to keep the undefined bits out of the developer's way. 3655 * 3656 * Flag to specify that the hidden navigation bar would like to be shown. 3657 */ 3658 public static final int NAVIGATION_BAR_UNHIDE = 0x20000000; 3659 3660 /** 3661 * @hide 3662 * 3663 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3664 * out of the public fields to keep the undefined bits out of the developer's way. 3665 * 3666 * Flag to specify that the status bar is displayed in translucent mode. 3667 */ 3668 public static final int STATUS_BAR_TRANSLUCENT = 0x40000000; 3669 3670 /** 3671 * @hide 3672 * 3673 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3674 * out of the public fields to keep the undefined bits out of the developer's way. 3675 * 3676 * Flag to specify that the navigation bar is displayed in translucent mode. 3677 */ 3678 public static final int NAVIGATION_BAR_TRANSLUCENT = 0x80000000; 3679 3680 /** 3681 * @hide 3682 * 3683 * Makes navigation bar transparent (but not the status bar). 3684 */ 3685 public static final int NAVIGATION_BAR_TRANSPARENT = 0x00008000; 3686 3687 /** 3688 * @hide 3689 * 3690 * Makes status bar transparent (but not the navigation bar). 3691 */ 3692 public static final int STATUS_BAR_TRANSPARENT = 0x00000008; 3693 3694 /** 3695 * @hide 3696 * 3697 * Makes both status bar and navigation bar transparent. 3698 */ 3699 public static final int SYSTEM_UI_TRANSPARENT = NAVIGATION_BAR_TRANSPARENT 3700 | STATUS_BAR_TRANSPARENT; 3701 3702 /** 3703 * @hide 3704 */ 3705 public static final int PUBLIC_STATUS_BAR_VISIBILITY_MASK = 0x00003FF7; 3706 3707 /** 3708 * These are the system UI flags that can be cleared by events outside 3709 * of an application. Currently this is just the ability to tap on the 3710 * screen while hiding the navigation bar to have it return. 3711 * @hide 3712 */ 3713 public static final int SYSTEM_UI_CLEARABLE_FLAGS = 3714 SYSTEM_UI_FLAG_LOW_PROFILE | SYSTEM_UI_FLAG_HIDE_NAVIGATION 3715 | SYSTEM_UI_FLAG_FULLSCREEN; 3716 3717 /** 3718 * Flags that can impact the layout in relation to system UI. 3719 */ 3720 public static final int SYSTEM_UI_LAYOUT_FLAGS = 3721 SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION 3722 | SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN; 3723 3724 /** @hide */ 3725 @IntDef(flag = true, prefix = { "FIND_VIEWS_" }, value = { 3726 FIND_VIEWS_WITH_TEXT, 3727 FIND_VIEWS_WITH_CONTENT_DESCRIPTION 3728 }) 3729 @Retention(RetentionPolicy.SOURCE) 3730 public @interface FindViewFlags {} 3731 3732 /** 3733 * Find views that render the specified text. 3734 * 3735 * @see #findViewsWithText(ArrayList, CharSequence, int) 3736 */ 3737 public static final int FIND_VIEWS_WITH_TEXT = 0x00000001; 3738 3739 /** 3740 * Find find views that contain the specified content description. 3741 * 3742 * @see #findViewsWithText(ArrayList, CharSequence, int) 3743 */ 3744 public static final int FIND_VIEWS_WITH_CONTENT_DESCRIPTION = 0x00000002; 3745 3746 /** 3747 * Find views that contain {@link AccessibilityNodeProvider}. Such 3748 * a View is a root of virtual view hierarchy and may contain the searched 3749 * text. If this flag is set Views with providers are automatically 3750 * added and it is a responsibility of the client to call the APIs of 3751 * the provider to determine whether the virtual tree rooted at this View 3752 * contains the text, i.e. getting the list of {@link AccessibilityNodeInfo}s 3753 * representing the virtual views with this text. 3754 * 3755 * @see #findViewsWithText(ArrayList, CharSequence, int) 3756 * 3757 * @hide 3758 */ 3759 public static final int FIND_VIEWS_WITH_ACCESSIBILITY_NODE_PROVIDERS = 0x00000004; 3760 3761 /** 3762 * The undefined cursor position. 3763 * 3764 * @hide 3765 */ 3766 public static final int ACCESSIBILITY_CURSOR_POSITION_UNDEFINED = -1; 3767 3768 /** 3769 * Indicates that the screen has changed state and is now off. 3770 * 3771 * @see #onScreenStateChanged(int) 3772 */ 3773 public static final int SCREEN_STATE_OFF = 0x0; 3774 3775 /** 3776 * Indicates that the screen has changed state and is now on. 3777 * 3778 * @see #onScreenStateChanged(int) 3779 */ 3780 public static final int SCREEN_STATE_ON = 0x1; 3781 3782 /** 3783 * Indicates no axis of view scrolling. 3784 */ 3785 public static final int SCROLL_AXIS_NONE = 0; 3786 3787 /** 3788 * Indicates scrolling along the horizontal axis. 3789 */ 3790 public static final int SCROLL_AXIS_HORIZONTAL = 1 << 0; 3791 3792 /** 3793 * Indicates scrolling along the vertical axis. 3794 */ 3795 public static final int SCROLL_AXIS_VERTICAL = 1 << 1; 3796 3797 /** 3798 * Controls the over-scroll mode for this view. 3799 * See {@link #overScrollBy(int, int, int, int, int, int, int, int, boolean)}, 3800 * {@link #OVER_SCROLL_ALWAYS}, {@link #OVER_SCROLL_IF_CONTENT_SCROLLS}, 3801 * and {@link #OVER_SCROLL_NEVER}. 3802 */ 3803 private int mOverScrollMode; 3804 3805 /** 3806 * The parent this view is attached to. 3807 * {@hide} 3808 * 3809 * @see #getParent() 3810 */ 3811 protected ViewParent mParent; 3812 3813 /** 3814 * {@hide} 3815 */ 3816 AttachInfo mAttachInfo; 3817 3818 /** 3819 * {@hide} 3820 */ 3821 @ViewDebug.ExportedProperty(flagMapping = { 3822 @ViewDebug.FlagToString(mask = PFLAG_FORCE_LAYOUT, equals = PFLAG_FORCE_LAYOUT, 3823 name = "FORCE_LAYOUT"), 3824 @ViewDebug.FlagToString(mask = PFLAG_LAYOUT_REQUIRED, equals = PFLAG_LAYOUT_REQUIRED, 3825 name = "LAYOUT_REQUIRED"), 3826 @ViewDebug.FlagToString(mask = PFLAG_DRAWING_CACHE_VALID, equals = PFLAG_DRAWING_CACHE_VALID, 3827 name = "DRAWING_CACHE_INVALID", outputIf = false), 3828 @ViewDebug.FlagToString(mask = PFLAG_DRAWN, equals = PFLAG_DRAWN, name = "DRAWN", outputIf = true), 3829 @ViewDebug.FlagToString(mask = PFLAG_DRAWN, equals = PFLAG_DRAWN, name = "NOT_DRAWN", outputIf = false), 3830 @ViewDebug.FlagToString(mask = PFLAG_DIRTY_MASK, equals = PFLAG_DIRTY_OPAQUE, name = "DIRTY_OPAQUE"), 3831 @ViewDebug.FlagToString(mask = PFLAG_DIRTY_MASK, equals = PFLAG_DIRTY, name = "DIRTY") 3832 }, formatToHexString = true) 3833 3834 /* @hide */ 3835 public int mPrivateFlags; 3836 int mPrivateFlags2; 3837 int mPrivateFlags3; 3838 3839 /** 3840 * This view's request for the visibility of the status bar. 3841 * @hide 3842 */ 3843 @ViewDebug.ExportedProperty(flagMapping = { 3844 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_LOW_PROFILE, 3845 equals = SYSTEM_UI_FLAG_LOW_PROFILE, 3846 name = "LOW_PROFILE"), 3847 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_HIDE_NAVIGATION, 3848 equals = SYSTEM_UI_FLAG_HIDE_NAVIGATION, 3849 name = "HIDE_NAVIGATION"), 3850 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_FULLSCREEN, 3851 equals = SYSTEM_UI_FLAG_FULLSCREEN, 3852 name = "FULLSCREEN"), 3853 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_LAYOUT_STABLE, 3854 equals = SYSTEM_UI_FLAG_LAYOUT_STABLE, 3855 name = "LAYOUT_STABLE"), 3856 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION, 3857 equals = SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION, 3858 name = "LAYOUT_HIDE_NAVIGATION"), 3859 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN, 3860 equals = SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN, 3861 name = "LAYOUT_FULLSCREEN"), 3862 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_IMMERSIVE, 3863 equals = SYSTEM_UI_FLAG_IMMERSIVE, 3864 name = "IMMERSIVE"), 3865 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_IMMERSIVE_STICKY, 3866 equals = SYSTEM_UI_FLAG_IMMERSIVE_STICKY, 3867 name = "IMMERSIVE_STICKY"), 3868 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_LIGHT_STATUS_BAR, 3869 equals = SYSTEM_UI_FLAG_LIGHT_STATUS_BAR, 3870 name = "LIGHT_STATUS_BAR"), 3871 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR, 3872 equals = SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR, 3873 name = "LIGHT_NAVIGATION_BAR"), 3874 @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_EXPAND, 3875 equals = STATUS_BAR_DISABLE_EXPAND, 3876 name = "STATUS_BAR_DISABLE_EXPAND"), 3877 @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_NOTIFICATION_ICONS, 3878 equals = STATUS_BAR_DISABLE_NOTIFICATION_ICONS, 3879 name = "STATUS_BAR_DISABLE_NOTIFICATION_ICONS"), 3880 @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_NOTIFICATION_ALERTS, 3881 equals = STATUS_BAR_DISABLE_NOTIFICATION_ALERTS, 3882 name = "STATUS_BAR_DISABLE_NOTIFICATION_ALERTS"), 3883 @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_NOTIFICATION_TICKER, 3884 equals = STATUS_BAR_DISABLE_NOTIFICATION_TICKER, 3885 name = "STATUS_BAR_DISABLE_NOTIFICATION_TICKER"), 3886 @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_SYSTEM_INFO, 3887 equals = STATUS_BAR_DISABLE_SYSTEM_INFO, 3888 name = "STATUS_BAR_DISABLE_SYSTEM_INFO"), 3889 @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_HOME, 3890 equals = STATUS_BAR_DISABLE_HOME, 3891 name = "STATUS_BAR_DISABLE_HOME"), 3892 @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_BACK, 3893 equals = STATUS_BAR_DISABLE_BACK, 3894 name = "STATUS_BAR_DISABLE_BACK"), 3895 @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_CLOCK, 3896 equals = STATUS_BAR_DISABLE_CLOCK, 3897 name = "STATUS_BAR_DISABLE_CLOCK"), 3898 @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_RECENT, 3899 equals = STATUS_BAR_DISABLE_RECENT, 3900 name = "STATUS_BAR_DISABLE_RECENT"), 3901 @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_SEARCH, 3902 equals = STATUS_BAR_DISABLE_SEARCH, 3903 name = "STATUS_BAR_DISABLE_SEARCH"), 3904 @ViewDebug.FlagToString(mask = STATUS_BAR_TRANSIENT, 3905 equals = STATUS_BAR_TRANSIENT, 3906 name = "STATUS_BAR_TRANSIENT"), 3907 @ViewDebug.FlagToString(mask = NAVIGATION_BAR_TRANSIENT, 3908 equals = NAVIGATION_BAR_TRANSIENT, 3909 name = "NAVIGATION_BAR_TRANSIENT"), 3910 @ViewDebug.FlagToString(mask = STATUS_BAR_UNHIDE, 3911 equals = STATUS_BAR_UNHIDE, 3912 name = "STATUS_BAR_UNHIDE"), 3913 @ViewDebug.FlagToString(mask = NAVIGATION_BAR_UNHIDE, 3914 equals = NAVIGATION_BAR_UNHIDE, 3915 name = "NAVIGATION_BAR_UNHIDE"), 3916 @ViewDebug.FlagToString(mask = STATUS_BAR_TRANSLUCENT, 3917 equals = STATUS_BAR_TRANSLUCENT, 3918 name = "STATUS_BAR_TRANSLUCENT"), 3919 @ViewDebug.FlagToString(mask = NAVIGATION_BAR_TRANSLUCENT, 3920 equals = NAVIGATION_BAR_TRANSLUCENT, 3921 name = "NAVIGATION_BAR_TRANSLUCENT"), 3922 @ViewDebug.FlagToString(mask = NAVIGATION_BAR_TRANSPARENT, 3923 equals = NAVIGATION_BAR_TRANSPARENT, 3924 name = "NAVIGATION_BAR_TRANSPARENT"), 3925 @ViewDebug.FlagToString(mask = STATUS_BAR_TRANSPARENT, 3926 equals = STATUS_BAR_TRANSPARENT, 3927 name = "STATUS_BAR_TRANSPARENT") 3928 }, formatToHexString = true) 3929 int mSystemUiVisibility; 3930 3931 /** 3932 * Reference count for transient state. 3933 * @see #setHasTransientState(boolean) 3934 */ 3935 int mTransientStateCount = 0; 3936 3937 /** 3938 * Count of how many windows this view has been attached to. 3939 */ 3940 int mWindowAttachCount; 3941 3942 /** 3943 * The layout parameters associated with this view and used by the parent 3944 * {@link android.view.ViewGroup} to determine how this view should be 3945 * laid out. 3946 * {@hide} 3947 */ 3948 protected ViewGroup.LayoutParams mLayoutParams; 3949 3950 /** 3951 * The view flags hold various views states. 3952 * {@hide} 3953 */ 3954 @ViewDebug.ExportedProperty(formatToHexString = true) 3955 int mViewFlags; 3956 3957 static class TransformationInfo { 3958 /** 3959 * The transform matrix for the View. This transform is calculated internally 3960 * based on the translation, rotation, and scale properties. 3961 * 3962 * Do *not* use this variable directly; instead call getMatrix(), which will 3963 * load the value from the View's RenderNode. 3964 */ 3965 private final Matrix mMatrix = new Matrix(); 3966 3967 /** 3968 * The inverse transform matrix for the View. This transform is calculated 3969 * internally based on the translation, rotation, and scale properties. 3970 * 3971 * Do *not* use this variable directly; instead call getInverseMatrix(), 3972 * which will load the value from the View's RenderNode. 3973 */ 3974 private Matrix mInverseMatrix; 3975 3976 /** 3977 * The opacity of the View. This is a value from 0 to 1, where 0 means 3978 * completely transparent and 1 means completely opaque. 3979 */ 3980 @ViewDebug.ExportedProperty 3981 float mAlpha = 1f; 3982 3983 /** 3984 * The opacity of the view as manipulated by the Fade transition. This is a hidden 3985 * property only used by transitions, which is composited with the other alpha 3986 * values to calculate the final visual alpha value. 3987 */ 3988 float mTransitionAlpha = 1f; 3989 } 3990 3991 /** @hide */ 3992 public TransformationInfo mTransformationInfo; 3993 3994 /** 3995 * Current clip bounds. to which all drawing of this view are constrained. 3996 */ 3997 @ViewDebug.ExportedProperty(category = "drawing") 3998 Rect mClipBounds = null; 3999 4000 private boolean mLastIsOpaque; 4001 4002 /** 4003 * The distance in pixels from the left edge of this view's parent 4004 * to the left edge of this view. 4005 * {@hide} 4006 */ 4007 @ViewDebug.ExportedProperty(category = "layout") 4008 protected int mLeft; 4009 /** 4010 * The distance in pixels from the left edge of this view's parent 4011 * to the right edge of this view. 4012 * {@hide} 4013 */ 4014 @ViewDebug.ExportedProperty(category = "layout") 4015 protected int mRight; 4016 /** 4017 * The distance in pixels from the top edge of this view's parent 4018 * to the top edge of this view. 4019 * {@hide} 4020 */ 4021 @ViewDebug.ExportedProperty(category = "layout") 4022 protected int mTop; 4023 /** 4024 * The distance in pixels from the top edge of this view's parent 4025 * to the bottom edge of this view. 4026 * {@hide} 4027 */ 4028 @ViewDebug.ExportedProperty(category = "layout") 4029 protected int mBottom; 4030 4031 /** 4032 * The offset, in pixels, by which the content of this view is scrolled 4033 * horizontally. 4034 * {@hide} 4035 */ 4036 @ViewDebug.ExportedProperty(category = "scrolling") 4037 protected int mScrollX; 4038 /** 4039 * The offset, in pixels, by which the content of this view is scrolled 4040 * vertically. 4041 * {@hide} 4042 */ 4043 @ViewDebug.ExportedProperty(category = "scrolling") 4044 protected int mScrollY; 4045 4046 /** 4047 * The left padding in pixels, that is the distance in pixels between the 4048 * left edge of this view and the left edge of its content. 4049 * {@hide} 4050 */ 4051 @ViewDebug.ExportedProperty(category = "padding") 4052 protected int mPaddingLeft = 0; 4053 /** 4054 * The right padding in pixels, that is the distance in pixels between the 4055 * right edge of this view and the right edge of its content. 4056 * {@hide} 4057 */ 4058 @ViewDebug.ExportedProperty(category = "padding") 4059 protected int mPaddingRight = 0; 4060 /** 4061 * The top padding in pixels, that is the distance in pixels between the 4062 * top edge of this view and the top edge of its content. 4063 * {@hide} 4064 */ 4065 @ViewDebug.ExportedProperty(category = "padding") 4066 protected int mPaddingTop; 4067 /** 4068 * The bottom padding in pixels, that is the distance in pixels between the 4069 * bottom edge of this view and the bottom edge of its content. 4070 * {@hide} 4071 */ 4072 @ViewDebug.ExportedProperty(category = "padding") 4073 protected int mPaddingBottom; 4074 4075 /** 4076 * The layout insets in pixels, that is the distance in pixels between the 4077 * visible edges of this view its bounds. 4078 */ 4079 private Insets mLayoutInsets; 4080 4081 /** 4082 * Briefly describes the view and is primarily used for accessibility support. 4083 */ 4084 private CharSequence mContentDescription; 4085 4086 /** 4087 * If this view represents a distinct part of the window, it can have a title that labels the 4088 * area. 4089 */ 4090 private CharSequence mAccessibilityPaneTitle; 4091 4092 /** 4093 * Specifies the id of a view for which this view serves as a label for 4094 * accessibility purposes. 4095 */ 4096 private int mLabelForId = View.NO_ID; 4097 4098 /** 4099 * Predicate for matching labeled view id with its label for 4100 * accessibility purposes. 4101 */ 4102 private MatchLabelForPredicate mMatchLabelForPredicate; 4103 4104 /** 4105 * Specifies a view before which this one is visited in accessibility traversal. 4106 */ 4107 private int mAccessibilityTraversalBeforeId = NO_ID; 4108 4109 /** 4110 * Specifies a view after which this one is visited in accessibility traversal. 4111 */ 4112 private int mAccessibilityTraversalAfterId = NO_ID; 4113 4114 /** 4115 * Predicate for matching a view by its id. 4116 */ 4117 private MatchIdPredicate mMatchIdPredicate; 4118 4119 /** 4120 * Cache the paddingRight set by the user to append to the scrollbar's size. 4121 * 4122 * @hide 4123 */ 4124 @ViewDebug.ExportedProperty(category = "padding") 4125 protected int mUserPaddingRight; 4126 4127 /** 4128 * Cache the paddingBottom set by the user to append to the scrollbar's size. 4129 * 4130 * @hide 4131 */ 4132 @ViewDebug.ExportedProperty(category = "padding") 4133 protected int mUserPaddingBottom; 4134 4135 /** 4136 * Cache the paddingLeft set by the user to append to the scrollbar's size. 4137 * 4138 * @hide 4139 */ 4140 @ViewDebug.ExportedProperty(category = "padding") 4141 protected int mUserPaddingLeft; 4142 4143 /** 4144 * Cache the paddingStart set by the user to append to the scrollbar's size. 4145 * 4146 */ 4147 @ViewDebug.ExportedProperty(category = "padding") 4148 int mUserPaddingStart; 4149 4150 /** 4151 * Cache the paddingEnd set by the user to append to the scrollbar's size. 4152 * 4153 */ 4154 @ViewDebug.ExportedProperty(category = "padding") 4155 int mUserPaddingEnd; 4156 4157 /** 4158 * Cache initial left padding. 4159 * 4160 * @hide 4161 */ 4162 int mUserPaddingLeftInitial; 4163 4164 /** 4165 * Cache initial right padding. 4166 * 4167 * @hide 4168 */ 4169 int mUserPaddingRightInitial; 4170 4171 /** 4172 * Default undefined padding 4173 */ 4174 private static final int UNDEFINED_PADDING = Integer.MIN_VALUE; 4175 4176 /** 4177 * Cache if a left padding has been defined 4178 */ 4179 private boolean mLeftPaddingDefined = false; 4180 4181 /** 4182 * Cache if a right padding has been defined 4183 */ 4184 private boolean mRightPaddingDefined = false; 4185 4186 /** 4187 * @hide 4188 */ 4189 int mOldWidthMeasureSpec = Integer.MIN_VALUE; 4190 /** 4191 * @hide 4192 */ 4193 int mOldHeightMeasureSpec = Integer.MIN_VALUE; 4194 4195 private LongSparseLongArray mMeasureCache; 4196 4197 @ViewDebug.ExportedProperty(deepExport = true, prefix = "bg_") 4198 private Drawable mBackground; 4199 private TintInfo mBackgroundTint; 4200 4201 @ViewDebug.ExportedProperty(deepExport = true, prefix = "fg_") 4202 private ForegroundInfo mForegroundInfo; 4203 4204 private Drawable mScrollIndicatorDrawable; 4205 4206 /** 4207 * RenderNode used for backgrounds. 4208 * <p> 4209 * When non-null and valid, this is expected to contain an up-to-date copy 4210 * of the background drawable. It is cleared on temporary detach, and reset 4211 * on cleanup. 4212 */ 4213 private RenderNode mBackgroundRenderNode; 4214 4215 private int mBackgroundResource; 4216 private boolean mBackgroundSizeChanged; 4217 4218 /** The default focus highlight. 4219 * @see #mDefaultFocusHighlightEnabled 4220 * @see Drawable#hasFocusStateSpecified() 4221 */ 4222 private Drawable mDefaultFocusHighlight; 4223 private Drawable mDefaultFocusHighlightCache; 4224 private boolean mDefaultFocusHighlightSizeChanged; 4225 /** 4226 * True if the default focus highlight is needed on the target device. 4227 */ 4228 private static boolean sUseDefaultFocusHighlight; 4229 4230 /** 4231 * True if zero-sized views can be focused. 4232 */ 4233 private static boolean sCanFocusZeroSized; 4234 4235 /** 4236 * Always assign focus if a focusable View is available. 4237 */ 4238 private static boolean sAlwaysAssignFocus; 4239 4240 private String mTransitionName; 4241 4242 static class TintInfo { 4243 ColorStateList mTintList; 4244 PorterDuff.Mode mTintMode; 4245 boolean mHasTintMode; 4246 boolean mHasTintList; 4247 } 4248 4249 private static class ForegroundInfo { 4250 private Drawable mDrawable; 4251 private TintInfo mTintInfo; 4252 private int mGravity = Gravity.FILL; 4253 private boolean mInsidePadding = true; 4254 private boolean mBoundsChanged = true; 4255 private final Rect mSelfBounds = new Rect(); 4256 private final Rect mOverlayBounds = new Rect(); 4257 } 4258 4259 static class ListenerInfo { 4260 /** 4261 * Listener used to dispatch focus change events. 4262 * This field should be made private, so it is hidden from the SDK. 4263 * {@hide} 4264 */ 4265 protected OnFocusChangeListener mOnFocusChangeListener; 4266 4267 /** 4268 * Listeners for layout change events. 4269 */ 4270 private ArrayList<OnLayoutChangeListener> mOnLayoutChangeListeners; 4271 4272 protected OnScrollChangeListener mOnScrollChangeListener; 4273 4274 /** 4275 * Listeners for attach events. 4276 */ 4277 private CopyOnWriteArrayList<OnAttachStateChangeListener> mOnAttachStateChangeListeners; 4278 4279 /** 4280 * Listener used to dispatch click events. 4281 * This field should be made private, so it is hidden from the SDK. 4282 * {@hide} 4283 */ 4284 public OnClickListener mOnClickListener; 4285 4286 /** 4287 * Listener used to dispatch long click events. 4288 * This field should be made private, so it is hidden from the SDK. 4289 * {@hide} 4290 */ 4291 protected OnLongClickListener mOnLongClickListener; 4292 4293 /** 4294 * Listener used to dispatch context click events. This field should be made private, so it 4295 * is hidden from the SDK. 4296 * {@hide} 4297 */ 4298 protected OnContextClickListener mOnContextClickListener; 4299 4300 /** 4301 * Listener used to build the context menu. 4302 * This field should be made private, so it is hidden from the SDK. 4303 * {@hide} 4304 */ 4305 protected OnCreateContextMenuListener mOnCreateContextMenuListener; 4306 4307 private OnKeyListener mOnKeyListener; 4308 4309 private OnTouchListener mOnTouchListener; 4310 4311 private OnHoverListener mOnHoverListener; 4312 4313 private OnGenericMotionListener mOnGenericMotionListener; 4314 4315 private OnDragListener mOnDragListener; 4316 4317 private OnSystemUiVisibilityChangeListener mOnSystemUiVisibilityChangeListener; 4318 4319 OnApplyWindowInsetsListener mOnApplyWindowInsetsListener; 4320 4321 OnCapturedPointerListener mOnCapturedPointerListener; 4322 4323 private ArrayList<OnKeyFallbackListener> mKeyFallbackListeners; 4324 } 4325 4326 ListenerInfo mListenerInfo; 4327 4328 private static class TooltipInfo { 4329 /** 4330 * Text to be displayed in a tooltip popup. 4331 */ 4332 @Nullable 4333 CharSequence mTooltipText; 4334 4335 /** 4336 * View-relative position of the tooltip anchor point. 4337 */ 4338 int mAnchorX; 4339 int mAnchorY; 4340 4341 /** 4342 * The tooltip popup. 4343 */ 4344 @Nullable 4345 TooltipPopup mTooltipPopup; 4346 4347 /** 4348 * Set to true if the tooltip was shown as a result of a long click. 4349 */ 4350 boolean mTooltipFromLongClick; 4351 4352 /** 4353 * Keep these Runnables so that they can be used to reschedule. 4354 */ 4355 Runnable mShowTooltipRunnable; 4356 Runnable mHideTooltipRunnable; 4357 4358 /** 4359 * Hover move is ignored if it is within this distance in pixels from the previous one. 4360 */ 4361 int mHoverSlop; 4362 4363 /** 4364 * Update the anchor position if it significantly (that is by at least mHoverSlop) 4365 * different from the previously stored position. Ignoring insignificant changes 4366 * filters out the jitter which is typical for such input sources as stylus. 4367 * 4368 * @return True if the position has been updated. 4369 */ 4370 private boolean updateAnchorPos(MotionEvent event) { 4371 final int newAnchorX = (int) event.getX(); 4372 final int newAnchorY = (int) event.getY(); 4373 if (Math.abs(newAnchorX - mAnchorX) <= mHoverSlop 4374 && Math.abs(newAnchorY - mAnchorY) <= mHoverSlop) { 4375 return false; 4376 } 4377 mAnchorX = newAnchorX; 4378 mAnchorY = newAnchorY; 4379 return true; 4380 } 4381 4382 /** 4383 * Clear the anchor position to ensure that the next change is considered significant. 4384 */ 4385 private void clearAnchorPos() { 4386 mAnchorX = Integer.MAX_VALUE; 4387 mAnchorY = Integer.MAX_VALUE; 4388 } 4389 } 4390 4391 TooltipInfo mTooltipInfo; 4392 4393 // Temporary values used to hold (x,y) coordinates when delegating from the 4394 // two-arg performLongClick() method to the legacy no-arg version. 4395 private float mLongClickX = Float.NaN; 4396 private float mLongClickY = Float.NaN; 4397 4398 /** 4399 * The application environment this view lives in. 4400 * This field should be made private, so it is hidden from the SDK. 4401 * {@hide} 4402 */ 4403 @ViewDebug.ExportedProperty(deepExport = true) 4404 protected Context mContext; 4405 4406 private final Resources mResources; 4407 4408 private ScrollabilityCache mScrollCache; 4409 4410 private int[] mDrawableState = null; 4411 4412 ViewOutlineProvider mOutlineProvider = ViewOutlineProvider.BACKGROUND; 4413 4414 /** 4415 * Animator that automatically runs based on state changes. 4416 */ 4417 private StateListAnimator mStateListAnimator; 4418 4419 /** 4420 * When this view has focus and the next focus is {@link #FOCUS_LEFT}, 4421 * the user may specify which view to go to next. 4422 */ 4423 private int mNextFocusLeftId = View.NO_ID; 4424 4425 /** 4426 * When this view has focus and the next focus is {@link #FOCUS_RIGHT}, 4427 * the user may specify which view to go to next. 4428 */ 4429 private int mNextFocusRightId = View.NO_ID; 4430 4431 /** 4432 * When this view has focus and the next focus is {@link #FOCUS_UP}, 4433 * the user may specify which view to go to next. 4434 */ 4435 private int mNextFocusUpId = View.NO_ID; 4436 4437 /** 4438 * When this view has focus and the next focus is {@link #FOCUS_DOWN}, 4439 * the user may specify which view to go to next. 4440 */ 4441 private int mNextFocusDownId = View.NO_ID; 4442 4443 /** 4444 * When this view has focus and the next focus is {@link #FOCUS_FORWARD}, 4445 * the user may specify which view to go to next. 4446 */ 4447 int mNextFocusForwardId = View.NO_ID; 4448 4449 /** 4450 * User-specified next keyboard navigation cluster in the {@link #FOCUS_FORWARD} direction. 4451 * 4452 * @see #findUserSetNextKeyboardNavigationCluster(View, int) 4453 */ 4454 int mNextClusterForwardId = View.NO_ID; 4455 4456 /** 4457 * Whether this View should use a default focus highlight when it gets focused but doesn't 4458 * have {@link android.R.attr#state_focused} defined in its background. 4459 */ 4460 boolean mDefaultFocusHighlightEnabled = true; 4461 4462 private CheckForLongPress mPendingCheckForLongPress; 4463 private CheckForTap mPendingCheckForTap = null; 4464 private PerformClick mPerformClick; 4465 private SendViewScrolledAccessibilityEvent mSendViewScrolledAccessibilityEvent; 4466 4467 private UnsetPressedState mUnsetPressedState; 4468 4469 /** 4470 * Whether the long press's action has been invoked. The tap's action is invoked on the 4471 * up event while a long press is invoked as soon as the long press duration is reached, so 4472 * a long press could be performed before the tap is checked, in which case the tap's action 4473 * should not be invoked. 4474 */ 4475 private boolean mHasPerformedLongPress; 4476 4477 /** 4478 * Whether a context click button is currently pressed down. This is true when the stylus is 4479 * touching the screen and the primary button has been pressed, or if a mouse's right button is 4480 * pressed. This is false once the button is released or if the stylus has been lifted. 4481 */ 4482 private boolean mInContextButtonPress; 4483 4484 /** 4485 * Whether the next up event should be ignored for the purposes of gesture recognition. This is 4486 * true after a stylus button press has occured, when the next up event should not be recognized 4487 * as a tap. 4488 */ 4489 private boolean mIgnoreNextUpEvent; 4490 4491 /** 4492 * The minimum height of the view. We'll try our best to have the height 4493 * of this view to at least this amount. 4494 */ 4495 @ViewDebug.ExportedProperty(category = "measurement") 4496 private int mMinHeight; 4497 4498 /** 4499 * The minimum width of the view. We'll try our best to have the width 4500 * of this view to at least this amount. 4501 */ 4502 @ViewDebug.ExportedProperty(category = "measurement") 4503 private int mMinWidth; 4504 4505 /** 4506 * The delegate to handle touch events that are physically in this view 4507 * but should be handled by another view. 4508 */ 4509 private TouchDelegate mTouchDelegate = null; 4510 4511 /** 4512 * Solid color to use as a background when creating the drawing cache. Enables 4513 * the cache to use 16 bit bitmaps instead of 32 bit. 4514 */ 4515 private int mDrawingCacheBackgroundColor = 0; 4516 4517 /** 4518 * Special tree observer used when mAttachInfo is null. 4519 */ 4520 private ViewTreeObserver mFloatingTreeObserver; 4521 4522 /** 4523 * Cache the touch slop from the context that created the view. 4524 */ 4525 private int mTouchSlop; 4526 4527 /** 4528 * Object that handles automatic animation of view properties. 4529 */ 4530 private ViewPropertyAnimator mAnimator = null; 4531 4532 /** 4533 * List of registered FrameMetricsObservers. 4534 */ 4535 private ArrayList<FrameMetricsObserver> mFrameMetricsObservers; 4536 4537 /** 4538 * Flag indicating that a drag can cross window boundaries. When 4539 * {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, int)} is called 4540 * with this flag set, all visible applications with targetSdkVersion >= 4541 * {@link android.os.Build.VERSION_CODES#N API 24} will be able to participate 4542 * in the drag operation and receive the dragged content. 4543 * 4544 * <p>If this is the only flag set, then the drag recipient will only have access to text data 4545 * and intents contained in the {@link ClipData} object. Access to URIs contained in the 4546 * {@link ClipData} is determined by other DRAG_FLAG_GLOBAL_* flags</p> 4547 */ 4548 public static final int DRAG_FLAG_GLOBAL = 1 << 8; // 256 4549 4550 /** 4551 * When this flag is used with {@link #DRAG_FLAG_GLOBAL}, the drag recipient will be able to 4552 * request read access to the content URI(s) contained in the {@link ClipData} object. 4553 * @see android.content.Intent#FLAG_GRANT_READ_URI_PERMISSION 4554 */ 4555 public static final int DRAG_FLAG_GLOBAL_URI_READ = Intent.FLAG_GRANT_READ_URI_PERMISSION; 4556 4557 /** 4558 * When this flag is used with {@link #DRAG_FLAG_GLOBAL}, the drag recipient will be able to 4559 * request write access to the content URI(s) contained in the {@link ClipData} object. 4560 * @see android.content.Intent#FLAG_GRANT_WRITE_URI_PERMISSION 4561 */ 4562 public static final int DRAG_FLAG_GLOBAL_URI_WRITE = Intent.FLAG_GRANT_WRITE_URI_PERMISSION; 4563 4564 /** 4565 * When this flag is used with {@link #DRAG_FLAG_GLOBAL_URI_READ} and/or {@link 4566 * #DRAG_FLAG_GLOBAL_URI_WRITE}, the URI permission grant can be persisted across device 4567 * reboots until explicitly revoked with 4568 * {@link android.content.Context#revokeUriPermission(Uri, int)} Context.revokeUriPermission}. 4569 * @see android.content.Intent#FLAG_GRANT_PERSISTABLE_URI_PERMISSION 4570 */ 4571 public static final int DRAG_FLAG_GLOBAL_PERSISTABLE_URI_PERMISSION = 4572 Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION; 4573 4574 /** 4575 * When this flag is used with {@link #DRAG_FLAG_GLOBAL_URI_READ} and/or {@link 4576 * #DRAG_FLAG_GLOBAL_URI_WRITE}, the URI permission grant applies to any URI that is a prefix 4577 * match against the original granted URI. 4578 * @see android.content.Intent#FLAG_GRANT_PREFIX_URI_PERMISSION 4579 */ 4580 public static final int DRAG_FLAG_GLOBAL_PREFIX_URI_PERMISSION = 4581 Intent.FLAG_GRANT_PREFIX_URI_PERMISSION; 4582 4583 /** 4584 * Flag indicating that the drag shadow will be opaque. When 4585 * {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, int)} is called 4586 * with this flag set, the drag shadow will be opaque, otherwise, it will be semitransparent. 4587 */ 4588 public static final int DRAG_FLAG_OPAQUE = 1 << 9; 4589 4590 /** 4591 * Vertical scroll factor cached by {@link #getVerticalScrollFactor}. 4592 */ 4593 private float mVerticalScrollFactor; 4594 4595 /** 4596 * Position of the vertical scroll bar. 4597 */ 4598 private int mVerticalScrollbarPosition; 4599 4600 /** 4601 * Position the scroll bar at the default position as determined by the system. 4602 */ 4603 public static final int SCROLLBAR_POSITION_DEFAULT = 0; 4604 4605 /** 4606 * Position the scroll bar along the left edge. 4607 */ 4608 public static final int SCROLLBAR_POSITION_LEFT = 1; 4609 4610 /** 4611 * Position the scroll bar along the right edge. 4612 */ 4613 public static final int SCROLLBAR_POSITION_RIGHT = 2; 4614 4615 /** 4616 * Indicates that the view does not have a layer. 4617 * 4618 * @see #getLayerType() 4619 * @see #setLayerType(int, android.graphics.Paint) 4620 * @see #LAYER_TYPE_SOFTWARE 4621 * @see #LAYER_TYPE_HARDWARE 4622 */ 4623 public static final int LAYER_TYPE_NONE = 0; 4624 4625 /** 4626 * <p>Indicates that the view has a software layer. A software layer is backed 4627 * by a bitmap and causes the view to be rendered using Android's software 4628 * rendering pipeline, even if hardware acceleration is enabled.</p> 4629 * 4630 * <p>Software layers have various usages:</p> 4631 * <p>When the application is not using hardware acceleration, a software layer 4632 * is useful to apply a specific color filter and/or blending mode and/or 4633 * translucency to a view and all its children.</p> 4634 * <p>When the application is using hardware acceleration, a software layer 4635 * is useful to render drawing primitives not supported by the hardware 4636 * accelerated pipeline. It can also be used to cache a complex view tree 4637 * into a texture and reduce the complexity of drawing operations. For instance, 4638 * when animating a complex view tree with a translation, a software layer can 4639 * be used to render the view tree only once.</p> 4640 * <p>Software layers should be avoided when the affected view tree updates 4641 * often. Every update will require to re-render the software layer, which can 4642 * potentially be slow (particularly when hardware acceleration is turned on 4643 * since the layer will have to be uploaded into a hardware texture after every 4644 * update.)</p> 4645 * 4646 * @see #getLayerType() 4647 * @see #setLayerType(int, android.graphics.Paint) 4648 * @see #LAYER_TYPE_NONE 4649 * @see #LAYER_TYPE_HARDWARE 4650 */ 4651 public static final int LAYER_TYPE_SOFTWARE = 1; 4652 4653 /** 4654 * <p>Indicates that the view has a hardware layer. A hardware layer is backed 4655 * by a hardware specific texture (generally Frame Buffer Objects or FBO on 4656 * OpenGL hardware) and causes the view to be rendered using Android's hardware 4657 * rendering pipeline, but only if hardware acceleration is turned on for the 4658 * view hierarchy. When hardware acceleration is turned off, hardware layers 4659 * behave exactly as {@link #LAYER_TYPE_SOFTWARE software layers}.</p> 4660 * 4661 * <p>A hardware layer is useful to apply a specific color filter and/or 4662 * blending mode and/or translucency to a view and all its children.</p> 4663 * <p>A hardware layer can be used to cache a complex view tree into a 4664 * texture and reduce the complexity of drawing operations. For instance, 4665 * when animating a complex view tree with a translation, a hardware layer can 4666 * be used to render the view tree only once.</p> 4667 * <p>A hardware layer can also be used to increase the rendering quality when 4668 * rotation transformations are applied on a view. It can also be used to 4669 * prevent potential clipping issues when applying 3D transforms on a view.</p> 4670 * 4671 * @see #getLayerType() 4672 * @see #setLayerType(int, android.graphics.Paint) 4673 * @see #LAYER_TYPE_NONE 4674 * @see #LAYER_TYPE_SOFTWARE 4675 */ 4676 public static final int LAYER_TYPE_HARDWARE = 2; 4677 4678 @ViewDebug.ExportedProperty(category = "drawing", mapping = { 4679 @ViewDebug.IntToString(from = LAYER_TYPE_NONE, to = "NONE"), 4680 @ViewDebug.IntToString(from = LAYER_TYPE_SOFTWARE, to = "SOFTWARE"), 4681 @ViewDebug.IntToString(from = LAYER_TYPE_HARDWARE, to = "HARDWARE") 4682 }) 4683 int mLayerType = LAYER_TYPE_NONE; 4684 Paint mLayerPaint; 4685 4686 /** 4687 * Set to true when drawing cache is enabled and cannot be created. 4688 * 4689 * @hide 4690 */ 4691 public boolean mCachingFailed; 4692 private Bitmap mDrawingCache; 4693 private Bitmap mUnscaledDrawingCache; 4694 4695 /** 4696 * RenderNode holding View properties, potentially holding a DisplayList of View content. 4697 * <p> 4698 * When non-null and valid, this is expected to contain an up-to-date copy 4699 * of the View content. Its DisplayList content is cleared on temporary detach and reset on 4700 * cleanup. 4701 */ 4702 final RenderNode mRenderNode; 4703 4704 /** 4705 * Set to true when the view is sending hover accessibility events because it 4706 * is the innermost hovered view. 4707 */ 4708 private boolean mSendingHoverAccessibilityEvents; 4709 4710 /** 4711 * Delegate for injecting accessibility functionality. 4712 */ 4713 AccessibilityDelegate mAccessibilityDelegate; 4714 4715 /** 4716 * The view's overlay layer. Developers get a reference to the overlay via getOverlay() 4717 * and add/remove objects to/from the overlay directly through the Overlay methods. 4718 */ 4719 ViewOverlay mOverlay; 4720 4721 /** 4722 * The currently active parent view for receiving delegated nested scrolling events. 4723 * This is set by {@link #startNestedScroll(int)} during a touch interaction and cleared 4724 * by {@link #stopNestedScroll()} at the same point where we clear 4725 * requestDisallowInterceptTouchEvent. 4726 */ 4727 private ViewParent mNestedScrollingParent; 4728 4729 /** 4730 * Consistency verifier for debugging purposes. 4731 * @hide 4732 */ 4733 protected final InputEventConsistencyVerifier mInputEventConsistencyVerifier = 4734 InputEventConsistencyVerifier.isInstrumentationEnabled() ? 4735 new InputEventConsistencyVerifier(this, 0) : null; 4736 4737 private static final AtomicInteger sNextGeneratedId = new AtomicInteger(1); 4738 4739 private int[] mTempNestedScrollConsumed; 4740 4741 /** 4742 * An overlay is going to draw this View instead of being drawn as part of this 4743 * View's parent. mGhostView is the View in the Overlay that must be invalidated 4744 * when this view is invalidated. 4745 */ 4746 GhostView mGhostView; 4747 4748 /** 4749 * Holds pairs of adjacent attribute data: attribute name followed by its value. 4750 * @hide 4751 */ 4752 @ViewDebug.ExportedProperty(category = "attributes", hasAdjacentMapping = true) 4753 public String[] mAttributes; 4754 4755 /** 4756 * Maps a Resource id to its name. 4757 */ 4758 private static SparseArray<String> mAttributeMap; 4759 4760 /** 4761 * Queue of pending runnables. Used to postpone calls to post() until this 4762 * view is attached and has a handler. 4763 */ 4764 private HandlerActionQueue mRunQueue; 4765 4766 /** 4767 * The pointer icon when the mouse hovers on this view. The default is null. 4768 */ 4769 private PointerIcon mPointerIcon; 4770 4771 /** 4772 * @hide 4773 */ 4774 String mStartActivityRequestWho; 4775 4776 @Nullable 4777 private RoundScrollbarRenderer mRoundScrollbarRenderer; 4778 4779 /** Used to delay visibility updates sent to the autofill manager */ 4780 private Handler mVisibilityChangeForAutofillHandler; 4781 4782 /** 4783 * Simple constructor to use when creating a view from code. 4784 * 4785 * @param context The Context the view is running in, through which it can 4786 * access the current theme, resources, etc. 4787 */ 4788 public View(Context context) { 4789 mContext = context; 4790 mResources = context != null ? context.getResources() : null; 4791 mViewFlags = SOUND_EFFECTS_ENABLED | HAPTIC_FEEDBACK_ENABLED | FOCUSABLE_AUTO; 4792 // Set some flags defaults 4793 mPrivateFlags2 = 4794 (LAYOUT_DIRECTION_DEFAULT << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT) | 4795 (TEXT_DIRECTION_DEFAULT << PFLAG2_TEXT_DIRECTION_MASK_SHIFT) | 4796 (PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT) | 4797 (TEXT_ALIGNMENT_DEFAULT << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT) | 4798 (PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT) | 4799 (IMPORTANT_FOR_ACCESSIBILITY_DEFAULT << PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT); 4800 mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); 4801 setOverScrollMode(OVER_SCROLL_IF_CONTENT_SCROLLS); 4802 mUserPaddingStart = UNDEFINED_PADDING; 4803 mUserPaddingEnd = UNDEFINED_PADDING; 4804 mRenderNode = RenderNode.create(getClass().getName(), this); 4805 4806 if (!sCompatibilityDone && context != null) { 4807 final int targetSdkVersion = context.getApplicationInfo().targetSdkVersion; 4808 4809 // Older apps may need this compatibility hack for measurement. 4810 sUseBrokenMakeMeasureSpec = targetSdkVersion <= Build.VERSION_CODES.JELLY_BEAN_MR1; 4811 4812 // Older apps expect onMeasure() to always be called on a layout pass, regardless 4813 // of whether a layout was requested on that View. 4814 sIgnoreMeasureCache = targetSdkVersion < Build.VERSION_CODES.KITKAT; 4815 4816 Canvas.sCompatibilityRestore = targetSdkVersion < Build.VERSION_CODES.M; 4817 Canvas.sCompatibilitySetBitmap = targetSdkVersion < Build.VERSION_CODES.O; 4818 Canvas.setCompatibilityVersion(targetSdkVersion); 4819 4820 // In M and newer, our widgets can pass a "hint" value in the size 4821 // for UNSPECIFIED MeasureSpecs. This lets child views of scrolling containers 4822 // know what the expected parent size is going to be, so e.g. list items can size 4823 // themselves at 1/3 the size of their container. It breaks older apps though, 4824 // specifically apps that use some popular open source libraries. 4825 sUseZeroUnspecifiedMeasureSpec = targetSdkVersion < Build.VERSION_CODES.M; 4826 4827 // Old versions of the platform would give different results from 4828 // LinearLayout measurement passes using EXACTLY and non-EXACTLY 4829 // modes, so we always need to run an additional EXACTLY pass. 4830 sAlwaysRemeasureExactly = targetSdkVersion <= Build.VERSION_CODES.M; 4831 4832 // Prior to N, layout params could change without requiring a 4833 // subsequent call to setLayoutParams() and they would usually 4834 // work. Partial layout breaks this assumption. 4835 sLayoutParamsAlwaysChanged = targetSdkVersion <= Build.VERSION_CODES.M; 4836 4837 // Prior to N, TextureView would silently ignore calls to setBackground/setForeground. 4838 // On N+, we throw, but that breaks compatibility with apps that use these methods. 4839 sTextureViewIgnoresDrawableSetters = targetSdkVersion <= Build.VERSION_CODES.M; 4840 4841 // Prior to N, we would drop margins in LayoutParam conversions. The fix triggers bugs 4842 // in apps so we target check it to avoid breaking existing apps. 4843 sPreserveMarginParamsInLayoutParamConversion = 4844 targetSdkVersion >= Build.VERSION_CODES.N; 4845 4846 sCascadedDragDrop = targetSdkVersion < Build.VERSION_CODES.N; 4847 4848 sHasFocusableExcludeAutoFocusable = targetSdkVersion < Build.VERSION_CODES.O; 4849 4850 sAutoFocusableOffUIThreadWontNotifyParents = targetSdkVersion < Build.VERSION_CODES.O; 4851 4852 sUseDefaultFocusHighlight = context.getResources().getBoolean( 4853 com.android.internal.R.bool.config_useDefaultFocusHighlight); 4854 4855 sThrowOnInvalidFloatProperties = targetSdkVersion >= Build.VERSION_CODES.P; 4856 4857 sCanFocusZeroSized = targetSdkVersion < Build.VERSION_CODES.P; 4858 4859 sAlwaysAssignFocus = targetSdkVersion < Build.VERSION_CODES.P; 4860 4861 sAcceptZeroSizeDragShadow = targetSdkVersion < Build.VERSION_CODES.P; 4862 4863 sCompatibilityDone = true; 4864 } 4865 } 4866 4867 /** 4868 * Constructor that is called when inflating a view from XML. This is called 4869 * when a view is being constructed from an XML file, supplying attributes 4870 * that were specified in the XML file. This version uses a default style of 4871 * 0, so the only attribute values applied are those in the Context's Theme 4872 * and the given AttributeSet. 4873 * 4874 * <p> 4875 * The method onFinishInflate() will be called after all children have been 4876 * added. 4877 * 4878 * @param context The Context the view is running in, through which it can 4879 * access the current theme, resources, etc. 4880 * @param attrs The attributes of the XML tag that is inflating the view. 4881 * @see #View(Context, AttributeSet, int) 4882 */ 4883 public View(Context context, @Nullable AttributeSet attrs) { 4884 this(context, attrs, 0); 4885 } 4886 4887 /** 4888 * Perform inflation from XML and apply a class-specific base style from a 4889 * theme attribute. This constructor of View allows subclasses to use their 4890 * own base style when they are inflating. For example, a Button class's 4891 * constructor would call this version of the super class constructor and 4892 * supply <code>R.attr.buttonStyle</code> for <var>defStyleAttr</var>; this 4893 * allows the theme's button style to modify all of the base view attributes 4894 * (in particular its background) as well as the Button class's attributes. 4895 * 4896 * @param context The Context the view is running in, through which it can 4897 * access the current theme, resources, etc. 4898 * @param attrs The attributes of the XML tag that is inflating the view. 4899 * @param defStyleAttr An attribute in the current theme that contains a 4900 * reference to a style resource that supplies default values for 4901 * the view. Can be 0 to not look for defaults. 4902 * @see #View(Context, AttributeSet) 4903 */ 4904 public View(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { 4905 this(context, attrs, defStyleAttr, 0); 4906 } 4907 4908 /** 4909 * Perform inflation from XML and apply a class-specific base style from a 4910 * theme attribute or style resource. This constructor of View allows 4911 * subclasses to use their own base style when they are inflating. 4912 * <p> 4913 * When determining the final value of a particular attribute, there are 4914 * four inputs that come into play: 4915 * <ol> 4916 * <li>Any attribute values in the given AttributeSet. 4917 * <li>The style resource specified in the AttributeSet (named "style"). 4918 * <li>The default style specified by <var>defStyleAttr</var>. 4919 * <li>The default style specified by <var>defStyleRes</var>. 4920 * <li>The base values in this theme. 4921 * </ol> 4922 * <p> 4923 * Each of these inputs is considered in-order, with the first listed taking 4924 * precedence over the following ones. In other words, if in the 4925 * AttributeSet you have supplied <code><Button * textColor="#ff000000"></code> 4926 * , then the button's text will <em>always</em> be black, regardless of 4927 * what is specified in any of the styles. 4928 * 4929 * @param context The Context the view is running in, through which it can 4930 * access the current theme, resources, etc. 4931 * @param attrs The attributes of the XML tag that is inflating the view. 4932 * @param defStyleAttr An attribute in the current theme that contains a 4933 * reference to a style resource that supplies default values for 4934 * the view. Can be 0 to not look for defaults. 4935 * @param defStyleRes A resource identifier of a style resource that 4936 * supplies default values for the view, used only if 4937 * defStyleAttr is 0 or can not be found in the theme. Can be 0 4938 * to not look for defaults. 4939 * @see #View(Context, AttributeSet, int) 4940 */ 4941 public View(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) { 4942 this(context); 4943 4944 final TypedArray a = context.obtainStyledAttributes( 4945 attrs, com.android.internal.R.styleable.View, defStyleAttr, defStyleRes); 4946 4947 if (mDebugViewAttributes) { 4948 saveAttributeData(attrs, a); 4949 } 4950 4951 Drawable background = null; 4952 4953 int leftPadding = -1; 4954 int topPadding = -1; 4955 int rightPadding = -1; 4956 int bottomPadding = -1; 4957 int startPadding = UNDEFINED_PADDING; 4958 int endPadding = UNDEFINED_PADDING; 4959 4960 int padding = -1; 4961 int paddingHorizontal = -1; 4962 int paddingVertical = -1; 4963 4964 int viewFlagValues = 0; 4965 int viewFlagMasks = 0; 4966 4967 boolean setScrollContainer = false; 4968 4969 int x = 0; 4970 int y = 0; 4971 4972 float tx = 0; 4973 float ty = 0; 4974 float tz = 0; 4975 float elevation = 0; 4976 float rotation = 0; 4977 float rotationX = 0; 4978 float rotationY = 0; 4979 float sx = 1f; 4980 float sy = 1f; 4981 boolean transformSet = false; 4982 4983 int scrollbarStyle = SCROLLBARS_INSIDE_OVERLAY; 4984 int overScrollMode = mOverScrollMode; 4985 boolean initializeScrollbars = false; 4986 boolean initializeScrollIndicators = false; 4987 4988 boolean startPaddingDefined = false; 4989 boolean endPaddingDefined = false; 4990 boolean leftPaddingDefined = false; 4991 boolean rightPaddingDefined = false; 4992 4993 final int targetSdkVersion = context.getApplicationInfo().targetSdkVersion; 4994 4995 // Set default values. 4996 viewFlagValues |= FOCUSABLE_AUTO; 4997 viewFlagMasks |= FOCUSABLE_AUTO; 4998 4999 final int N = a.getIndexCount(); 5000 for (int i = 0; i < N; i++) { 5001 int attr = a.getIndex(i); 5002 switch (attr) { 5003 case com.android.internal.R.styleable.View_background: 5004 background = a.getDrawable(attr); 5005 break; 5006 case com.android.internal.R.styleable.View_padding: 5007 padding = a.getDimensionPixelSize(attr, -1); 5008 mUserPaddingLeftInitial = padding; 5009 mUserPaddingRightInitial = padding; 5010 leftPaddingDefined = true; 5011 rightPaddingDefined = true; 5012 break; 5013 case com.android.internal.R.styleable.View_paddingHorizontal: 5014 paddingHorizontal = a.getDimensionPixelSize(attr, -1); 5015 mUserPaddingLeftInitial = paddingHorizontal; 5016 mUserPaddingRightInitial = paddingHorizontal; 5017 leftPaddingDefined = true; 5018 rightPaddingDefined = true; 5019 break; 5020 case com.android.internal.R.styleable.View_paddingVertical: 5021 paddingVertical = a.getDimensionPixelSize(attr, -1); 5022 break; 5023 case com.android.internal.R.styleable.View_paddingLeft: 5024 leftPadding = a.getDimensionPixelSize(attr, -1); 5025 mUserPaddingLeftInitial = leftPadding; 5026 leftPaddingDefined = true; 5027 break; 5028 case com.android.internal.R.styleable.View_paddingTop: 5029 topPadding = a.getDimensionPixelSize(attr, -1); 5030 break; 5031 case com.android.internal.R.styleable.View_paddingRight: 5032 rightPadding = a.getDimensionPixelSize(attr, -1); 5033 mUserPaddingRightInitial = rightPadding; 5034 rightPaddingDefined = true; 5035 break; 5036 case com.android.internal.R.styleable.View_paddingBottom: 5037 bottomPadding = a.getDimensionPixelSize(attr, -1); 5038 break; 5039 case com.android.internal.R.styleable.View_paddingStart: 5040 startPadding = a.getDimensionPixelSize(attr, UNDEFINED_PADDING); 5041 startPaddingDefined = (startPadding != UNDEFINED_PADDING); 5042 break; 5043 case com.android.internal.R.styleable.View_paddingEnd: 5044 endPadding = a.getDimensionPixelSize(attr, UNDEFINED_PADDING); 5045 endPaddingDefined = (endPadding != UNDEFINED_PADDING); 5046 break; 5047 case com.android.internal.R.styleable.View_scrollX: 5048 x = a.getDimensionPixelOffset(attr, 0); 5049 break; 5050 case com.android.internal.R.styleable.View_scrollY: 5051 y = a.getDimensionPixelOffset(attr, 0); 5052 break; 5053 case com.android.internal.R.styleable.View_alpha: 5054 setAlpha(a.getFloat(attr, 1f)); 5055 break; 5056 case com.android.internal.R.styleable.View_transformPivotX: 5057 setPivotX(a.getDimension(attr, 0)); 5058 break; 5059 case com.android.internal.R.styleable.View_transformPivotY: 5060 setPivotY(a.getDimension(attr, 0)); 5061 break; 5062 case com.android.internal.R.styleable.View_translationX: 5063 tx = a.getDimension(attr, 0); 5064 transformSet = true; 5065 break; 5066 case com.android.internal.R.styleable.View_translationY: 5067 ty = a.getDimension(attr, 0); 5068 transformSet = true; 5069 break; 5070 case com.android.internal.R.styleable.View_translationZ: 5071 tz = a.getDimension(attr, 0); 5072 transformSet = true; 5073 break; 5074 case com.android.internal.R.styleable.View_elevation: 5075 elevation = a.getDimension(attr, 0); 5076 transformSet = true; 5077 break; 5078 case com.android.internal.R.styleable.View_rotation: 5079 rotation = a.getFloat(attr, 0); 5080 transformSet = true; 5081 break; 5082 case com.android.internal.R.styleable.View_rotationX: 5083 rotationX = a.getFloat(attr, 0); 5084 transformSet = true; 5085 break; 5086 case com.android.internal.R.styleable.View_rotationY: 5087 rotationY = a.getFloat(attr, 0); 5088 transformSet = true; 5089 break; 5090 case com.android.internal.R.styleable.View_scaleX: 5091 sx = a.getFloat(attr, 1f); 5092 transformSet = true; 5093 break; 5094 case com.android.internal.R.styleable.View_scaleY: 5095 sy = a.getFloat(attr, 1f); 5096 transformSet = true; 5097 break; 5098 case com.android.internal.R.styleable.View_id: 5099 mID = a.getResourceId(attr, NO_ID); 5100 break; 5101 case com.android.internal.R.styleable.View_tag: 5102 mTag = a.getText(attr); 5103 break; 5104 case com.android.internal.R.styleable.View_fitsSystemWindows: 5105 if (a.getBoolean(attr, false)) { 5106 viewFlagValues |= FITS_SYSTEM_WINDOWS; 5107 viewFlagMasks |= FITS_SYSTEM_WINDOWS; 5108 } 5109 break; 5110 case com.android.internal.R.styleable.View_focusable: 5111 viewFlagValues = (viewFlagValues & ~FOCUSABLE_MASK) | getFocusableAttribute(a); 5112 if ((viewFlagValues & FOCUSABLE_AUTO) == 0) { 5113 viewFlagMasks |= FOCUSABLE_MASK; 5114 } 5115 break; 5116 case com.android.internal.R.styleable.View_focusableInTouchMode: 5117 if (a.getBoolean(attr, false)) { 5118 // unset auto focus since focusableInTouchMode implies explicit focusable 5119 viewFlagValues &= ~FOCUSABLE_AUTO; 5120 viewFlagValues |= FOCUSABLE_IN_TOUCH_MODE | FOCUSABLE; 5121 viewFlagMasks |= FOCUSABLE_IN_TOUCH_MODE | FOCUSABLE_MASK; 5122 } 5123 break; 5124 case com.android.internal.R.styleable.View_clickable: 5125 if (a.getBoolean(attr, false)) { 5126 viewFlagValues |= CLICKABLE; 5127 viewFlagMasks |= CLICKABLE; 5128 } 5129 break; 5130 case com.android.internal.R.styleable.View_longClickable: 5131 if (a.getBoolean(attr, false)) { 5132 viewFlagValues |= LONG_CLICKABLE; 5133 viewFlagMasks |= LONG_CLICKABLE; 5134 } 5135 break; 5136 case com.android.internal.R.styleable.View_contextClickable: 5137 if (a.getBoolean(attr, false)) { 5138 viewFlagValues |= CONTEXT_CLICKABLE; 5139 viewFlagMasks |= CONTEXT_CLICKABLE; 5140 } 5141 break; 5142 case com.android.internal.R.styleable.View_saveEnabled: 5143 if (!a.getBoolean(attr, true)) { 5144 viewFlagValues |= SAVE_DISABLED; 5145 viewFlagMasks |= SAVE_DISABLED_MASK; 5146 } 5147 break; 5148 case com.android.internal.R.styleable.View_duplicateParentState: 5149 if (a.getBoolean(attr, false)) { 5150 viewFlagValues |= DUPLICATE_PARENT_STATE; 5151 viewFlagMasks |= DUPLICATE_PARENT_STATE; 5152 } 5153 break; 5154 case com.android.internal.R.styleable.View_visibility: 5155 final int visibility = a.getInt(attr, 0); 5156 if (visibility != 0) { 5157 viewFlagValues |= VISIBILITY_FLAGS[visibility]; 5158 viewFlagMasks |= VISIBILITY_MASK; 5159 } 5160 break; 5161 case com.android.internal.R.styleable.View_layoutDirection: 5162 // Clear any layout direction flags (included resolved bits) already set 5163 mPrivateFlags2 &= 5164 ~(PFLAG2_LAYOUT_DIRECTION_MASK | PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK); 5165 // Set the layout direction flags depending on the value of the attribute 5166 final int layoutDirection = a.getInt(attr, -1); 5167 final int value = (layoutDirection != -1) ? 5168 LAYOUT_DIRECTION_FLAGS[layoutDirection] : LAYOUT_DIRECTION_DEFAULT; 5169 mPrivateFlags2 |= (value << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT); 5170 break; 5171 case com.android.internal.R.styleable.View_drawingCacheQuality: 5172 final int cacheQuality = a.getInt(attr, 0); 5173 if (cacheQuality != 0) { 5174 viewFlagValues |= DRAWING_CACHE_QUALITY_FLAGS[cacheQuality]; 5175 viewFlagMasks |= DRAWING_CACHE_QUALITY_MASK; 5176 } 5177 break; 5178 case com.android.internal.R.styleable.View_contentDescription: 5179 setContentDescription(a.getString(attr)); 5180 break; 5181 case com.android.internal.R.styleable.View_accessibilityTraversalBefore: 5182 setAccessibilityTraversalBefore(a.getResourceId(attr, NO_ID)); 5183 break; 5184 case com.android.internal.R.styleable.View_accessibilityTraversalAfter: 5185 setAccessibilityTraversalAfter(a.getResourceId(attr, NO_ID)); 5186 break; 5187 case com.android.internal.R.styleable.View_labelFor: 5188 setLabelFor(a.getResourceId(attr, NO_ID)); 5189 break; 5190 case com.android.internal.R.styleable.View_soundEffectsEnabled: 5191 if (!a.getBoolean(attr, true)) { 5192 viewFlagValues &= ~SOUND_EFFECTS_ENABLED; 5193 viewFlagMasks |= SOUND_EFFECTS_ENABLED; 5194 } 5195 break; 5196 case com.android.internal.R.styleable.View_hapticFeedbackEnabled: 5197 if (!a.getBoolean(attr, true)) { 5198 viewFlagValues &= ~HAPTIC_FEEDBACK_ENABLED; 5199 viewFlagMasks |= HAPTIC_FEEDBACK_ENABLED; 5200 } 5201 break; 5202 case R.styleable.View_scrollbars: 5203 final int scrollbars = a.getInt(attr, SCROLLBARS_NONE); 5204 if (scrollbars != SCROLLBARS_NONE) { 5205 viewFlagValues |= scrollbars; 5206 viewFlagMasks |= SCROLLBARS_MASK; 5207 initializeScrollbars = true; 5208 } 5209 break; 5210 //noinspection deprecation 5211 case R.styleable.View_fadingEdge: 5212 if (targetSdkVersion >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { 5213 // Ignore the attribute starting with ICS 5214 break; 5215 } 5216 // With builds < ICS, fall through and apply fading edges 5217 case R.styleable.View_requiresFadingEdge: 5218 final int fadingEdge = a.getInt(attr, FADING_EDGE_NONE); 5219 if (fadingEdge != FADING_EDGE_NONE) { 5220 viewFlagValues |= fadingEdge; 5221 viewFlagMasks |= FADING_EDGE_MASK; 5222 initializeFadingEdgeInternal(a); 5223 } 5224 break; 5225 case R.styleable.View_scrollbarStyle: 5226 scrollbarStyle = a.getInt(attr, SCROLLBARS_INSIDE_OVERLAY); 5227 if (scrollbarStyle != SCROLLBARS_INSIDE_OVERLAY) { 5228 viewFlagValues |= scrollbarStyle & SCROLLBARS_STYLE_MASK; 5229 viewFlagMasks |= SCROLLBARS_STYLE_MASK; 5230 } 5231 break; 5232 case R.styleable.View_isScrollContainer: 5233 setScrollContainer = true; 5234 if (a.getBoolean(attr, false)) { 5235 setScrollContainer(true); 5236 } 5237 break; 5238 case com.android.internal.R.styleable.View_keepScreenOn: 5239 if (a.getBoolean(attr, false)) { 5240 viewFlagValues |= KEEP_SCREEN_ON; 5241 viewFlagMasks |= KEEP_SCREEN_ON; 5242 } 5243 break; 5244 case R.styleable.View_filterTouchesWhenObscured: 5245 if (a.getBoolean(attr, false)) { 5246 viewFlagValues |= FILTER_TOUCHES_WHEN_OBSCURED; 5247 viewFlagMasks |= FILTER_TOUCHES_WHEN_OBSCURED; 5248 } 5249 break; 5250 case R.styleable.View_nextFocusLeft: 5251 mNextFocusLeftId = a.getResourceId(attr, View.NO_ID); 5252 break; 5253 case R.styleable.View_nextFocusRight: 5254 mNextFocusRightId = a.getResourceId(attr, View.NO_ID); 5255 break; 5256 case R.styleable.View_nextFocusUp: 5257 mNextFocusUpId = a.getResourceId(attr, View.NO_ID); 5258 break; 5259 case R.styleable.View_nextFocusDown: 5260 mNextFocusDownId = a.getResourceId(attr, View.NO_ID); 5261 break; 5262 case R.styleable.View_nextFocusForward: 5263 mNextFocusForwardId = a.getResourceId(attr, View.NO_ID); 5264 break; 5265 case R.styleable.View_nextClusterForward: 5266 mNextClusterForwardId = a.getResourceId(attr, View.NO_ID); 5267 break; 5268 case R.styleable.View_minWidth: 5269 mMinWidth = a.getDimensionPixelSize(attr, 0); 5270 break; 5271 case R.styleable.View_minHeight: 5272 mMinHeight = a.getDimensionPixelSize(attr, 0); 5273 break; 5274 case R.styleable.View_onClick: 5275 if (context.isRestricted()) { 5276 throw new IllegalStateException("The android:onClick attribute cannot " 5277 + "be used within a restricted context"); 5278 } 5279 5280 final String handlerName = a.getString(attr); 5281 if (handlerName != null) { 5282 setOnClickListener(new DeclaredOnClickListener(this, handlerName)); 5283 } 5284 break; 5285 case R.styleable.View_overScrollMode: 5286 overScrollMode = a.getInt(attr, OVER_SCROLL_IF_CONTENT_SCROLLS); 5287 break; 5288 case R.styleable.View_verticalScrollbarPosition: 5289 mVerticalScrollbarPosition = a.getInt(attr, SCROLLBAR_POSITION_DEFAULT); 5290 break; 5291 case R.styleable.View_layerType: 5292 setLayerType(a.getInt(attr, LAYER_TYPE_NONE), null); 5293 break; 5294 case R.styleable.View_textDirection: 5295 // Clear any text direction flag already set 5296 mPrivateFlags2 &= ~PFLAG2_TEXT_DIRECTION_MASK; 5297 // Set the text direction flags depending on the value of the attribute 5298 final int textDirection = a.getInt(attr, -1); 5299 if (textDirection != -1) { 5300 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_FLAGS[textDirection]; 5301 } 5302 break; 5303 case R.styleable.View_textAlignment: 5304 // Clear any text alignment flag already set 5305 mPrivateFlags2 &= ~PFLAG2_TEXT_ALIGNMENT_MASK; 5306 // Set the text alignment flag depending on the value of the attribute 5307 final int textAlignment = a.getInt(attr, TEXT_ALIGNMENT_DEFAULT); 5308 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_FLAGS[textAlignment]; 5309 break; 5310 case R.styleable.View_importantForAccessibility: 5311 setImportantForAccessibility(a.getInt(attr, 5312 IMPORTANT_FOR_ACCESSIBILITY_DEFAULT)); 5313 break; 5314 case R.styleable.View_accessibilityLiveRegion: 5315 setAccessibilityLiveRegion(a.getInt(attr, ACCESSIBILITY_LIVE_REGION_DEFAULT)); 5316 break; 5317 case R.styleable.View_transitionName: 5318 setTransitionName(a.getString(attr)); 5319 break; 5320 case R.styleable.View_nestedScrollingEnabled: 5321 setNestedScrollingEnabled(a.getBoolean(attr, false)); 5322 break; 5323 case R.styleable.View_stateListAnimator: 5324 setStateListAnimator(AnimatorInflater.loadStateListAnimator(context, 5325 a.getResourceId(attr, 0))); 5326 break; 5327 case R.styleable.View_backgroundTint: 5328 // This will get applied later during setBackground(). 5329 if (mBackgroundTint == null) { 5330 mBackgroundTint = new TintInfo(); 5331 } 5332 mBackgroundTint.mTintList = a.getColorStateList( 5333 R.styleable.View_backgroundTint); 5334 mBackgroundTint.mHasTintList = true; 5335 break; 5336 case R.styleable.View_backgroundTintMode: 5337 // This will get applied later during setBackground(). 5338 if (mBackgroundTint == null) { 5339 mBackgroundTint = new TintInfo(); 5340 } 5341 mBackgroundTint.mTintMode = Drawable.parseTintMode(a.getInt( 5342 R.styleable.View_backgroundTintMode, -1), null); 5343 mBackgroundTint.mHasTintMode = true; 5344 break; 5345 case R.styleable.View_outlineProvider: 5346 setOutlineProviderFromAttribute(a.getInt(R.styleable.View_outlineProvider, 5347 PROVIDER_BACKGROUND)); 5348 break; 5349 case R.styleable.View_foreground: 5350 if (targetSdkVersion >= Build.VERSION_CODES.M || this instanceof FrameLayout) { 5351 setForeground(a.getDrawable(attr)); 5352 } 5353 break; 5354 case R.styleable.View_foregroundGravity: 5355 if (targetSdkVersion >= Build.VERSION_CODES.M || this instanceof FrameLayout) { 5356 setForegroundGravity(a.getInt(attr, Gravity.NO_GRAVITY)); 5357 } 5358 break; 5359 case R.styleable.View_foregroundTintMode: 5360 if (targetSdkVersion >= Build.VERSION_CODES.M || this instanceof FrameLayout) { 5361 setForegroundTintMode(Drawable.parseTintMode(a.getInt(attr, -1), null)); 5362 } 5363 break; 5364 case R.styleable.View_foregroundTint: 5365 if (targetSdkVersion >= Build.VERSION_CODES.M || this instanceof FrameLayout) { 5366 setForegroundTintList(a.getColorStateList(attr)); 5367 } 5368 break; 5369 case R.styleable.View_foregroundInsidePadding: 5370 if (targetSdkVersion >= Build.VERSION_CODES.M || this instanceof FrameLayout) { 5371 if (mForegroundInfo == null) { 5372 mForegroundInfo = new ForegroundInfo(); 5373 } 5374 mForegroundInfo.mInsidePadding = a.getBoolean(attr, 5375 mForegroundInfo.mInsidePadding); 5376 } 5377 break; 5378 case R.styleable.View_scrollIndicators: 5379 final int scrollIndicators = 5380 (a.getInt(attr, 0) << SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT) 5381 & SCROLL_INDICATORS_PFLAG3_MASK; 5382 if (scrollIndicators != 0) { 5383 mPrivateFlags3 |= scrollIndicators; 5384 initializeScrollIndicators = true; 5385 } 5386 break; 5387 case R.styleable.View_pointerIcon: 5388 final int resourceId = a.getResourceId(attr, 0); 5389 if (resourceId != 0) { 5390 setPointerIcon(PointerIcon.load( 5391 context.getResources(), resourceId)); 5392 } else { 5393 final int pointerType = a.getInt(attr, PointerIcon.TYPE_NOT_SPECIFIED); 5394 if (pointerType != PointerIcon.TYPE_NOT_SPECIFIED) { 5395 setPointerIcon(PointerIcon.getSystemIcon(context, pointerType)); 5396 } 5397 } 5398 break; 5399 case R.styleable.View_forceHasOverlappingRendering: 5400 if (a.peekValue(attr) != null) { 5401 forceHasOverlappingRendering(a.getBoolean(attr, true)); 5402 } 5403 break; 5404 case R.styleable.View_tooltipText: 5405 setTooltipText(a.getText(attr)); 5406 break; 5407 case R.styleable.View_keyboardNavigationCluster: 5408 if (a.peekValue(attr) != null) { 5409 setKeyboardNavigationCluster(a.getBoolean(attr, true)); 5410 } 5411 break; 5412 case R.styleable.View_focusedByDefault: 5413 if (a.peekValue(attr) != null) { 5414 setFocusedByDefault(a.getBoolean(attr, true)); 5415 } 5416 break; 5417 case R.styleable.View_autofillHints: 5418 if (a.peekValue(attr) != null) { 5419 CharSequence[] rawHints = null; 5420 String rawString = null; 5421 5422 if (a.getType(attr) == TypedValue.TYPE_REFERENCE) { 5423 int resId = a.getResourceId(attr, 0); 5424 5425 try { 5426 rawHints = a.getTextArray(attr); 5427 } catch (Resources.NotFoundException e) { 5428 rawString = getResources().getString(resId); 5429 } 5430 } else { 5431 rawString = a.getString(attr); 5432 } 5433 5434 if (rawHints == null) { 5435 if (rawString == null) { 5436 throw new IllegalArgumentException( 5437 "Could not resolve autofillHints"); 5438 } else { 5439 rawHints = rawString.split(","); 5440 } 5441 } 5442 5443 String[] hints = new String[rawHints.length]; 5444 5445 int numHints = rawHints.length; 5446 for (int rawHintNum = 0; rawHintNum < numHints; rawHintNum++) { 5447 hints[rawHintNum] = rawHints[rawHintNum].toString().trim(); 5448 } 5449 setAutofillHints(hints); 5450 } 5451 break; 5452 case R.styleable.View_importantForAutofill: 5453 if (a.peekValue(attr) != null) { 5454 setImportantForAutofill(a.getInt(attr, IMPORTANT_FOR_AUTOFILL_AUTO)); 5455 } 5456 break; 5457 case R.styleable.View_defaultFocusHighlightEnabled: 5458 if (a.peekValue(attr) != null) { 5459 setDefaultFocusHighlightEnabled(a.getBoolean(attr, true)); 5460 } 5461 break; 5462 case R.styleable.View_screenReaderFocusable: 5463 if (a.peekValue(attr) != null) { 5464 setScreenReaderFocusable(a.getBoolean(attr, false)); 5465 } 5466 break; 5467 case R.styleable.View_accessibilityPaneTitle: 5468 if (a.peekValue(attr) != null) { 5469 setAccessibilityPaneTitle(a.getString(attr)); 5470 } 5471 break; 5472 case R.styleable.View_outlineSpotShadowColor: 5473 setOutlineSpotShadowColor(a.getColor(attr, Color.BLACK)); 5474 break; 5475 case R.styleable.View_outlineAmbientShadowColor: 5476 setOutlineAmbientShadowColor(a.getColor(attr, Color.BLACK)); 5477 break; 5478 } 5479 } 5480 5481 setOverScrollMode(overScrollMode); 5482 5483 // Cache start/end user padding as we cannot fully resolve padding here (we dont have yet 5484 // the resolved layout direction). Those cached values will be used later during padding 5485 // resolution. 5486 mUserPaddingStart = startPadding; 5487 mUserPaddingEnd = endPadding; 5488 5489 if (background != null) { 5490 setBackground(background); 5491 } 5492 5493 // setBackground above will record that padding is currently provided by the background. 5494 // If we have padding specified via xml, record that here instead and use it. 5495 mLeftPaddingDefined = leftPaddingDefined; 5496 mRightPaddingDefined = rightPaddingDefined; 5497 5498 if (padding >= 0) { 5499 leftPadding = padding; 5500 topPadding = padding; 5501 rightPadding = padding; 5502 bottomPadding = padding; 5503 mUserPaddingLeftInitial = padding; 5504 mUserPaddingRightInitial = padding; 5505 } else { 5506 if (paddingHorizontal >= 0) { 5507 leftPadding = paddingHorizontal; 5508 rightPadding = paddingHorizontal; 5509 mUserPaddingLeftInitial = paddingHorizontal; 5510 mUserPaddingRightInitial = paddingHorizontal; 5511 } 5512 if (paddingVertical >= 0) { 5513 topPadding = paddingVertical; 5514 bottomPadding = paddingVertical; 5515 } 5516 } 5517 5518 if (isRtlCompatibilityMode()) { 5519 // RTL compatibility mode: pre Jelly Bean MR1 case OR no RTL support case. 5520 // left / right padding are used if defined (meaning here nothing to do). If they are not 5521 // defined and start / end padding are defined (e.g. in Frameworks resources), then we use 5522 // start / end and resolve them as left / right (layout direction is not taken into account). 5523 // Padding from the background drawable is stored at this point in mUserPaddingLeftInitial 5524 // and mUserPaddingRightInitial) so drawable padding will be used as ultimate default if 5525 // defined. 5526 if (!mLeftPaddingDefined && startPaddingDefined) { 5527 leftPadding = startPadding; 5528 } 5529 mUserPaddingLeftInitial = (leftPadding >= 0) ? leftPadding : mUserPaddingLeftInitial; 5530 if (!mRightPaddingDefined && endPaddingDefined) { 5531 rightPadding = endPadding; 5532 } 5533 mUserPaddingRightInitial = (rightPadding >= 0) ? rightPadding : mUserPaddingRightInitial; 5534 } else { 5535 // Jelly Bean MR1 and after case: if start/end defined, they will override any left/right 5536 // values defined. Otherwise, left /right values are used. 5537 // Padding from the background drawable is stored at this point in mUserPaddingLeftInitial 5538 // and mUserPaddingRightInitial) so drawable padding will be used as ultimate default if 5539 // defined. 5540 final boolean hasRelativePadding = startPaddingDefined || endPaddingDefined; 5541 5542 if (mLeftPaddingDefined && !hasRelativePadding) { 5543 mUserPaddingLeftInitial = leftPadding; 5544 } 5545 if (mRightPaddingDefined && !hasRelativePadding) { 5546 mUserPaddingRightInitial = rightPadding; 5547 } 5548 } 5549 5550 internalSetPadding( 5551 mUserPaddingLeftInitial, 5552 topPadding >= 0 ? topPadding : mPaddingTop, 5553 mUserPaddingRightInitial, 5554 bottomPadding >= 0 ? bottomPadding : mPaddingBottom); 5555 5556 if (viewFlagMasks != 0) { 5557 setFlags(viewFlagValues, viewFlagMasks); 5558 } 5559 5560 if (initializeScrollbars) { 5561 initializeScrollbarsInternal(a); 5562 } 5563 5564 if (initializeScrollIndicators) { 5565 initializeScrollIndicatorsInternal(); 5566 } 5567 5568 a.recycle(); 5569 5570 // Needs to be called after mViewFlags is set 5571 if (scrollbarStyle != SCROLLBARS_INSIDE_OVERLAY) { 5572 recomputePadding(); 5573 } 5574 5575 if (x != 0 || y != 0) { 5576 scrollTo(x, y); 5577 } 5578 5579 if (transformSet) { 5580 setTranslationX(tx); 5581 setTranslationY(ty); 5582 setTranslationZ(tz); 5583 setElevation(elevation); 5584 setRotation(rotation); 5585 setRotationX(rotationX); 5586 setRotationY(rotationY); 5587 setScaleX(sx); 5588 setScaleY(sy); 5589 } 5590 5591 if (!setScrollContainer && (viewFlagValues&SCROLLBARS_VERTICAL) != 0) { 5592 setScrollContainer(true); 5593 } 5594 5595 computeOpaqueFlags(); 5596 } 5597 5598 /** 5599 * An implementation of OnClickListener that attempts to lazily load a 5600 * named click handling method from a parent or ancestor context. 5601 */ 5602 private static class DeclaredOnClickListener implements OnClickListener { 5603 private final View mHostView; 5604 private final String mMethodName; 5605 5606 private Method mResolvedMethod; 5607 private Context mResolvedContext; 5608 5609 public DeclaredOnClickListener(@NonNull View hostView, @NonNull String methodName) { 5610 mHostView = hostView; 5611 mMethodName = methodName; 5612 } 5613 5614 @Override 5615 public void onClick(@NonNull View v) { 5616 if (mResolvedMethod == null) { 5617 resolveMethod(mHostView.getContext(), mMethodName); 5618 } 5619 5620 try { 5621 mResolvedMethod.invoke(mResolvedContext, v); 5622 } catch (IllegalAccessException e) { 5623 throw new IllegalStateException( 5624 "Could not execute non-public method for android:onClick", e); 5625 } catch (InvocationTargetException e) { 5626 throw new IllegalStateException( 5627 "Could not execute method for android:onClick", e); 5628 } 5629 } 5630 5631 @NonNull 5632 private void resolveMethod(@Nullable Context context, @NonNull String name) { 5633 while (context != null) { 5634 try { 5635 if (!context.isRestricted()) { 5636 final Method method = context.getClass().getMethod(mMethodName, View.class); 5637 if (method != null) { 5638 mResolvedMethod = method; 5639 mResolvedContext = context; 5640 return; 5641 } 5642 } 5643 } catch (NoSuchMethodException e) { 5644 // Failed to find method, keep searching up the hierarchy. 5645 } 5646 5647 if (context instanceof ContextWrapper) { 5648 context = ((ContextWrapper) context).getBaseContext(); 5649 } else { 5650 // Can't search up the hierarchy, null out and fail. 5651 context = null; 5652 } 5653 } 5654 5655 final int id = mHostView.getId(); 5656 final String idText = id == NO_ID ? "" : " with id '" 5657 + mHostView.getContext().getResources().getResourceEntryName(id) + "'"; 5658 throw new IllegalStateException("Could not find method " + mMethodName 5659 + "(View) in a parent or ancestor Context for android:onClick " 5660 + "attribute defined on view " + mHostView.getClass() + idText); 5661 } 5662 } 5663 5664 /** 5665 * Non-public constructor for use in testing 5666 */ 5667 View() { 5668 mResources = null; 5669 mRenderNode = RenderNode.create(getClass().getName(), this); 5670 } 5671 5672 final boolean debugDraw() { 5673 return DEBUG_DRAW || mAttachInfo != null && mAttachInfo.mDebugLayout; 5674 } 5675 5676 private static SparseArray<String> getAttributeMap() { 5677 if (mAttributeMap == null) { 5678 mAttributeMap = new SparseArray<>(); 5679 } 5680 return mAttributeMap; 5681 } 5682 5683 private void saveAttributeData(@Nullable AttributeSet attrs, @NonNull TypedArray t) { 5684 final int attrsCount = attrs == null ? 0 : attrs.getAttributeCount(); 5685 final int indexCount = t.getIndexCount(); 5686 final String[] attributes = new String[(attrsCount + indexCount) * 2]; 5687 5688 int i = 0; 5689 5690 // Store raw XML attributes. 5691 for (int j = 0; j < attrsCount; ++j) { 5692 attributes[i] = attrs.getAttributeName(j); 5693 attributes[i + 1] = attrs.getAttributeValue(j); 5694 i += 2; 5695 } 5696 5697 // Store resolved styleable attributes. 5698 final Resources res = t.getResources(); 5699 final SparseArray<String> attributeMap = getAttributeMap(); 5700 for (int j = 0; j < indexCount; ++j) { 5701 final int index = t.getIndex(j); 5702 if (!t.hasValueOrEmpty(index)) { 5703 // Value is undefined. Skip it. 5704 continue; 5705 } 5706 5707 final int resourceId = t.getResourceId(index, 0); 5708 if (resourceId == 0) { 5709 // Value is not a reference. Skip it. 5710 continue; 5711 } 5712 5713 String resourceName = attributeMap.get(resourceId); 5714 if (resourceName == null) { 5715 try { 5716 resourceName = res.getResourceName(resourceId); 5717 } catch (Resources.NotFoundException e) { 5718 resourceName = "0x" + Integer.toHexString(resourceId); 5719 } 5720 attributeMap.put(resourceId, resourceName); 5721 } 5722 5723 attributes[i] = resourceName; 5724 attributes[i + 1] = t.getString(index); 5725 i += 2; 5726 } 5727 5728 // Trim to fit contents. 5729 final String[] trimmed = new String[i]; 5730 System.arraycopy(attributes, 0, trimmed, 0, i); 5731 mAttributes = trimmed; 5732 } 5733 5734 public String toString() { 5735 StringBuilder out = new StringBuilder(128); 5736 out.append(getClass().getName()); 5737 out.append('{'); 5738 out.append(Integer.toHexString(System.identityHashCode(this))); 5739 out.append(' '); 5740 switch (mViewFlags&VISIBILITY_MASK) { 5741 case VISIBLE: out.append('V'); break; 5742 case INVISIBLE: out.append('I'); break; 5743 case GONE: out.append('G'); break; 5744 default: out.append('.'); break; 5745 } 5746 out.append((mViewFlags & FOCUSABLE) == FOCUSABLE ? 'F' : '.'); 5747 out.append((mViewFlags&ENABLED_MASK) == ENABLED ? 'E' : '.'); 5748 out.append((mViewFlags&DRAW_MASK) == WILL_NOT_DRAW ? '.' : 'D'); 5749 out.append((mViewFlags&SCROLLBARS_HORIZONTAL) != 0 ? 'H' : '.'); 5750 out.append((mViewFlags&SCROLLBARS_VERTICAL) != 0 ? 'V' : '.'); 5751 out.append((mViewFlags&CLICKABLE) != 0 ? 'C' : '.'); 5752 out.append((mViewFlags&LONG_CLICKABLE) != 0 ? 'L' : '.'); 5753 out.append((mViewFlags&CONTEXT_CLICKABLE) != 0 ? 'X' : '.'); 5754 out.append(' '); 5755 out.append((mPrivateFlags&PFLAG_IS_ROOT_NAMESPACE) != 0 ? 'R' : '.'); 5756 out.append((mPrivateFlags&PFLAG_FOCUSED) != 0 ? 'F' : '.'); 5757 out.append((mPrivateFlags&PFLAG_SELECTED) != 0 ? 'S' : '.'); 5758 if ((mPrivateFlags&PFLAG_PREPRESSED) != 0) { 5759 out.append('p'); 5760 } else { 5761 out.append((mPrivateFlags&PFLAG_PRESSED) != 0 ? 'P' : '.'); 5762 } 5763 out.append((mPrivateFlags&PFLAG_HOVERED) != 0 ? 'H' : '.'); 5764 out.append((mPrivateFlags&PFLAG_ACTIVATED) != 0 ? 'A' : '.'); 5765 out.append((mPrivateFlags&PFLAG_INVALIDATED) != 0 ? 'I' : '.'); 5766 out.append((mPrivateFlags&PFLAG_DIRTY_MASK) != 0 ? 'D' : '.'); 5767 out.append(' '); 5768 out.append(mLeft); 5769 out.append(','); 5770 out.append(mTop); 5771 out.append('-'); 5772 out.append(mRight); 5773 out.append(','); 5774 out.append(mBottom); 5775 final int id = getId(); 5776 if (id != NO_ID) { 5777 out.append(" #"); 5778 out.append(Integer.toHexString(id)); 5779 final Resources r = mResources; 5780 if (id > 0 && Resources.resourceHasPackage(id) && r != null) { 5781 try { 5782 String pkgname; 5783 switch (id&0xff000000) { 5784 case 0x7f000000: 5785 pkgname="app"; 5786 break; 5787 case 0x01000000: 5788 pkgname="android"; 5789 break; 5790 default: 5791 pkgname = r.getResourcePackageName(id); 5792 break; 5793 } 5794 String typename = r.getResourceTypeName(id); 5795 String entryname = r.getResourceEntryName(id); 5796 out.append(" "); 5797 out.append(pkgname); 5798 out.append(":"); 5799 out.append(typename); 5800 out.append("/"); 5801 out.append(entryname); 5802 } catch (Resources.NotFoundException e) { 5803 } 5804 } 5805 } 5806 out.append("}"); 5807 return out.toString(); 5808 } 5809 5810 /** 5811 * <p> 5812 * Initializes the fading edges from a given set of styled attributes. This 5813 * method should be called by subclasses that need fading edges and when an 5814 * instance of these subclasses is created programmatically rather than 5815 * being inflated from XML. This method is automatically called when the XML 5816 * is inflated. 5817 * </p> 5818 * 5819 * @param a the styled attributes set to initialize the fading edges from 5820 * 5821 * @removed 5822 */ 5823 protected void initializeFadingEdge(TypedArray a) { 5824 // This method probably shouldn't have been included in the SDK to begin with. 5825 // It relies on 'a' having been initialized using an attribute filter array that is 5826 // not publicly available to the SDK. The old method has been renamed 5827 // to initializeFadingEdgeInternal and hidden for framework use only; 5828 // this one initializes using defaults to make it safe to call for apps. 5829 5830 TypedArray arr = mContext.obtainStyledAttributes(com.android.internal.R.styleable.View); 5831 5832 initializeFadingEdgeInternal(arr); 5833 5834 arr.recycle(); 5835 } 5836 5837 /** 5838 * <p> 5839 * Initializes the fading edges from a given set of styled attributes. This 5840 * method should be called by subclasses that need fading edges and when an 5841 * instance of these subclasses is created programmatically rather than 5842 * being inflated from XML. This method is automatically called when the XML 5843 * is inflated. 5844 * </p> 5845 * 5846 * @param a the styled attributes set to initialize the fading edges from 5847 * @hide This is the real method; the public one is shimmed to be safe to call from apps. 5848 */ 5849 protected void initializeFadingEdgeInternal(TypedArray a) { 5850 initScrollCache(); 5851 5852 mScrollCache.fadingEdgeLength = a.getDimensionPixelSize( 5853 R.styleable.View_fadingEdgeLength, 5854 ViewConfiguration.get(mContext).getScaledFadingEdgeLength()); 5855 } 5856 5857 /** 5858 * Returns the size of the vertical faded edges used to indicate that more 5859 * content in this view is visible. 5860 * 5861 * @return The size in pixels of the vertical faded edge or 0 if vertical 5862 * faded edges are not enabled for this view. 5863 * @attr ref android.R.styleable#View_fadingEdgeLength 5864 */ 5865 public int getVerticalFadingEdgeLength() { 5866 if (isVerticalFadingEdgeEnabled()) { 5867 ScrollabilityCache cache = mScrollCache; 5868 if (cache != null) { 5869 return cache.fadingEdgeLength; 5870 } 5871 } 5872 return 0; 5873 } 5874 5875 /** 5876 * Set the size of the faded edge used to indicate that more content in this 5877 * view is available. Will not change whether the fading edge is enabled; use 5878 * {@link #setVerticalFadingEdgeEnabled(boolean)} or 5879 * {@link #setHorizontalFadingEdgeEnabled(boolean)} to enable the fading edge 5880 * for the vertical or horizontal fading edges. 5881 * 5882 * @param length The size in pixels of the faded edge used to indicate that more 5883 * content in this view is visible. 5884 */ 5885 public void setFadingEdgeLength(int length) { 5886 initScrollCache(); 5887 mScrollCache.fadingEdgeLength = length; 5888 } 5889 5890 /** 5891 * Returns the size of the horizontal faded edges used to indicate that more 5892 * content in this view is visible. 5893 * 5894 * @return The size in pixels of the horizontal faded edge or 0 if horizontal 5895 * faded edges are not enabled for this view. 5896 * @attr ref android.R.styleable#View_fadingEdgeLength 5897 */ 5898 public int getHorizontalFadingEdgeLength() { 5899 if (isHorizontalFadingEdgeEnabled()) { 5900 ScrollabilityCache cache = mScrollCache; 5901 if (cache != null) { 5902 return cache.fadingEdgeLength; 5903 } 5904 } 5905 return 0; 5906 } 5907 5908 /** 5909 * Returns the width of the vertical scrollbar. 5910 * 5911 * @return The width in pixels of the vertical scrollbar or 0 if there 5912 * is no vertical scrollbar. 5913 */ 5914 public int getVerticalScrollbarWidth() { 5915 ScrollabilityCache cache = mScrollCache; 5916 if (cache != null) { 5917 ScrollBarDrawable scrollBar = cache.scrollBar; 5918 if (scrollBar != null) { 5919 int size = scrollBar.getSize(true); 5920 if (size <= 0) { 5921 size = cache.scrollBarSize; 5922 } 5923 return size; 5924 } 5925 return 0; 5926 } 5927 return 0; 5928 } 5929 5930 /** 5931 * Returns the height of the horizontal scrollbar. 5932 * 5933 * @return The height in pixels of the horizontal scrollbar or 0 if 5934 * there is no horizontal scrollbar. 5935 */ 5936 protected int getHorizontalScrollbarHeight() { 5937 ScrollabilityCache cache = mScrollCache; 5938 if (cache != null) { 5939 ScrollBarDrawable scrollBar = cache.scrollBar; 5940 if (scrollBar != null) { 5941 int size = scrollBar.getSize(false); 5942 if (size <= 0) { 5943 size = cache.scrollBarSize; 5944 } 5945 return size; 5946 } 5947 return 0; 5948 } 5949 return 0; 5950 } 5951 5952 /** 5953 * <p> 5954 * Initializes the scrollbars from a given set of styled attributes. This 5955 * method should be called by subclasses that need scrollbars and when an 5956 * instance of these subclasses is created programmatically rather than 5957 * being inflated from XML. This method is automatically called when the XML 5958 * is inflated. 5959 * </p> 5960 * 5961 * @param a the styled attributes set to initialize the scrollbars from 5962 * 5963 * @removed 5964 */ 5965 protected void initializeScrollbars(TypedArray a) { 5966 // It's not safe to use this method from apps. The parameter 'a' must have been obtained 5967 // using the View filter array which is not available to the SDK. As such, internal 5968 // framework usage now uses initializeScrollbarsInternal and we grab a default 5969 // TypedArray with the right filter instead here. 5970 TypedArray arr = mContext.obtainStyledAttributes(com.android.internal.R.styleable.View); 5971 5972 initializeScrollbarsInternal(arr); 5973 5974 // We ignored the method parameter. Recycle the one we actually did use. 5975 arr.recycle(); 5976 } 5977 5978 /** 5979 * <p> 5980 * Initializes the scrollbars from a given set of styled attributes. This 5981 * method should be called by subclasses that need scrollbars and when an 5982 * instance of these subclasses is created programmatically rather than 5983 * being inflated from XML. This method is automatically called when the XML 5984 * is inflated. 5985 * </p> 5986 * 5987 * @param a the styled attributes set to initialize the scrollbars from 5988 * @hide 5989 */ 5990 protected void initializeScrollbarsInternal(TypedArray a) { 5991 initScrollCache(); 5992 5993 final ScrollabilityCache scrollabilityCache = mScrollCache; 5994 5995 if (scrollabilityCache.scrollBar == null) { 5996 scrollabilityCache.scrollBar = new ScrollBarDrawable(); 5997 scrollabilityCache.scrollBar.setState(getDrawableState()); 5998 scrollabilityCache.scrollBar.setCallback(this); 5999 } 6000 6001 final boolean fadeScrollbars = a.getBoolean(R.styleable.View_fadeScrollbars, true); 6002 6003 if (!fadeScrollbars) { 6004 scrollabilityCache.state = ScrollabilityCache.ON; 6005 } 6006 scrollabilityCache.fadeScrollBars = fadeScrollbars; 6007 6008 6009 scrollabilityCache.scrollBarFadeDuration = a.getInt( 6010 R.styleable.View_scrollbarFadeDuration, ViewConfiguration 6011 .getScrollBarFadeDuration()); 6012 scrollabilityCache.scrollBarDefaultDelayBeforeFade = a.getInt( 6013 R.styleable.View_scrollbarDefaultDelayBeforeFade, 6014 ViewConfiguration.getScrollDefaultDelay()); 6015 6016 6017 scrollabilityCache.scrollBarSize = a.getDimensionPixelSize( 6018 com.android.internal.R.styleable.View_scrollbarSize, 6019 ViewConfiguration.get(mContext).getScaledScrollBarSize()); 6020 6021 Drawable track = a.getDrawable(R.styleable.View_scrollbarTrackHorizontal); 6022 scrollabilityCache.scrollBar.setHorizontalTrackDrawable(track); 6023 6024 Drawable thumb = a.getDrawable(R.styleable.View_scrollbarThumbHorizontal); 6025 if (thumb != null) { 6026 scrollabilityCache.scrollBar.setHorizontalThumbDrawable(thumb); 6027 } 6028 6029 boolean alwaysDraw = a.getBoolean(R.styleable.View_scrollbarAlwaysDrawHorizontalTrack, 6030 false); 6031 if (alwaysDraw) { 6032 scrollabilityCache.scrollBar.setAlwaysDrawHorizontalTrack(true); 6033 } 6034 6035 track = a.getDrawable(R.styleable.View_scrollbarTrackVertical); 6036 scrollabilityCache.scrollBar.setVerticalTrackDrawable(track); 6037 6038 thumb = a.getDrawable(R.styleable.View_scrollbarThumbVertical); 6039 if (thumb != null) { 6040 scrollabilityCache.scrollBar.setVerticalThumbDrawable(thumb); 6041 } 6042 6043 alwaysDraw = a.getBoolean(R.styleable.View_scrollbarAlwaysDrawVerticalTrack, 6044 false); 6045 if (alwaysDraw) { 6046 scrollabilityCache.scrollBar.setAlwaysDrawVerticalTrack(true); 6047 } 6048 6049 // Apply layout direction to the new Drawables if needed 6050 final int layoutDirection = getLayoutDirection(); 6051 if (track != null) { 6052 track.setLayoutDirection(layoutDirection); 6053 } 6054 if (thumb != null) { 6055 thumb.setLayoutDirection(layoutDirection); 6056 } 6057 6058 // Re-apply user/background padding so that scrollbar(s) get added 6059 resolvePadding(); 6060 } 6061 6062 private void initializeScrollIndicatorsInternal() { 6063 // Some day maybe we'll break this into top/left/start/etc. and let the 6064 // client control it. Until then, you can have any scroll indicator you 6065 // want as long as it's a 1dp foreground-colored rectangle. 6066 if (mScrollIndicatorDrawable == null) { 6067 mScrollIndicatorDrawable = mContext.getDrawable(R.drawable.scroll_indicator_material); 6068 } 6069 } 6070 6071 /** 6072 * <p> 6073 * Initalizes the scrollability cache if necessary. 6074 * </p> 6075 */ 6076 private void initScrollCache() { 6077 if (mScrollCache == null) { 6078 mScrollCache = new ScrollabilityCache(ViewConfiguration.get(mContext), this); 6079 } 6080 } 6081 6082 private ScrollabilityCache getScrollCache() { 6083 initScrollCache(); 6084 return mScrollCache; 6085 } 6086 6087 /** 6088 * Set the position of the vertical scroll bar. Should be one of 6089 * {@link #SCROLLBAR_POSITION_DEFAULT}, {@link #SCROLLBAR_POSITION_LEFT} or 6090 * {@link #SCROLLBAR_POSITION_RIGHT}. 6091 * 6092 * @param position Where the vertical scroll bar should be positioned. 6093 */ 6094 public void setVerticalScrollbarPosition(int position) { 6095 if (mVerticalScrollbarPosition != position) { 6096 mVerticalScrollbarPosition = position; 6097 computeOpaqueFlags(); 6098 resolvePadding(); 6099 } 6100 } 6101 6102 /** 6103 * @return The position where the vertical scroll bar will show, if applicable. 6104 * @see #setVerticalScrollbarPosition(int) 6105 */ 6106 public int getVerticalScrollbarPosition() { 6107 return mVerticalScrollbarPosition; 6108 } 6109 6110 boolean isOnScrollbar(float x, float y) { 6111 if (mScrollCache == null) { 6112 return false; 6113 } 6114 x += getScrollX(); 6115 y += getScrollY(); 6116 if (isVerticalScrollBarEnabled() && !isVerticalScrollBarHidden()) { 6117 final Rect touchBounds = mScrollCache.mScrollBarTouchBounds; 6118 getVerticalScrollBarBounds(null, touchBounds); 6119 if (touchBounds.contains((int) x, (int) y)) { 6120 return true; 6121 } 6122 } 6123 if (isHorizontalScrollBarEnabled()) { 6124 final Rect touchBounds = mScrollCache.mScrollBarTouchBounds; 6125 getHorizontalScrollBarBounds(null, touchBounds); 6126 if (touchBounds.contains((int) x, (int) y)) { 6127 return true; 6128 } 6129 } 6130 return false; 6131 } 6132 6133 boolean isOnScrollbarThumb(float x, float y) { 6134 return isOnVerticalScrollbarThumb(x, y) || isOnHorizontalScrollbarThumb(x, y); 6135 } 6136 6137 private boolean isOnVerticalScrollbarThumb(float x, float y) { 6138 if (mScrollCache == null) { 6139 return false; 6140 } 6141 if (isVerticalScrollBarEnabled() && !isVerticalScrollBarHidden()) { 6142 x += getScrollX(); 6143 y += getScrollY(); 6144 final Rect bounds = mScrollCache.mScrollBarBounds; 6145 final Rect touchBounds = mScrollCache.mScrollBarTouchBounds; 6146 getVerticalScrollBarBounds(bounds, touchBounds); 6147 final int range = computeVerticalScrollRange(); 6148 final int offset = computeVerticalScrollOffset(); 6149 final int extent = computeVerticalScrollExtent(); 6150 final int thumbLength = ScrollBarUtils.getThumbLength(bounds.height(), bounds.width(), 6151 extent, range); 6152 final int thumbOffset = ScrollBarUtils.getThumbOffset(bounds.height(), thumbLength, 6153 extent, range, offset); 6154 final int thumbTop = bounds.top + thumbOffset; 6155 final int adjust = Math.max(mScrollCache.scrollBarMinTouchTarget - thumbLength, 0) / 2; 6156 if (x >= touchBounds.left && x <= touchBounds.right 6157 && y >= thumbTop - adjust && y <= thumbTop + thumbLength + adjust) { 6158 return true; 6159 } 6160 } 6161 return false; 6162 } 6163 6164 private boolean isOnHorizontalScrollbarThumb(float x, float y) { 6165 if (mScrollCache == null) { 6166 return false; 6167 } 6168 if (isHorizontalScrollBarEnabled()) { 6169 x += getScrollX(); 6170 y += getScrollY(); 6171 final Rect bounds = mScrollCache.mScrollBarBounds; 6172 final Rect touchBounds = mScrollCache.mScrollBarTouchBounds; 6173 getHorizontalScrollBarBounds(bounds, touchBounds); 6174 final int range = computeHorizontalScrollRange(); 6175 final int offset = computeHorizontalScrollOffset(); 6176 final int extent = computeHorizontalScrollExtent(); 6177 final int thumbLength = ScrollBarUtils.getThumbLength(bounds.width(), bounds.height(), 6178 extent, range); 6179 final int thumbOffset = ScrollBarUtils.getThumbOffset(bounds.width(), thumbLength, 6180 extent, range, offset); 6181 final int thumbLeft = bounds.left + thumbOffset; 6182 final int adjust = Math.max(mScrollCache.scrollBarMinTouchTarget - thumbLength, 0) / 2; 6183 if (x >= thumbLeft - adjust && x <= thumbLeft + thumbLength + adjust 6184 && y >= touchBounds.top && y <= touchBounds.bottom) { 6185 return true; 6186 } 6187 } 6188 return false; 6189 } 6190 6191 boolean isDraggingScrollBar() { 6192 return mScrollCache != null 6193 && mScrollCache.mScrollBarDraggingState != ScrollabilityCache.NOT_DRAGGING; 6194 } 6195 6196 /** 6197 * Sets the state of all scroll indicators. 6198 * <p> 6199 * See {@link #setScrollIndicators(int, int)} for usage information. 6200 * 6201 * @param indicators a bitmask of indicators that should be enabled, or 6202 * {@code 0} to disable all indicators 6203 * @see #setScrollIndicators(int, int) 6204 * @see #getScrollIndicators() 6205 * @attr ref android.R.styleable#View_scrollIndicators 6206 */ 6207 public void setScrollIndicators(@ScrollIndicators int indicators) { 6208 setScrollIndicators(indicators, 6209 SCROLL_INDICATORS_PFLAG3_MASK >>> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT); 6210 } 6211 6212 /** 6213 * Sets the state of the scroll indicators specified by the mask. To change 6214 * all scroll indicators at once, see {@link #setScrollIndicators(int)}. 6215 * <p> 6216 * When a scroll indicator is enabled, it will be displayed if the view 6217 * can scroll in the direction of the indicator. 6218 * <p> 6219 * Multiple indicator types may be enabled or disabled by passing the 6220 * logical OR of the desired types. If multiple types are specified, they 6221 * will all be set to the same enabled state. 6222 * <p> 6223 * For example, to enable the top scroll indicatorExample: {@code setScrollIndicators 6224 * 6225 * @param indicators the indicator direction, or the logical OR of multiple 6226 * indicator directions. One or more of: 6227 * <ul> 6228 * <li>{@link #SCROLL_INDICATOR_TOP}</li> 6229 * <li>{@link #SCROLL_INDICATOR_BOTTOM}</li> 6230 * <li>{@link #SCROLL_INDICATOR_LEFT}</li> 6231 * <li>{@link #SCROLL_INDICATOR_RIGHT}</li> 6232 * <li>{@link #SCROLL_INDICATOR_START}</li> 6233 * <li>{@link #SCROLL_INDICATOR_END}</li> 6234 * </ul> 6235 * @see #setScrollIndicators(int) 6236 * @see #getScrollIndicators() 6237 * @attr ref android.R.styleable#View_scrollIndicators 6238 */ 6239 public void setScrollIndicators(@ScrollIndicators int indicators, @ScrollIndicators int mask) { 6240 // Shift and sanitize mask. 6241 mask <<= SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 6242 mask &= SCROLL_INDICATORS_PFLAG3_MASK; 6243 6244 // Shift and mask indicators. 6245 indicators <<= SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 6246 indicators &= mask; 6247 6248 // Merge with non-masked flags. 6249 final int updatedFlags = indicators | (mPrivateFlags3 & ~mask); 6250 6251 if (mPrivateFlags3 != updatedFlags) { 6252 mPrivateFlags3 = updatedFlags; 6253 6254 if (indicators != 0) { 6255 initializeScrollIndicatorsInternal(); 6256 } 6257 invalidate(); 6258 } 6259 } 6260 6261 /** 6262 * Returns a bitmask representing the enabled scroll indicators. 6263 * <p> 6264 * For example, if the top and left scroll indicators are enabled and all 6265 * other indicators are disabled, the return value will be 6266 * {@code View.SCROLL_INDICATOR_TOP | View.SCROLL_INDICATOR_LEFT}. 6267 * <p> 6268 * To check whether the bottom scroll indicator is enabled, use the value 6269 * of {@code (getScrollIndicators() & View.SCROLL_INDICATOR_BOTTOM) != 0}. 6270 * 6271 * @return a bitmask representing the enabled scroll indicators 6272 */ 6273 @ScrollIndicators 6274 public int getScrollIndicators() { 6275 return (mPrivateFlags3 & SCROLL_INDICATORS_PFLAG3_MASK) 6276 >>> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 6277 } 6278 6279 ListenerInfo getListenerInfo() { 6280 if (mListenerInfo != null) { 6281 return mListenerInfo; 6282 } 6283 mListenerInfo = new ListenerInfo(); 6284 return mListenerInfo; 6285 } 6286 6287 /** 6288 * Register a callback to be invoked when the scroll X or Y positions of 6289 * this view change. 6290 * <p> 6291 * <b>Note:</b> Some views handle scrolling independently from View and may 6292 * have their own separate listeners for scroll-type events. For example, 6293 * {@link android.widget.ListView ListView} allows clients to register an 6294 * {@link android.widget.ListView#setOnScrollListener(android.widget.AbsListView.OnScrollListener) AbsListView.OnScrollListener} 6295 * to listen for changes in list scroll position. 6296 * 6297 * @param l The listener to notify when the scroll X or Y position changes. 6298 * @see android.view.View#getScrollX() 6299 * @see android.view.View#getScrollY() 6300 */ 6301 public void setOnScrollChangeListener(OnScrollChangeListener l) { 6302 getListenerInfo().mOnScrollChangeListener = l; 6303 } 6304 6305 /** 6306 * Register a callback to be invoked when focus of this view changed. 6307 * 6308 * @param l The callback that will run. 6309 */ 6310 public void setOnFocusChangeListener(OnFocusChangeListener l) { 6311 getListenerInfo().mOnFocusChangeListener = l; 6312 } 6313 6314 /** 6315 * Add a listener that will be called when the bounds of the view change due to 6316 * layout processing. 6317 * 6318 * @param listener The listener that will be called when layout bounds change. 6319 */ 6320 public void addOnLayoutChangeListener(OnLayoutChangeListener listener) { 6321 ListenerInfo li = getListenerInfo(); 6322 if (li.mOnLayoutChangeListeners == null) { 6323 li.mOnLayoutChangeListeners = new ArrayList<OnLayoutChangeListener>(); 6324 } 6325 if (!li.mOnLayoutChangeListeners.contains(listener)) { 6326 li.mOnLayoutChangeListeners.add(listener); 6327 } 6328 } 6329 6330 /** 6331 * Remove a listener for layout changes. 6332 * 6333 * @param listener The listener for layout bounds change. 6334 */ 6335 public void removeOnLayoutChangeListener(OnLayoutChangeListener listener) { 6336 ListenerInfo li = mListenerInfo; 6337 if (li == null || li.mOnLayoutChangeListeners == null) { 6338 return; 6339 } 6340 li.mOnLayoutChangeListeners.remove(listener); 6341 } 6342 6343 /** 6344 * Add a listener for attach state changes. 6345 * 6346 * This listener will be called whenever this view is attached or detached 6347 * from a window. Remove the listener using 6348 * {@link #removeOnAttachStateChangeListener(OnAttachStateChangeListener)}. 6349 * 6350 * @param listener Listener to attach 6351 * @see #removeOnAttachStateChangeListener(OnAttachStateChangeListener) 6352 */ 6353 public void addOnAttachStateChangeListener(OnAttachStateChangeListener listener) { 6354 ListenerInfo li = getListenerInfo(); 6355 if (li.mOnAttachStateChangeListeners == null) { 6356 li.mOnAttachStateChangeListeners 6357 = new CopyOnWriteArrayList<OnAttachStateChangeListener>(); 6358 } 6359 li.mOnAttachStateChangeListeners.add(listener); 6360 } 6361 6362 /** 6363 * Remove a listener for attach state changes. The listener will receive no further 6364 * notification of window attach/detach events. 6365 * 6366 * @param listener Listener to remove 6367 * @see #addOnAttachStateChangeListener(OnAttachStateChangeListener) 6368 */ 6369 public void removeOnAttachStateChangeListener(OnAttachStateChangeListener listener) { 6370 ListenerInfo li = mListenerInfo; 6371 if (li == null || li.mOnAttachStateChangeListeners == null) { 6372 return; 6373 } 6374 li.mOnAttachStateChangeListeners.remove(listener); 6375 } 6376 6377 /** 6378 * Returns the focus-change callback registered for this view. 6379 * 6380 * @return The callback, or null if one is not registered. 6381 */ 6382 public OnFocusChangeListener getOnFocusChangeListener() { 6383 ListenerInfo li = mListenerInfo; 6384 return li != null ? li.mOnFocusChangeListener : null; 6385 } 6386 6387 /** 6388 * Register a callback to be invoked when this view is clicked. If this view is not 6389 * clickable, it becomes clickable. 6390 * 6391 * @param l The callback that will run 6392 * 6393 * @see #setClickable(boolean) 6394 */ 6395 public void setOnClickListener(@Nullable OnClickListener l) { 6396 if (!isClickable()) { 6397 setClickable(true); 6398 } 6399 getListenerInfo().mOnClickListener = l; 6400 } 6401 6402 /** 6403 * Return whether this view has an attached OnClickListener. Returns 6404 * true if there is a listener, false if there is none. 6405 */ 6406 public boolean hasOnClickListeners() { 6407 ListenerInfo li = mListenerInfo; 6408 return (li != null && li.mOnClickListener != null); 6409 } 6410 6411 /** 6412 * Register a callback to be invoked when this view is clicked and held. If this view is not 6413 * long clickable, it becomes long clickable. 6414 * 6415 * @param l The callback that will run 6416 * 6417 * @see #setLongClickable(boolean) 6418 */ 6419 public void setOnLongClickListener(@Nullable OnLongClickListener l) { 6420 if (!isLongClickable()) { 6421 setLongClickable(true); 6422 } 6423 getListenerInfo().mOnLongClickListener = l; 6424 } 6425 6426 /** 6427 * Register a callback to be invoked when this view is context clicked. If the view is not 6428 * context clickable, it becomes context clickable. 6429 * 6430 * @param l The callback that will run 6431 * @see #setContextClickable(boolean) 6432 */ 6433 public void setOnContextClickListener(@Nullable OnContextClickListener l) { 6434 if (!isContextClickable()) { 6435 setContextClickable(true); 6436 } 6437 getListenerInfo().mOnContextClickListener = l; 6438 } 6439 6440 /** 6441 * Register a callback to be invoked when the context menu for this view is 6442 * being built. If this view is not long clickable, it becomes long clickable. 6443 * 6444 * @param l The callback that will run 6445 * 6446 */ 6447 public void setOnCreateContextMenuListener(OnCreateContextMenuListener l) { 6448 if (!isLongClickable()) { 6449 setLongClickable(true); 6450 } 6451 getListenerInfo().mOnCreateContextMenuListener = l; 6452 } 6453 6454 /** 6455 * Set an observer to collect stats for each frame rendered for this view. 6456 * 6457 * @hide 6458 */ 6459 public void addFrameMetricsListener(Window window, 6460 Window.OnFrameMetricsAvailableListener listener, 6461 Handler handler) { 6462 if (mAttachInfo != null) { 6463 if (mAttachInfo.mThreadedRenderer != null) { 6464 if (mFrameMetricsObservers == null) { 6465 mFrameMetricsObservers = new ArrayList<>(); 6466 } 6467 6468 FrameMetricsObserver fmo = new FrameMetricsObserver(window, 6469 handler.getLooper(), listener); 6470 mFrameMetricsObservers.add(fmo); 6471 mAttachInfo.mThreadedRenderer.addFrameMetricsObserver(fmo); 6472 } else { 6473 Log.w(VIEW_LOG_TAG, "View not hardware-accelerated. Unable to observe frame stats"); 6474 } 6475 } else { 6476 if (mFrameMetricsObservers == null) { 6477 mFrameMetricsObservers = new ArrayList<>(); 6478 } 6479 6480 FrameMetricsObserver fmo = new FrameMetricsObserver(window, 6481 handler.getLooper(), listener); 6482 mFrameMetricsObservers.add(fmo); 6483 } 6484 } 6485 6486 /** 6487 * Remove observer configured to collect frame stats for this view. 6488 * 6489 * @hide 6490 */ 6491 public void removeFrameMetricsListener( 6492 Window.OnFrameMetricsAvailableListener listener) { 6493 ThreadedRenderer renderer = getThreadedRenderer(); 6494 FrameMetricsObserver fmo = findFrameMetricsObserver(listener); 6495 if (fmo == null) { 6496 throw new IllegalArgumentException( 6497 "attempt to remove OnFrameMetricsAvailableListener that was never added"); 6498 } 6499 6500 if (mFrameMetricsObservers != null) { 6501 mFrameMetricsObservers.remove(fmo); 6502 if (renderer != null) { 6503 renderer.removeFrameMetricsObserver(fmo); 6504 } 6505 } 6506 } 6507 6508 private void registerPendingFrameMetricsObservers() { 6509 if (mFrameMetricsObservers != null) { 6510 ThreadedRenderer renderer = getThreadedRenderer(); 6511 if (renderer != null) { 6512 for (FrameMetricsObserver fmo : mFrameMetricsObservers) { 6513 renderer.addFrameMetricsObserver(fmo); 6514 } 6515 } else { 6516 Log.w(VIEW_LOG_TAG, "View not hardware-accelerated. Unable to observe frame stats"); 6517 } 6518 } 6519 } 6520 6521 private FrameMetricsObserver findFrameMetricsObserver( 6522 Window.OnFrameMetricsAvailableListener listener) { 6523 for (int i = 0; i < mFrameMetricsObservers.size(); i++) { 6524 FrameMetricsObserver observer = mFrameMetricsObservers.get(i); 6525 if (observer.mListener == listener) { 6526 return observer; 6527 } 6528 } 6529 6530 return null; 6531 } 6532 6533 /** @hide */ 6534 public void setNotifyAutofillManagerOnClick(boolean notify) { 6535 if (notify) { 6536 mPrivateFlags |= PFLAG_NOTIFY_AUTOFILL_MANAGER_ON_CLICK; 6537 } else { 6538 mPrivateFlags &= ~PFLAG_NOTIFY_AUTOFILL_MANAGER_ON_CLICK; 6539 } 6540 } 6541 6542 private void notifyAutofillManagerOnClick() { 6543 if ((mPrivateFlags & PFLAG_NOTIFY_AUTOFILL_MANAGER_ON_CLICK) != 0) { 6544 try { 6545 getAutofillManager().notifyViewClicked(this); 6546 } finally { 6547 // Set it to already called so it's not called twice when called by 6548 // performClickInternal() 6549 mPrivateFlags &= ~PFLAG_NOTIFY_AUTOFILL_MANAGER_ON_CLICK; 6550 } 6551 } 6552 } 6553 6554 /** 6555 * Entry point for {@link #performClick()} - other methods on View should call it instead of 6556 * {@code performClick()} directly to make sure the autofill manager is notified when 6557 * necessary (as subclasses could extend {@code performClick()} without calling the parent's 6558 * method). 6559 */ 6560 private boolean performClickInternal() { 6561 // Must notify autofill manager before performing the click actions to avoid scenarios where 6562 // the app has a click listener that changes the state of views the autofill service might 6563 // be interested on. 6564 notifyAutofillManagerOnClick(); 6565 6566 return performClick(); 6567 } 6568 6569 /** 6570 * Call this view's OnClickListener, if it is defined. Performs all normal 6571 * actions associated with clicking: reporting accessibility event, playing 6572 * a sound, etc. 6573 * 6574 * @return True there was an assigned OnClickListener that was called, false 6575 * otherwise is returned. 6576 */ 6577 // NOTE: other methods on View should not call this method directly, but performClickInternal() 6578 // instead, to guarantee that the autofill manager is notified when necessary (as subclasses 6579 // could extend this method without calling super.performClick()). 6580 public boolean performClick() { 6581 // We still need to call this method to handle the cases where performClick() was called 6582 // externally, instead of through performClickInternal() 6583 notifyAutofillManagerOnClick(); 6584 6585 final boolean result; 6586 final ListenerInfo li = mListenerInfo; 6587 if (li != null && li.mOnClickListener != null) { 6588 playSoundEffect(SoundEffectConstants.CLICK); 6589 li.mOnClickListener.onClick(this); 6590 result = true; 6591 } else { 6592 result = false; 6593 } 6594 6595 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED); 6596 6597 notifyEnterOrExitForAutoFillIfNeeded(true); 6598 6599 return result; 6600 } 6601 6602 /** 6603 * Directly call any attached OnClickListener. Unlike {@link #performClick()}, 6604 * this only calls the listener, and does not do any associated clicking 6605 * actions like reporting an accessibility event. 6606 * 6607 * @return True there was an assigned OnClickListener that was called, false 6608 * otherwise is returned. 6609 */ 6610 public boolean callOnClick() { 6611 ListenerInfo li = mListenerInfo; 6612 if (li != null && li.mOnClickListener != null) { 6613 li.mOnClickListener.onClick(this); 6614 return true; 6615 } 6616 return false; 6617 } 6618 6619 /** 6620 * Calls this view's OnLongClickListener, if it is defined. Invokes the 6621 * context menu if the OnLongClickListener did not consume the event. 6622 * 6623 * @return {@code true} if one of the above receivers consumed the event, 6624 * {@code false} otherwise 6625 */ 6626 public boolean performLongClick() { 6627 return performLongClickInternal(mLongClickX, mLongClickY); 6628 } 6629 6630 /** 6631 * Calls this view's OnLongClickListener, if it is defined. Invokes the 6632 * context menu if the OnLongClickListener did not consume the event, 6633 * anchoring it to an (x,y) coordinate. 6634 * 6635 * @param x x coordinate of the anchoring touch event, or {@link Float#NaN} 6636 * to disable anchoring 6637 * @param y y coordinate of the anchoring touch event, or {@link Float#NaN} 6638 * to disable anchoring 6639 * @return {@code true} if one of the above receivers consumed the event, 6640 * {@code false} otherwise 6641 */ 6642 public boolean performLongClick(float x, float y) { 6643 mLongClickX = x; 6644 mLongClickY = y; 6645 final boolean handled = performLongClick(); 6646 mLongClickX = Float.NaN; 6647 mLongClickY = Float.NaN; 6648 return handled; 6649 } 6650 6651 /** 6652 * Calls this view's OnLongClickListener, if it is defined. Invokes the 6653 * context menu if the OnLongClickListener did not consume the event, 6654 * optionally anchoring it to an (x,y) coordinate. 6655 * 6656 * @param x x coordinate of the anchoring touch event, or {@link Float#NaN} 6657 * to disable anchoring 6658 * @param y y coordinate of the anchoring touch event, or {@link Float#NaN} 6659 * to disable anchoring 6660 * @return {@code true} if one of the above receivers consumed the event, 6661 * {@code false} otherwise 6662 */ 6663 private boolean performLongClickInternal(float x, float y) { 6664 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_LONG_CLICKED); 6665 6666 boolean handled = false; 6667 final ListenerInfo li = mListenerInfo; 6668 if (li != null && li.mOnLongClickListener != null) { 6669 handled = li.mOnLongClickListener.onLongClick(View.this); 6670 } 6671 if (!handled) { 6672 final boolean isAnchored = !Float.isNaN(x) && !Float.isNaN(y); 6673 handled = isAnchored ? showContextMenu(x, y) : showContextMenu(); 6674 } 6675 if ((mViewFlags & TOOLTIP) == TOOLTIP) { 6676 if (!handled) { 6677 handled = showLongClickTooltip((int) x, (int) y); 6678 } 6679 } 6680 if (handled) { 6681 performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); 6682 } 6683 return handled; 6684 } 6685 6686 /** 6687 * Call this view's OnContextClickListener, if it is defined. 6688 * 6689 * @param x the x coordinate of the context click 6690 * @param y the y coordinate of the context click 6691 * @return True if there was an assigned OnContextClickListener that consumed the event, false 6692 * otherwise. 6693 */ 6694 public boolean performContextClick(float x, float y) { 6695 return performContextClick(); 6696 } 6697 6698 /** 6699 * Call this view's OnContextClickListener, if it is defined. 6700 * 6701 * @return True if there was an assigned OnContextClickListener that consumed the event, false 6702 * otherwise. 6703 */ 6704 public boolean performContextClick() { 6705 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CONTEXT_CLICKED); 6706 6707 boolean handled = false; 6708 ListenerInfo li = mListenerInfo; 6709 if (li != null && li.mOnContextClickListener != null) { 6710 handled = li.mOnContextClickListener.onContextClick(View.this); 6711 } 6712 if (handled) { 6713 performHapticFeedback(HapticFeedbackConstants.CONTEXT_CLICK); 6714 } 6715 return handled; 6716 } 6717 6718 /** 6719 * Performs button-related actions during a touch down event. 6720 * 6721 * @param event The event. 6722 * @return True if the down was consumed. 6723 * 6724 * @hide 6725 */ 6726 protected boolean performButtonActionOnTouchDown(MotionEvent event) { 6727 if (event.isFromSource(InputDevice.SOURCE_MOUSE) && 6728 (event.getButtonState() & MotionEvent.BUTTON_SECONDARY) != 0) { 6729 showContextMenu(event.getX(), event.getY()); 6730 mPrivateFlags |= PFLAG_CANCEL_NEXT_UP_EVENT; 6731 return true; 6732 } 6733 return false; 6734 } 6735 6736 /** 6737 * Shows the context menu for this view. 6738 * 6739 * @return {@code true} if the context menu was shown, {@code false} 6740 * otherwise 6741 * @see #showContextMenu(float, float) 6742 */ 6743 public boolean showContextMenu() { 6744 return getParent().showContextMenuForChild(this); 6745 } 6746 6747 /** 6748 * Shows the context menu for this view anchored to the specified 6749 * view-relative coordinate. 6750 * 6751 * @param x the X coordinate in pixels relative to the view to which the 6752 * menu should be anchored, or {@link Float#NaN} to disable anchoring 6753 * @param y the Y coordinate in pixels relative to the view to which the 6754 * menu should be anchored, or {@link Float#NaN} to disable anchoring 6755 * @return {@code true} if the context menu was shown, {@code false} 6756 * otherwise 6757 */ 6758 public boolean showContextMenu(float x, float y) { 6759 return getParent().showContextMenuForChild(this, x, y); 6760 } 6761 6762 /** 6763 * Start an action mode with the default type {@link ActionMode#TYPE_PRIMARY}. 6764 * 6765 * @param callback Callback that will control the lifecycle of the action mode 6766 * @return The new action mode if it is started, null otherwise 6767 * 6768 * @see ActionMode 6769 * @see #startActionMode(android.view.ActionMode.Callback, int) 6770 */ 6771 public ActionMode startActionMode(ActionMode.Callback callback) { 6772 return startActionMode(callback, ActionMode.TYPE_PRIMARY); 6773 } 6774 6775 /** 6776 * Start an action mode with the given type. 6777 * 6778 * @param callback Callback that will control the lifecycle of the action mode 6779 * @param type One of {@link ActionMode#TYPE_PRIMARY} or {@link ActionMode#TYPE_FLOATING}. 6780 * @return The new action mode if it is started, null otherwise 6781 * 6782 * @see ActionMode 6783 */ 6784 public ActionMode startActionMode(ActionMode.Callback callback, int type) { 6785 ViewParent parent = getParent(); 6786 if (parent == null) return null; 6787 try { 6788 return parent.startActionModeForChild(this, callback, type); 6789 } catch (AbstractMethodError ame) { 6790 // Older implementations of custom views might not implement this. 6791 return parent.startActionModeForChild(this, callback); 6792 } 6793 } 6794 6795 /** 6796 * Call {@link Context#startActivityForResult(String, Intent, int, Bundle)} for the View's 6797 * Context, creating a unique View identifier to retrieve the result. 6798 * 6799 * @param intent The Intent to be started. 6800 * @param requestCode The request code to use. 6801 * @hide 6802 */ 6803 public void startActivityForResult(Intent intent, int requestCode) { 6804 mStartActivityRequestWho = "@android:view:" + System.identityHashCode(this); 6805 getContext().startActivityForResult(mStartActivityRequestWho, intent, requestCode, null); 6806 } 6807 6808 /** 6809 * If this View corresponds to the calling who, dispatches the activity result. 6810 * @param who The identifier for the targeted View to receive the result. 6811 * @param requestCode The integer request code originally supplied to 6812 * startActivityForResult(), allowing you to identify who this 6813 * result came from. 6814 * @param resultCode The integer result code returned by the child activity 6815 * through its setResult(). 6816 * @param data An Intent, which can return result data to the caller 6817 * (various data can be attached to Intent "extras"). 6818 * @return {@code true} if the activity result was dispatched. 6819 * @hide 6820 */ 6821 public boolean dispatchActivityResult( 6822 String who, int requestCode, int resultCode, Intent data) { 6823 if (mStartActivityRequestWho != null && mStartActivityRequestWho.equals(who)) { 6824 onActivityResult(requestCode, resultCode, data); 6825 mStartActivityRequestWho = null; 6826 return true; 6827 } 6828 return false; 6829 } 6830 6831 /** 6832 * Receive the result from a previous call to {@link #startActivityForResult(Intent, int)}. 6833 * 6834 * @param requestCode The integer request code originally supplied to 6835 * startActivityForResult(), allowing you to identify who this 6836 * result came from. 6837 * @param resultCode The integer result code returned by the child activity 6838 * through its setResult(). 6839 * @param data An Intent, which can return result data to the caller 6840 * (various data can be attached to Intent "extras"). 6841 * @hide 6842 */ 6843 public void onActivityResult(int requestCode, int resultCode, Intent data) { 6844 // Do nothing. 6845 } 6846 6847 /** 6848 * Register a callback to be invoked when a hardware key is pressed in this view. 6849 * Key presses in software input methods will generally not trigger the methods of 6850 * this listener. 6851 * @param l the key listener to attach to this view 6852 */ 6853 public void setOnKeyListener(OnKeyListener l) { 6854 getListenerInfo().mOnKeyListener = l; 6855 } 6856 6857 /** 6858 * Register a callback to be invoked when a touch event is sent to this view. 6859 * @param l the touch listener to attach to this view 6860 */ 6861 public void setOnTouchListener(OnTouchListener l) { 6862 getListenerInfo().mOnTouchListener = l; 6863 } 6864 6865 /** 6866 * Register a callback to be invoked when a generic motion event is sent to this view. 6867 * @param l the generic motion listener to attach to this view 6868 */ 6869 public void setOnGenericMotionListener(OnGenericMotionListener l) { 6870 getListenerInfo().mOnGenericMotionListener = l; 6871 } 6872 6873 /** 6874 * Register a callback to be invoked when a hover event is sent to this view. 6875 * @param l the hover listener to attach to this view 6876 */ 6877 public void setOnHoverListener(OnHoverListener l) { 6878 getListenerInfo().mOnHoverListener = l; 6879 } 6880 6881 /** 6882 * Register a drag event listener callback object for this View. The parameter is 6883 * an implementation of {@link android.view.View.OnDragListener}. To send a drag event to a 6884 * View, the system calls the 6885 * {@link android.view.View.OnDragListener#onDrag(View,DragEvent)} method. 6886 * @param l An implementation of {@link android.view.View.OnDragListener}. 6887 */ 6888 public void setOnDragListener(OnDragListener l) { 6889 getListenerInfo().mOnDragListener = l; 6890 } 6891 6892 /** 6893 * Give this view focus. This will cause 6894 * {@link #onFocusChanged(boolean, int, android.graphics.Rect)} to be called. 6895 * 6896 * Note: this does not check whether this {@link View} should get focus, it just 6897 * gives it focus no matter what. It should only be called internally by framework 6898 * code that knows what it is doing, namely {@link #requestFocus(int, Rect)}. 6899 * 6900 * @param direction values are {@link View#FOCUS_UP}, {@link View#FOCUS_DOWN}, 6901 * {@link View#FOCUS_LEFT} or {@link View#FOCUS_RIGHT}. This is the direction which 6902 * focus moved when requestFocus() is called. It may not always 6903 * apply, in which case use the default View.FOCUS_DOWN. 6904 * @param previouslyFocusedRect The rectangle of the view that had focus 6905 * prior in this View's coordinate system. 6906 */ 6907 void handleFocusGainInternal(@FocusRealDirection int direction, Rect previouslyFocusedRect) { 6908 if (DBG) { 6909 System.out.println(this + " requestFocus()"); 6910 } 6911 6912 if ((mPrivateFlags & PFLAG_FOCUSED) == 0) { 6913 mPrivateFlags |= PFLAG_FOCUSED; 6914 6915 View oldFocus = (mAttachInfo != null) ? getRootView().findFocus() : null; 6916 6917 if (mParent != null) { 6918 mParent.requestChildFocus(this, this); 6919 updateFocusedInCluster(oldFocus, direction); 6920 } 6921 6922 if (mAttachInfo != null) { 6923 mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(oldFocus, this); 6924 } 6925 6926 onFocusChanged(true, direction, previouslyFocusedRect); 6927 refreshDrawableState(); 6928 } 6929 } 6930 6931 /** 6932 * Sets this view's preference for reveal behavior when it gains focus. 6933 * 6934 * <p>When set to true, this is a signal to ancestor views in the hierarchy that 6935 * this view would prefer to be brought fully into view when it gains focus. 6936 * For example, a text field that a user is meant to type into. Other views such 6937 * as scrolling containers may prefer to opt-out of this behavior.</p> 6938 * 6939 * <p>The default value for views is true, though subclasses may change this 6940 * based on their preferred behavior.</p> 6941 * 6942 * @param revealOnFocus true to request reveal on focus in ancestors, false otherwise 6943 * 6944 * @see #getRevealOnFocusHint() 6945 */ 6946 public final void setRevealOnFocusHint(boolean revealOnFocus) { 6947 if (revealOnFocus) { 6948 mPrivateFlags3 &= ~PFLAG3_NO_REVEAL_ON_FOCUS; 6949 } else { 6950 mPrivateFlags3 |= PFLAG3_NO_REVEAL_ON_FOCUS; 6951 } 6952 } 6953 6954 /** 6955 * Returns this view's preference for reveal behavior when it gains focus. 6956 * 6957 * <p>When this method returns true for a child view requesting focus, ancestor 6958 * views responding to a focus change in {@link ViewParent#requestChildFocus(View, View)} 6959 * should make a best effort to make the newly focused child fully visible to the user. 6960 * When it returns false, ancestor views should preferably not disrupt scroll positioning or 6961 * other properties affecting visibility to the user as part of the focus change.</p> 6962 * 6963 * @return true if this view would prefer to become fully visible when it gains focus, 6964 * false if it would prefer not to disrupt scroll positioning 6965 * 6966 * @see #setRevealOnFocusHint(boolean) 6967 */ 6968 public final boolean getRevealOnFocusHint() { 6969 return (mPrivateFlags3 & PFLAG3_NO_REVEAL_ON_FOCUS) == 0; 6970 } 6971 6972 /** 6973 * Populates <code>outRect</code> with the hotspot bounds. By default, 6974 * the hotspot bounds are identical to the screen bounds. 6975 * 6976 * @param outRect rect to populate with hotspot bounds 6977 * @hide Only for internal use by views and widgets. 6978 */ 6979 public void getHotspotBounds(Rect outRect) { 6980 final Drawable background = getBackground(); 6981 if (background != null) { 6982 background.getHotspotBounds(outRect); 6983 } else { 6984 getBoundsOnScreen(outRect); 6985 } 6986 } 6987 6988 /** 6989 * Request that a rectangle of this view be visible on the screen, 6990 * scrolling if necessary just enough. 6991 * 6992 * <p>A View should call this if it maintains some notion of which part 6993 * of its content is interesting. For example, a text editing view 6994 * should call this when its cursor moves. 6995 * <p>The Rectangle passed into this method should be in the View's content coordinate space. 6996 * It should not be affected by which part of the View is currently visible or its scroll 6997 * position. 6998 * 6999 * @param rectangle The rectangle in the View's content coordinate space 7000 * @return Whether any parent scrolled. 7001 */ 7002 public boolean requestRectangleOnScreen(Rect rectangle) { 7003 return requestRectangleOnScreen(rectangle, false); 7004 } 7005 7006 /** 7007 * Request that a rectangle of this view be visible on the screen, 7008 * scrolling if necessary just enough. 7009 * 7010 * <p>A View should call this if it maintains some notion of which part 7011 * of its content is interesting. For example, a text editing view 7012 * should call this when its cursor moves. 7013 * <p>The Rectangle passed into this method should be in the View's content coordinate space. 7014 * It should not be affected by which part of the View is currently visible or its scroll 7015 * position. 7016 * <p>When <code>immediate</code> is set to true, scrolling will not be 7017 * animated. 7018 * 7019 * @param rectangle The rectangle in the View's content coordinate space 7020 * @param immediate True to forbid animated scrolling, false otherwise 7021 * @return Whether any parent scrolled. 7022 */ 7023 public boolean requestRectangleOnScreen(Rect rectangle, boolean immediate) { 7024 if (mParent == null) { 7025 return false; 7026 } 7027 7028 View child = this; 7029 7030 RectF position = (mAttachInfo != null) ? mAttachInfo.mTmpTransformRect : new RectF(); 7031 position.set(rectangle); 7032 7033 ViewParent parent = mParent; 7034 boolean scrolled = false; 7035 while (parent != null) { 7036 rectangle.set((int) position.left, (int) position.top, 7037 (int) position.right, (int) position.bottom); 7038 7039 scrolled |= parent.requestChildRectangleOnScreen(child, rectangle, immediate); 7040 7041 if (!(parent instanceof View)) { 7042 break; 7043 } 7044 7045 // move it from child's content coordinate space to parent's content coordinate space 7046 position.offset(child.mLeft - child.getScrollX(), child.mTop -child.getScrollY()); 7047 7048 child = (View) parent; 7049 parent = child.getParent(); 7050 } 7051 7052 return scrolled; 7053 } 7054 7055 /** 7056 * Called when this view wants to give up focus. If focus is cleared 7057 * {@link #onFocusChanged(boolean, int, android.graphics.Rect)} is called. 7058 * <p> 7059 * <strong>Note:</strong> When not in touch-mode, the framework will try to give focus 7060 * to the first focusable View from the top after focus is cleared. Hence, if this 7061 * View is the first from the top that can take focus, then all callbacks 7062 * related to clearing focus will be invoked after which the framework will 7063 * give focus to this view. 7064 * </p> 7065 */ 7066 public void clearFocus() { 7067 if (DBG) { 7068 System.out.println(this + " clearFocus()"); 7069 } 7070 7071 final boolean refocus = sAlwaysAssignFocus || !isInTouchMode(); 7072 clearFocusInternal(null, true, refocus); 7073 } 7074 7075 /** 7076 * Clears focus from the view, optionally propagating the change up through 7077 * the parent hierarchy and requesting that the root view place new focus. 7078 * 7079 * @param propagate whether to propagate the change up through the parent 7080 * hierarchy 7081 * @param refocus when propagate is true, specifies whether to request the 7082 * root view place new focus 7083 */ 7084 void clearFocusInternal(View focused, boolean propagate, boolean refocus) { 7085 if ((mPrivateFlags & PFLAG_FOCUSED) != 0) { 7086 mPrivateFlags &= ~PFLAG_FOCUSED; 7087 clearParentsWantFocus(); 7088 7089 if (propagate && mParent != null) { 7090 mParent.clearChildFocus(this); 7091 } 7092 7093 onFocusChanged(false, 0, null); 7094 refreshDrawableState(); 7095 7096 if (propagate && (!refocus || !rootViewRequestFocus())) { 7097 notifyGlobalFocusCleared(this); 7098 } 7099 } 7100 } 7101 7102 void notifyGlobalFocusCleared(View oldFocus) { 7103 if (oldFocus != null && mAttachInfo != null) { 7104 mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(oldFocus, null); 7105 } 7106 } 7107 7108 boolean rootViewRequestFocus() { 7109 final View root = getRootView(); 7110 return root != null && root.requestFocus(); 7111 } 7112 7113 /** 7114 * Called internally by the view system when a new view is getting focus. 7115 * This is what clears the old focus. 7116 * <p> 7117 * <b>NOTE:</b> The parent view's focused child must be updated manually 7118 * after calling this method. Otherwise, the view hierarchy may be left in 7119 * an inconstent state. 7120 */ 7121 void unFocus(View focused) { 7122 if (DBG) { 7123 System.out.println(this + " unFocus()"); 7124 } 7125 7126 clearFocusInternal(focused, false, false); 7127 } 7128 7129 /** 7130 * Returns true if this view has focus itself, or is the ancestor of the 7131 * view that has focus. 7132 * 7133 * @return True if this view has or contains focus, false otherwise. 7134 */ 7135 @ViewDebug.ExportedProperty(category = "focus") 7136 public boolean hasFocus() { 7137 return (mPrivateFlags & PFLAG_FOCUSED) != 0; 7138 } 7139 7140 /** 7141 * Returns true if this view is focusable or if it contains a reachable View 7142 * for which {@link #hasFocusable()} returns {@code true}. A "reachable hasFocusable()" 7143 * is a view whose parents do not block descendants focus. 7144 * Only {@link #VISIBLE} views are considered focusable. 7145 * 7146 * <p>As of {@link Build.VERSION_CODES#O} views that are determined to be focusable 7147 * through {@link #FOCUSABLE_AUTO} will also cause this method to return {@code true}. 7148 * Apps that declare a {@link android.content.pm.ApplicationInfo#targetSdkVersion} of 7149 * earlier than {@link Build.VERSION_CODES#O} will continue to see this method return 7150 * {@code false} for views not explicitly marked as focusable. 7151 * Use {@link #hasExplicitFocusable()} if you require the pre-{@link Build.VERSION_CODES#O} 7152 * behavior.</p> 7153 * 7154 * @return {@code true} if the view is focusable or if the view contains a focusable 7155 * view, {@code false} otherwise 7156 * 7157 * @see ViewGroup#FOCUS_BLOCK_DESCENDANTS 7158 * @see ViewGroup#getTouchscreenBlocksFocus() 7159 * @see #hasExplicitFocusable() 7160 */ 7161 public boolean hasFocusable() { 7162 return hasFocusable(!sHasFocusableExcludeAutoFocusable, false); 7163 } 7164 7165 /** 7166 * Returns true if this view is focusable or if it contains a reachable View 7167 * for which {@link #hasExplicitFocusable()} returns {@code true}. 7168 * A "reachable hasExplicitFocusable()" is a view whose parents do not block descendants focus. 7169 * Only {@link #VISIBLE} views for which {@link #getFocusable()} would return 7170 * {@link #FOCUSABLE} are considered focusable. 7171 * 7172 * <p>This method preserves the pre-{@link Build.VERSION_CODES#O} behavior of 7173 * {@link #hasFocusable()} in that only views explicitly set focusable will cause 7174 * this method to return true. A view set to {@link #FOCUSABLE_AUTO} that resolves 7175 * to focusable will not.</p> 7176 * 7177 * @return {@code true} if the view is focusable or if the view contains a focusable 7178 * view, {@code false} otherwise 7179 * 7180 * @see #hasFocusable() 7181 */ 7182 public boolean hasExplicitFocusable() { 7183 return hasFocusable(false, true); 7184 } 7185 7186 boolean hasFocusable(boolean allowAutoFocus, boolean dispatchExplicit) { 7187 if (!isFocusableInTouchMode()) { 7188 for (ViewParent p = mParent; p instanceof ViewGroup; p = p.getParent()) { 7189 final ViewGroup g = (ViewGroup) p; 7190 if (g.shouldBlockFocusForTouchscreen()) { 7191 return false; 7192 } 7193 } 7194 } 7195 7196 // Invisible, gone, or disabled views are never focusable. 7197 if ((mViewFlags & VISIBILITY_MASK) != VISIBLE 7198 || (mViewFlags & ENABLED_MASK) != ENABLED) { 7199 return false; 7200 } 7201 7202 // Only use effective focusable value when allowed. 7203 if ((allowAutoFocus || getFocusable() != FOCUSABLE_AUTO) && isFocusable()) { 7204 return true; 7205 } 7206 7207 return false; 7208 } 7209 7210 /** 7211 * Called by the view system when the focus state of this view changes. 7212 * When the focus change event is caused by directional navigation, direction 7213 * and previouslyFocusedRect provide insight into where the focus is coming from. 7214 * When overriding, be sure to call up through to the super class so that 7215 * the standard focus handling will occur. 7216 * 7217 * @param gainFocus True if the View has focus; false otherwise. 7218 * @param direction The direction focus has moved when requestFocus() 7219 * is called to give this view focus. Values are 7220 * {@link #FOCUS_UP}, {@link #FOCUS_DOWN}, {@link #FOCUS_LEFT}, 7221 * {@link #FOCUS_RIGHT}, {@link #FOCUS_FORWARD}, or {@link #FOCUS_BACKWARD}. 7222 * It may not always apply, in which case use the default. 7223 * @param previouslyFocusedRect The rectangle, in this view's coordinate 7224 * system, of the previously focused view. If applicable, this will be 7225 * passed in as finer grained information about where the focus is coming 7226 * from (in addition to direction). Will be <code>null</code> otherwise. 7227 */ 7228 @CallSuper 7229 protected void onFocusChanged(boolean gainFocus, @FocusDirection int direction, 7230 @Nullable Rect previouslyFocusedRect) { 7231 if (gainFocus) { 7232 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED); 7233 } else { 7234 notifyViewAccessibilityStateChangedIfNeeded( 7235 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 7236 } 7237 7238 // Here we check whether we still need the default focus highlight, and switch it on/off. 7239 switchDefaultFocusHighlight(); 7240 7241 InputMethodManager imm = InputMethodManager.peekInstance(); 7242 if (!gainFocus) { 7243 if (isPressed()) { 7244 setPressed(false); 7245 } 7246 if (imm != null && mAttachInfo != null && mAttachInfo.mHasWindowFocus) { 7247 imm.focusOut(this); 7248 } 7249 onFocusLost(); 7250 } else if (imm != null && mAttachInfo != null && mAttachInfo.mHasWindowFocus) { 7251 imm.focusIn(this); 7252 } 7253 7254 invalidate(true); 7255 ListenerInfo li = mListenerInfo; 7256 if (li != null && li.mOnFocusChangeListener != null) { 7257 li.mOnFocusChangeListener.onFocusChange(this, gainFocus); 7258 } 7259 7260 if (mAttachInfo != null) { 7261 mAttachInfo.mKeyDispatchState.reset(this); 7262 } 7263 7264 notifyEnterOrExitForAutoFillIfNeeded(gainFocus); 7265 } 7266 7267 /** @hide */ 7268 public void notifyEnterOrExitForAutoFillIfNeeded(boolean enter) { 7269 if (canNotifyAutofillEnterExitEvent()) { 7270 AutofillManager afm = getAutofillManager(); 7271 if (afm != null) { 7272 if (enter && isFocused()) { 7273 // We have not been laid out yet, hence cannot evaluate 7274 // whether this view is visible to the user, we will do 7275 // the evaluation once layout is complete. 7276 if (!isLaidOut()) { 7277 mPrivateFlags3 |= PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT; 7278 } else if (isVisibleToUser()) { 7279 // TODO This is a potential problem that View gets focus before it's visible 7280 // to User. Ideally View should handle the event when isVisibleToUser() 7281 // becomes true where it should issue notifyViewEntered(). 7282 afm.notifyViewEntered(this); 7283 } 7284 } else if (!enter && !isFocused()) { 7285 afm.notifyViewExited(this); 7286 } 7287 } 7288 } 7289 } 7290 7291 /** 7292 * Visually distinct portion of a window with window-like semantics are considered panes for 7293 * accessibility purposes. One example is the content view of a fragment that is replaced. 7294 * In order for accessibility services to understand a pane's window-like behavior, panes 7295 * should have descriptive titles. Views with pane titles produce {@link AccessibilityEvent}s 7296 * when they appear, disappear, or change title. 7297 * 7298 * @param accessibilityPaneTitle The pane's title. Setting to {@code null} indicates that this 7299 * View is not a pane. 7300 * 7301 * {@see AccessibilityNodeInfo#setPaneTitle(CharSequence)} 7302 */ 7303 public void setAccessibilityPaneTitle(@Nullable CharSequence accessibilityPaneTitle) { 7304 if (!TextUtils.equals(accessibilityPaneTitle, mAccessibilityPaneTitle)) { 7305 mAccessibilityPaneTitle = accessibilityPaneTitle; 7306 notifyViewAccessibilityStateChangedIfNeeded( 7307 AccessibilityEvent.CONTENT_CHANGE_TYPE_PANE_TITLE); 7308 } 7309 } 7310 7311 /** 7312 * Get the title of the pane for purposes of accessibility. 7313 * 7314 * @return The current pane title. 7315 * 7316 * {@see #setAccessibilityPaneTitle}. 7317 */ 7318 @Nullable public CharSequence getAccessibilityPaneTitle() { 7319 return mAccessibilityPaneTitle; 7320 } 7321 7322 private boolean isAccessibilityPane() { 7323 return mAccessibilityPaneTitle != null; 7324 } 7325 7326 /** 7327 * Sends an accessibility event of the given type. If accessibility is 7328 * not enabled this method has no effect. The default implementation calls 7329 * {@link #onInitializeAccessibilityEvent(AccessibilityEvent)} first 7330 * to populate information about the event source (this View), then calls 7331 * {@link #dispatchPopulateAccessibilityEvent(AccessibilityEvent)} to 7332 * populate the text content of the event source including its descendants, 7333 * and last calls 7334 * {@link ViewParent#requestSendAccessibilityEvent(View, AccessibilityEvent)} 7335 * on its parent to request sending of the event to interested parties. 7336 * <p> 7337 * If an {@link AccessibilityDelegate} has been specified via calling 7338 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 7339 * {@link AccessibilityDelegate#sendAccessibilityEvent(View, int)} is 7340 * responsible for handling this call. 7341 * </p> 7342 * 7343 * @param eventType The type of the event to send, as defined by several types from 7344 * {@link android.view.accessibility.AccessibilityEvent}, such as 7345 * {@link android.view.accessibility.AccessibilityEvent#TYPE_VIEW_CLICKED} or 7346 * {@link android.view.accessibility.AccessibilityEvent#TYPE_VIEW_HOVER_ENTER}. 7347 * 7348 * @see #onInitializeAccessibilityEvent(AccessibilityEvent) 7349 * @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent) 7350 * @see ViewParent#requestSendAccessibilityEvent(View, AccessibilityEvent) 7351 * @see AccessibilityDelegate 7352 */ 7353 public void sendAccessibilityEvent(int eventType) { 7354 if (mAccessibilityDelegate != null) { 7355 mAccessibilityDelegate.sendAccessibilityEvent(this, eventType); 7356 } else { 7357 sendAccessibilityEventInternal(eventType); 7358 } 7359 } 7360 7361 /** 7362 * Convenience method for sending a {@link AccessibilityEvent#TYPE_ANNOUNCEMENT} 7363 * {@link AccessibilityEvent} to make an announcement which is related to some 7364 * sort of a context change for which none of the events representing UI transitions 7365 * is a good fit. For example, announcing a new page in a book. If accessibility 7366 * is not enabled this method does nothing. 7367 * 7368 * @param text The announcement text. 7369 */ 7370 public void announceForAccessibility(CharSequence text) { 7371 if (AccessibilityManager.getInstance(mContext).isEnabled() && mParent != null) { 7372 AccessibilityEvent event = AccessibilityEvent.obtain( 7373 AccessibilityEvent.TYPE_ANNOUNCEMENT); 7374 onInitializeAccessibilityEvent(event); 7375 event.getText().add(text); 7376 event.setContentDescription(null); 7377 mParent.requestSendAccessibilityEvent(this, event); 7378 } 7379 } 7380 7381 /** 7382 * @see #sendAccessibilityEvent(int) 7383 * 7384 * Note: Called from the default {@link AccessibilityDelegate}. 7385 * 7386 * @hide 7387 */ 7388 public void sendAccessibilityEventInternal(int eventType) { 7389 if (AccessibilityManager.getInstance(mContext).isEnabled()) { 7390 sendAccessibilityEventUnchecked(AccessibilityEvent.obtain(eventType)); 7391 } 7392 } 7393 7394 /** 7395 * This method behaves exactly as {@link #sendAccessibilityEvent(int)} but 7396 * takes as an argument an empty {@link AccessibilityEvent} and does not 7397 * perform a check whether accessibility is enabled. 7398 * <p> 7399 * If an {@link AccessibilityDelegate} has been specified via calling 7400 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 7401 * {@link AccessibilityDelegate#sendAccessibilityEventUnchecked(View, AccessibilityEvent)} 7402 * is responsible for handling this call. 7403 * </p> 7404 * 7405 * @param event The event to send. 7406 * 7407 * @see #sendAccessibilityEvent(int) 7408 */ 7409 public void sendAccessibilityEventUnchecked(AccessibilityEvent event) { 7410 if (mAccessibilityDelegate != null) { 7411 mAccessibilityDelegate.sendAccessibilityEventUnchecked(this, event); 7412 } else { 7413 sendAccessibilityEventUncheckedInternal(event); 7414 } 7415 } 7416 7417 /** 7418 * @see #sendAccessibilityEventUnchecked(AccessibilityEvent) 7419 * 7420 * Note: Called from the default {@link AccessibilityDelegate}. 7421 * 7422 * @hide 7423 */ 7424 public void sendAccessibilityEventUncheckedInternal(AccessibilityEvent event) { 7425 // Panes disappearing are relevant even if though the view is no longer visible. 7426 boolean isWindowStateChanged = 7427 (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED); 7428 boolean isWindowDisappearedEvent = isWindowStateChanged && ((event.getContentChangeTypes() 7429 & AccessibilityEvent.CONTENT_CHANGE_TYPE_PANE_DISAPPEARED) != 0); 7430 if (!isShown() && !isWindowDisappearedEvent) { 7431 return; 7432 } 7433 onInitializeAccessibilityEvent(event); 7434 // Only a subset of accessibility events populates text content. 7435 if ((event.getEventType() & POPULATING_ACCESSIBILITY_EVENT_TYPES) != 0) { 7436 dispatchPopulateAccessibilityEvent(event); 7437 } 7438 // In the beginning we called #isShown(), so we know that getParent() is not null. 7439 ViewParent parent = getParent(); 7440 if (parent != null) { 7441 getParent().requestSendAccessibilityEvent(this, event); 7442 } 7443 } 7444 7445 /** 7446 * Dispatches an {@link AccessibilityEvent} to the {@link View} first and then 7447 * to its children for adding their text content to the event. Note that the 7448 * event text is populated in a separate dispatch path since we add to the 7449 * event not only the text of the source but also the text of all its descendants. 7450 * A typical implementation will call 7451 * {@link #onPopulateAccessibilityEvent(AccessibilityEvent)} on the this view 7452 * and then call the {@link #dispatchPopulateAccessibilityEvent(AccessibilityEvent)} 7453 * on each child. Override this method if custom population of the event text 7454 * content is required. 7455 * <p> 7456 * If an {@link AccessibilityDelegate} has been specified via calling 7457 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 7458 * {@link AccessibilityDelegate#dispatchPopulateAccessibilityEvent(View, AccessibilityEvent)} 7459 * is responsible for handling this call. 7460 * </p> 7461 * <p> 7462 * <em>Note:</em> Accessibility events of certain types are not dispatched for 7463 * populating the event text via this method. For details refer to {@link AccessibilityEvent}. 7464 * </p> 7465 * 7466 * @param event The event. 7467 * 7468 * @return True if the event population was completed. 7469 */ 7470 public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) { 7471 if (mAccessibilityDelegate != null) { 7472 return mAccessibilityDelegate.dispatchPopulateAccessibilityEvent(this, event); 7473 } else { 7474 return dispatchPopulateAccessibilityEventInternal(event); 7475 } 7476 } 7477 7478 /** 7479 * @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent) 7480 * 7481 * Note: Called from the default {@link AccessibilityDelegate}. 7482 * 7483 * @hide 7484 */ 7485 public boolean dispatchPopulateAccessibilityEventInternal(AccessibilityEvent event) { 7486 onPopulateAccessibilityEvent(event); 7487 return false; 7488 } 7489 7490 /** 7491 * Called from {@link #dispatchPopulateAccessibilityEvent(AccessibilityEvent)} 7492 * giving a chance to this View to populate the accessibility event with its 7493 * text content. While this method is free to modify event 7494 * attributes other than text content, doing so should normally be performed in 7495 * {@link #onInitializeAccessibilityEvent(AccessibilityEvent)}. 7496 * <p> 7497 * Example: Adding formatted date string to an accessibility event in addition 7498 * to the text added by the super implementation: 7499 * <pre> public void onPopulateAccessibilityEvent(AccessibilityEvent event) { 7500 * super.onPopulateAccessibilityEvent(event); 7501 * final int flags = DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_WEEKDAY; 7502 * String selectedDateUtterance = DateUtils.formatDateTime(mContext, 7503 * mCurrentDate.getTimeInMillis(), flags); 7504 * event.getText().add(selectedDateUtterance); 7505 * }</pre> 7506 * <p> 7507 * If an {@link AccessibilityDelegate} has been specified via calling 7508 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 7509 * {@link AccessibilityDelegate#onPopulateAccessibilityEvent(View, AccessibilityEvent)} 7510 * is responsible for handling this call. 7511 * </p> 7512 * <p class="note"><strong>Note:</strong> Always call the super implementation before adding 7513 * information to the event, in case the default implementation has basic information to add. 7514 * </p> 7515 * 7516 * @param event The accessibility event which to populate. 7517 * 7518 * @see #sendAccessibilityEvent(int) 7519 * @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent) 7520 */ 7521 @CallSuper 7522 public void onPopulateAccessibilityEvent(AccessibilityEvent event) { 7523 if (mAccessibilityDelegate != null) { 7524 mAccessibilityDelegate.onPopulateAccessibilityEvent(this, event); 7525 } else { 7526 onPopulateAccessibilityEventInternal(event); 7527 } 7528 } 7529 7530 /** 7531 * @see #onPopulateAccessibilityEvent(AccessibilityEvent) 7532 * 7533 * Note: Called from the default {@link AccessibilityDelegate}. 7534 * 7535 * @hide 7536 */ 7537 public void onPopulateAccessibilityEventInternal(AccessibilityEvent event) { 7538 if ((event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) 7539 && !TextUtils.isEmpty(getAccessibilityPaneTitle())) { 7540 event.getText().add(getAccessibilityPaneTitle()); 7541 } 7542 } 7543 7544 /** 7545 * Initializes an {@link AccessibilityEvent} with information about 7546 * this View which is the event source. In other words, the source of 7547 * an accessibility event is the view whose state change triggered firing 7548 * the event. 7549 * <p> 7550 * Example: Setting the password property of an event in addition 7551 * to properties set by the super implementation: 7552 * <pre> public void onInitializeAccessibilityEvent(AccessibilityEvent event) { 7553 * super.onInitializeAccessibilityEvent(event); 7554 * event.setPassword(true); 7555 * }</pre> 7556 * <p> 7557 * If an {@link AccessibilityDelegate} has been specified via calling 7558 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 7559 * {@link AccessibilityDelegate#onInitializeAccessibilityEvent(View, AccessibilityEvent)} 7560 * is responsible for handling this call. 7561 * </p> 7562 * <p class="note"><strong>Note:</strong> Always call the super implementation before adding 7563 * information to the event, in case the default implementation has basic information to add. 7564 * </p> 7565 * @param event The event to initialize. 7566 * 7567 * @see #sendAccessibilityEvent(int) 7568 * @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent) 7569 */ 7570 @CallSuper 7571 public void onInitializeAccessibilityEvent(AccessibilityEvent event) { 7572 if (mAccessibilityDelegate != null) { 7573 mAccessibilityDelegate.onInitializeAccessibilityEvent(this, event); 7574 } else { 7575 onInitializeAccessibilityEventInternal(event); 7576 } 7577 } 7578 7579 /** 7580 * @see #onInitializeAccessibilityEvent(AccessibilityEvent) 7581 * 7582 * Note: Called from the default {@link AccessibilityDelegate}. 7583 * 7584 * @hide 7585 */ 7586 public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) { 7587 event.setSource(this); 7588 event.setClassName(getAccessibilityClassName()); 7589 event.setPackageName(getContext().getPackageName()); 7590 event.setEnabled(isEnabled()); 7591 event.setContentDescription(mContentDescription); 7592 7593 switch (event.getEventType()) { 7594 case AccessibilityEvent.TYPE_VIEW_FOCUSED: { 7595 ArrayList<View> focusablesTempList = (mAttachInfo != null) 7596 ? mAttachInfo.mTempArrayList : new ArrayList<View>(); 7597 getRootView().addFocusables(focusablesTempList, View.FOCUS_FORWARD, FOCUSABLES_ALL); 7598 event.setItemCount(focusablesTempList.size()); 7599 event.setCurrentItemIndex(focusablesTempList.indexOf(this)); 7600 if (mAttachInfo != null) { 7601 focusablesTempList.clear(); 7602 } 7603 } break; 7604 case AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED: { 7605 CharSequence text = getIterableTextForAccessibility(); 7606 if (text != null && text.length() > 0) { 7607 event.setFromIndex(getAccessibilitySelectionStart()); 7608 event.setToIndex(getAccessibilitySelectionEnd()); 7609 event.setItemCount(text.length()); 7610 } 7611 } break; 7612 } 7613 } 7614 7615 /** 7616 * Returns an {@link AccessibilityNodeInfo} representing this view from the 7617 * point of view of an {@link android.accessibilityservice.AccessibilityService}. 7618 * This method is responsible for obtaining an accessibility node info from a 7619 * pool of reusable instances and calling 7620 * {@link #onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} on this view to 7621 * initialize the former. 7622 * <p> 7623 * Note: The client is responsible for recycling the obtained instance by calling 7624 * {@link AccessibilityNodeInfo#recycle()} to minimize object creation. 7625 * </p> 7626 * 7627 * @return A populated {@link AccessibilityNodeInfo}. 7628 * 7629 * @see AccessibilityNodeInfo 7630 */ 7631 public AccessibilityNodeInfo createAccessibilityNodeInfo() { 7632 if (mAccessibilityDelegate != null) { 7633 return mAccessibilityDelegate.createAccessibilityNodeInfo(this); 7634 } else { 7635 return createAccessibilityNodeInfoInternal(); 7636 } 7637 } 7638 7639 /** 7640 * @see #createAccessibilityNodeInfo() 7641 * 7642 * @hide 7643 */ 7644 public AccessibilityNodeInfo createAccessibilityNodeInfoInternal() { 7645 AccessibilityNodeProvider provider = getAccessibilityNodeProvider(); 7646 if (provider != null) { 7647 return provider.createAccessibilityNodeInfo(AccessibilityNodeProvider.HOST_VIEW_ID); 7648 } else { 7649 AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain(this); 7650 onInitializeAccessibilityNodeInfo(info); 7651 return info; 7652 } 7653 } 7654 7655 /** 7656 * Initializes an {@link AccessibilityNodeInfo} with information about this view. 7657 * The base implementation sets: 7658 * <ul> 7659 * <li>{@link AccessibilityNodeInfo#setParent(View)},</li> 7660 * <li>{@link AccessibilityNodeInfo#setBoundsInParent(Rect)},</li> 7661 * <li>{@link AccessibilityNodeInfo#setBoundsInScreen(Rect)},</li> 7662 * <li>{@link AccessibilityNodeInfo#setPackageName(CharSequence)},</li> 7663 * <li>{@link AccessibilityNodeInfo#setClassName(CharSequence)},</li> 7664 * <li>{@link AccessibilityNodeInfo#setContentDescription(CharSequence)},</li> 7665 * <li>{@link AccessibilityNodeInfo#setEnabled(boolean)},</li> 7666 * <li>{@link AccessibilityNodeInfo#setClickable(boolean)},</li> 7667 * <li>{@link AccessibilityNodeInfo#setFocusable(boolean)},</li> 7668 * <li>{@link AccessibilityNodeInfo#setFocused(boolean)},</li> 7669 * <li>{@link AccessibilityNodeInfo#setLongClickable(boolean)},</li> 7670 * <li>{@link AccessibilityNodeInfo#setSelected(boolean)},</li> 7671 * <li>{@link AccessibilityNodeInfo#setContextClickable(boolean)}</li> 7672 * </ul> 7673 * <p> 7674 * Subclasses should override this method, call the super implementation, 7675 * and set additional attributes. 7676 * </p> 7677 * <p> 7678 * If an {@link AccessibilityDelegate} has been specified via calling 7679 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 7680 * {@link AccessibilityDelegate#onInitializeAccessibilityNodeInfo(View, AccessibilityNodeInfo)} 7681 * is responsible for handling this call. 7682 * </p> 7683 * 7684 * @param info The instance to initialize. 7685 */ 7686 @CallSuper 7687 public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { 7688 if (mAccessibilityDelegate != null) { 7689 mAccessibilityDelegate.onInitializeAccessibilityNodeInfo(this, info); 7690 } else { 7691 onInitializeAccessibilityNodeInfoInternal(info); 7692 } 7693 } 7694 7695 /** 7696 * Gets the location of this view in screen coordinates. 7697 * 7698 * @param outRect The output location 7699 * @hide 7700 */ 7701 public void getBoundsOnScreen(Rect outRect) { 7702 getBoundsOnScreen(outRect, false); 7703 } 7704 7705 /** 7706 * Gets the location of this view in screen coordinates. 7707 * 7708 * @param outRect The output location 7709 * @param clipToParent Whether to clip child bounds to the parent ones. 7710 * @hide 7711 */ 7712 public void getBoundsOnScreen(Rect outRect, boolean clipToParent) { 7713 if (mAttachInfo == null) { 7714 return; 7715 } 7716 7717 RectF position = mAttachInfo.mTmpTransformRect; 7718 position.set(0, 0, mRight - mLeft, mBottom - mTop); 7719 mapRectFromViewToScreenCoords(position, clipToParent); 7720 outRect.set(Math.round(position.left), Math.round(position.top), 7721 Math.round(position.right), Math.round(position.bottom)); 7722 } 7723 7724 /** 7725 * Map a rectangle from view-relative coordinates to screen-relative coordinates 7726 * 7727 * @param rect The rectangle to be mapped 7728 * @param clipToParent Whether to clip child bounds to the parent ones. 7729 * @hide 7730 */ 7731 public void mapRectFromViewToScreenCoords(RectF rect, boolean clipToParent) { 7732 if (!hasIdentityMatrix()) { 7733 getMatrix().mapRect(rect); 7734 } 7735 7736 rect.offset(mLeft, mTop); 7737 7738 ViewParent parent = mParent; 7739 while (parent instanceof View) { 7740 View parentView = (View) parent; 7741 7742 rect.offset(-parentView.mScrollX, -parentView.mScrollY); 7743 7744 if (clipToParent) { 7745 rect.left = Math.max(rect.left, 0); 7746 rect.top = Math.max(rect.top, 0); 7747 rect.right = Math.min(rect.right, parentView.getWidth()); 7748 rect.bottom = Math.min(rect.bottom, parentView.getHeight()); 7749 } 7750 7751 if (!parentView.hasIdentityMatrix()) { 7752 parentView.getMatrix().mapRect(rect); 7753 } 7754 7755 rect.offset(parentView.mLeft, parentView.mTop); 7756 7757 parent = parentView.mParent; 7758 } 7759 7760 if (parent instanceof ViewRootImpl) { 7761 ViewRootImpl viewRootImpl = (ViewRootImpl) parent; 7762 rect.offset(0, -viewRootImpl.mCurScrollY); 7763 } 7764 7765 rect.offset(mAttachInfo.mWindowLeft, mAttachInfo.mWindowTop); 7766 } 7767 7768 /** 7769 * Return the class name of this object to be used for accessibility purposes. 7770 * Subclasses should only override this if they are implementing something that 7771 * should be seen as a completely new class of view when used by accessibility, 7772 * unrelated to the class it is deriving from. This is used to fill in 7773 * {@link AccessibilityNodeInfo#setClassName AccessibilityNodeInfo.setClassName}. 7774 */ 7775 public CharSequence getAccessibilityClassName() { 7776 return View.class.getName(); 7777 } 7778 7779 /** 7780 * Called when assist structure is being retrieved from a view as part of 7781 * {@link android.app.Activity#onProvideAssistData Activity.onProvideAssistData}. 7782 * @param structure Fill in with structured view data. The default implementation 7783 * fills in all data that can be inferred from the view itself. 7784 */ 7785 public void onProvideStructure(ViewStructure structure) { 7786 onProvideStructureForAssistOrAutofill(structure, false, 0); 7787 } 7788 7789 /** 7790 * Populates a {@link ViewStructure} to fullfil an autofill request. 7791 * 7792 * <p>The structure should contain at least the following properties: 7793 * <ul> 7794 * <li>Autofill id ({@link ViewStructure#setAutofillId(AutofillId, int)}). 7795 * <li>Autofill type ({@link ViewStructure#setAutofillType(int)}). 7796 * <li>Autofill value ({@link ViewStructure#setAutofillValue(AutofillValue)}). 7797 * <li>Whether the data is sensitive ({@link ViewStructure#setDataIsSensitive(boolean)}). 7798 * </ul> 7799 * 7800 * <p>It's also recommended to set the following properties - the more properties the structure 7801 * has, the higher the changes of an {@link android.service.autofill.AutofillService} properly 7802 * using the structure: 7803 * 7804 * <ul> 7805 * <li>Autofill hints ({@link ViewStructure#setAutofillHints(String[])}). 7806 * <li>Autofill options ({@link ViewStructure#setAutofillOptions(CharSequence[])}) when the 7807 * view can only be filled with predefined values (typically used when the autofill type 7808 * is {@link #AUTOFILL_TYPE_LIST}). 7809 * <li>Resource id ({@link ViewStructure#setId(int, String, String, String)}). 7810 * <li>Class name ({@link ViewStructure#setClassName(String)}). 7811 * <li>Content description ({@link ViewStructure#setContentDescription(CharSequence)}). 7812 * <li>Visual properties such as visibility ({@link ViewStructure#setVisibility(int)}), 7813 * dimensions ({@link ViewStructure#setDimens(int, int, int, int, int, int)}), and 7814 * opacity ({@link ViewStructure#setOpaque(boolean)}). 7815 * <li>For views representing text fields, text properties such as the text itself 7816 * ({@link ViewStructure#setText(CharSequence)}), text hints 7817 * ({@link ViewStructure#setHint(CharSequence)}, input type 7818 * ({@link ViewStructure#setInputType(int)}), 7819 * <li>For views representing HTML nodes, its web domain 7820 * ({@link ViewStructure#setWebDomain(String)}) and HTML properties 7821 * (({@link ViewStructure#setHtmlInfo(android.view.ViewStructure.HtmlInfo)}). 7822 * </ul> 7823 * 7824 * <p>The default implementation of this method already sets most of these properties based on 7825 * related {@link View} methods (for example, the autofill id is set using 7826 * {@link #getAutofillId()}, the autofill type set using {@link #getAutofillType()}, etc.), 7827 * and views in the standard Android widgets library also override it to set their 7828 * relevant properties (for example, {@link android.widget.TextView} already sets the text 7829 * properties), so it's recommended to only override this method 7830 * (and call {@code super.onProvideAutofillStructure()}) when: 7831 * 7832 * <ul> 7833 * <li>The view contents does not include PII (Personally Identifiable Information), so it 7834 * can call {@link ViewStructure#setDataIsSensitive(boolean)} passing {@code false}. 7835 * <li>The view can only be autofilled with predefined options, so it can call 7836 * {@link ViewStructure#setAutofillOptions(CharSequence[])}. 7837 * </ul> 7838 * 7839 * <p><b>Note:</b> The {@code left} and {@code top} values set in 7840 * {@link ViewStructure#setDimens(int, int, int, int, int, int)} must be relative to the next 7841 * {@link ViewGroup#isImportantForAutofill()} predecessor view included in the structure. 7842 * 7843 * <p>Views support the Autofill Framework mainly by: 7844 * <ul> 7845 * <li>Providing the metadata defining what the view means and how it can be autofilled. 7846 * <li>Notifying the Android System when the view value changed by calling 7847 * {@link AutofillManager#notifyValueChanged(View)}. 7848 * <li>Implementing the methods that autofill the view. 7849 * </ul> 7850 * <p>This method is responsible for the former; {@link #autofill(AutofillValue)} is responsible 7851 * for the latter. 7852 * 7853 * @param structure fill in with structured view data for autofill purposes. 7854 * @param flags optional flags. 7855 * 7856 * @see #AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS 7857 */ 7858 public void onProvideAutofillStructure(ViewStructure structure, @AutofillFlags int flags) { 7859 onProvideStructureForAssistOrAutofill(structure, true, flags); 7860 } 7861 7862 private void onProvideStructureForAssistOrAutofill(ViewStructure structure, 7863 boolean forAutofill, @AutofillFlags int flags) { 7864 final int id = mID; 7865 if (id != NO_ID && !isViewIdGenerated(id)) { 7866 String pkg, type, entry; 7867 try { 7868 final Resources res = getResources(); 7869 entry = res.getResourceEntryName(id); 7870 type = res.getResourceTypeName(id); 7871 pkg = res.getResourcePackageName(id); 7872 } catch (Resources.NotFoundException e) { 7873 entry = type = pkg = null; 7874 } 7875 structure.setId(id, pkg, type, entry); 7876 } else { 7877 structure.setId(id, null, null, null); 7878 } 7879 7880 if (forAutofill) { 7881 final @AutofillType int autofillType = getAutofillType(); 7882 // Don't need to fill autofill info if view does not support it. 7883 // For example, only TextViews that are editable support autofill 7884 if (autofillType != AUTOFILL_TYPE_NONE) { 7885 structure.setAutofillType(autofillType); 7886 structure.setAutofillHints(getAutofillHints()); 7887 structure.setAutofillValue(getAutofillValue()); 7888 } 7889 structure.setImportantForAutofill(getImportantForAutofill()); 7890 } 7891 7892 int ignoredParentLeft = 0; 7893 int ignoredParentTop = 0; 7894 if (forAutofill && (flags & AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS) == 0) { 7895 View parentGroup = null; 7896 7897 ViewParent viewParent = getParent(); 7898 if (viewParent instanceof View) { 7899 parentGroup = (View) viewParent; 7900 } 7901 7902 while (parentGroup != null && !parentGroup.isImportantForAutofill()) { 7903 ignoredParentLeft += parentGroup.mLeft; 7904 ignoredParentTop += parentGroup.mTop; 7905 7906 viewParent = parentGroup.getParent(); 7907 if (viewParent instanceof View) { 7908 parentGroup = (View) viewParent; 7909 } else { 7910 break; 7911 } 7912 } 7913 } 7914 7915 structure.setDimens(ignoredParentLeft + mLeft, ignoredParentTop + mTop, mScrollX, mScrollY, 7916 mRight - mLeft, mBottom - mTop); 7917 if (!forAutofill) { 7918 if (!hasIdentityMatrix()) { 7919 structure.setTransformation(getMatrix()); 7920 } 7921 structure.setElevation(getZ()); 7922 } 7923 structure.setVisibility(getVisibility()); 7924 structure.setEnabled(isEnabled()); 7925 if (isClickable()) { 7926 structure.setClickable(true); 7927 } 7928 if (isFocusable()) { 7929 structure.setFocusable(true); 7930 } 7931 if (isFocused()) { 7932 structure.setFocused(true); 7933 } 7934 if (isAccessibilityFocused()) { 7935 structure.setAccessibilityFocused(true); 7936 } 7937 if (isSelected()) { 7938 structure.setSelected(true); 7939 } 7940 if (isActivated()) { 7941 structure.setActivated(true); 7942 } 7943 if (isLongClickable()) { 7944 structure.setLongClickable(true); 7945 } 7946 if (this instanceof Checkable) { 7947 structure.setCheckable(true); 7948 if (((Checkable)this).isChecked()) { 7949 structure.setChecked(true); 7950 } 7951 } 7952 if (isOpaque()) { 7953 structure.setOpaque(true); 7954 } 7955 if (isContextClickable()) { 7956 structure.setContextClickable(true); 7957 } 7958 structure.setClassName(getAccessibilityClassName().toString()); 7959 structure.setContentDescription(getContentDescription()); 7960 } 7961 7962 /** 7963 * Called when assist structure is being retrieved from a view as part of 7964 * {@link android.app.Activity#onProvideAssistData Activity.onProvideAssistData} to 7965 * generate additional virtual structure under this view. The defaullt implementation 7966 * uses {@link #getAccessibilityNodeProvider()} to try to generate this from the 7967 * view's virtual accessibility nodes, if any. You can override this for a more 7968 * optimal implementation providing this data. 7969 */ 7970 public void onProvideVirtualStructure(ViewStructure structure) { 7971 onProvideVirtualStructureCompat(structure, false); 7972 } 7973 7974 /** 7975 * Fallback implementation to populate a ViewStructure from accessibility state. 7976 * 7977 * @param structure The structure to populate. 7978 * @param forAutofill Whether the structure is needed for autofill. 7979 */ 7980 private void onProvideVirtualStructureCompat(ViewStructure structure, boolean forAutofill) { 7981 final AccessibilityNodeProvider provider = getAccessibilityNodeProvider(); 7982 if (provider != null) { 7983 if (android.view.autofill.Helper.sVerbose && forAutofill) { 7984 Log.v(VIEW_LOG_TAG, "onProvideVirtualStructureCompat() for " + this); 7985 } 7986 7987 final AccessibilityNodeInfo info = createAccessibilityNodeInfo(); 7988 structure.setChildCount(1); 7989 final ViewStructure root = structure.newChild(0); 7990 populateVirtualStructure(root, provider, info, forAutofill); 7991 info.recycle(); 7992 } 7993 } 7994 7995 /** 7996 * Populates a {@link ViewStructure} containing virtual children to fullfil an autofill 7997 * request. 7998 * 7999 * <p>This method should be used when the view manages a virtual structure under this view. For 8000 * example, a view that draws input fields using {@link #draw(Canvas)}. 8001 * 8002 * <p>When implementing this method, subclasses must follow the rules below: 8003 * 8004 * <ul> 8005 * <li>Add virtual children by calling the {@link ViewStructure#newChild(int)} or 8006 * {@link ViewStructure#asyncNewChild(int)} methods, where the {@code id} is an unique id 8007 * identifying the children in the virtual structure. 8008 * <li>The children hierarchy can have multiple levels if necessary, but ideally it should 8009 * exclude intermediate levels that are irrelevant for autofill; that would improve the 8010 * autofill performance. 8011 * <li>Also implement {@link #autofill(SparseArray)} to autofill the virtual 8012 * children. 8013 * <li>Set the autofill properties of the child structure as defined by 8014 * {@link #onProvideAutofillStructure(ViewStructure, int)}, using 8015 * {@link ViewStructure#setAutofillId(AutofillId, int)} to set its autofill id. 8016 * <li>Call {@link android.view.autofill.AutofillManager#notifyViewEntered(View, int, Rect)} 8017 * and/or {@link android.view.autofill.AutofillManager#notifyViewExited(View, int)} 8018 * when the focused virtual child changed. 8019 * <li>Override {@link #isVisibleToUserForAutofill(int)} to allow the platform to query 8020 * whether a given virtual view is visible to the user in order to support triggering 8021 * save when all views of interest go away. 8022 * <li>Call 8023 * {@link android.view.autofill.AutofillManager#notifyValueChanged(View, int, AutofillValue)} 8024 * when the value of a virtual child changed. 8025 * <li>Call {@link 8026 * android.view.autofill.AutofillManager#notifyViewVisibilityChanged(View, int, boolean)} 8027 * when the visibility of a virtual child changed. 8028 * <li>Call 8029 * {@link android.view.autofill.AutofillManager#notifyViewClicked(View, int)} when a virtual 8030 * child is clicked. 8031 * <li>Call {@link AutofillManager#commit()} when the autofill context of the view structure 8032 * changed and the current context should be committed (for example, when the user tapped 8033 * a {@code SUBMIT} button in an HTML page). 8034 * <li>Call {@link AutofillManager#cancel()} when the autofill context of the view structure 8035 * changed and the current context should be canceled (for example, when the user tapped 8036 * a {@code CANCEL} button in an HTML page). 8037 * <li>Provide ways for users to manually request autofill by calling 8038 * {@link AutofillManager#requestAutofill(View, int, Rect)}. 8039 * <li>The {@code left} and {@code top} values set in 8040 * {@link ViewStructure#setDimens(int, int, int, int, int, int)} must be relative to the 8041 * next {@link ViewGroup#isImportantForAutofill()} predecessor view included in the 8042 * structure. 8043 * </ul> 8044 * 8045 * <p>Views with virtual children support the Autofill Framework mainly by: 8046 * <ul> 8047 * <li>Providing the metadata defining what the virtual children mean and how they can be 8048 * autofilled. 8049 * <li>Implementing the methods that autofill the virtual children. 8050 * </ul> 8051 * <p>This method is responsible for the former; {@link #autofill(SparseArray)} is responsible 8052 * for the latter. 8053 * 8054 * @param structure fill in with virtual children data for autofill purposes. 8055 * @param flags optional flags. 8056 * 8057 * @see #AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS 8058 */ 8059 public void onProvideAutofillVirtualStructure(ViewStructure structure, int flags) { 8060 if (mContext.isAutofillCompatibilityEnabled()) { 8061 onProvideVirtualStructureCompat(structure, true); 8062 } 8063 } 8064 8065 /** 8066 * Automatically fills the content of this view with the {@code value}. 8067 * 8068 * <p>Views support the Autofill Framework mainly by: 8069 * <ul> 8070 * <li>Providing the metadata defining what the view means and how it can be autofilled. 8071 * <li>Implementing the methods that autofill the view. 8072 * </ul> 8073 * <p>{@link #onProvideAutofillStructure(ViewStructure, int)} is responsible for the former, 8074 * this method is responsible for latter. 8075 * 8076 * <p>This method does nothing by default, but when overridden it typically: 8077 * <ol> 8078 * <li>Checks if the provided value matches the expected type (which is defined by 8079 * {@link #getAutofillType()}). 8080 * <li>Checks if the view is editable - if it isn't, it should return right away. 8081 * <li>Call the proper getter method on {@link AutofillValue} to fetch the actual value. 8082 * <li>Pass the actual value to the equivalent setter in the view. 8083 * </ol> 8084 * 8085 * <p>For example, a text-field view could implement the method this way: 8086 * 8087 * <pre class="prettyprint"> 8088 * @Override 8089 * public void autofill(AutofillValue value) { 8090 * if (!value.isText() || !this.isEditable()) { 8091 * return; 8092 * } 8093 * CharSequence text = value.getTextValue(); 8094 * if (text != null) { 8095 * this.setText(text); 8096 * } 8097 * } 8098 * </pre> 8099 * 8100 * <p>If the value is updated asynchronously, the next call to 8101 * {@link AutofillManager#notifyValueChanged(View)} must happen <b>after</b> the value was 8102 * changed to the autofilled value. If not, the view will not be considered autofilled. 8103 * 8104 * <p><b>Note:</b> After this method is called, the value returned by 8105 * {@link #getAutofillValue()} must be equal to the {@code value} passed to it, otherwise the 8106 * view will not be highlighted as autofilled. 8107 * 8108 * @param value value to be autofilled. 8109 */ 8110 public void autofill(@SuppressWarnings("unused") AutofillValue value) { 8111 } 8112 8113 /** 8114 * Automatically fills the content of the virtual children within this view. 8115 * 8116 * <p>Views with virtual children support the Autofill Framework mainly by: 8117 * <ul> 8118 * <li>Providing the metadata defining what the virtual children mean and how they can be 8119 * autofilled. 8120 * <li>Implementing the methods that autofill the virtual children. 8121 * </ul> 8122 * <p>{@link #onProvideAutofillVirtualStructure(ViewStructure, int)} is responsible for the 8123 * former, this method is responsible for the latter - see {@link #autofill(AutofillValue)} and 8124 * {@link #onProvideAutofillVirtualStructure(ViewStructure, int)} for more info about autofill. 8125 * 8126 * <p>If a child value is updated asynchronously, the next call to 8127 * {@link AutofillManager#notifyValueChanged(View, int, AutofillValue)} must happen 8128 * <b>after</b> the value was changed to the autofilled value. If not, the child will not be 8129 * considered autofilled. 8130 * 8131 * <p><b>Note:</b> To indicate that a virtual view was autofilled, 8132 * <code>?android:attr/autofilledHighlight</code> should be drawn over it until the data 8133 * changes. 8134 * 8135 * @param values map of values to be autofilled, keyed by virtual child id. 8136 * 8137 * @attr ref android.R.styleable#Theme_autofilledHighlight 8138 */ 8139 public void autofill(@NonNull @SuppressWarnings("unused") SparseArray<AutofillValue> values) { 8140 if (!mContext.isAutofillCompatibilityEnabled()) { 8141 return; 8142 } 8143 final AccessibilityNodeProvider provider = getAccessibilityNodeProvider(); 8144 if (provider == null) { 8145 return; 8146 } 8147 final int valueCount = values.size(); 8148 for (int i = 0; i < valueCount; i++) { 8149 final AutofillValue value = values.valueAt(i); 8150 if (value.isText()) { 8151 final int virtualId = values.keyAt(i); 8152 final CharSequence text = value.getTextValue(); 8153 final Bundle arguments = new Bundle(); 8154 arguments.putCharSequence( 8155 AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE, text); 8156 provider.performAction(virtualId, AccessibilityNodeInfo.ACTION_SET_TEXT, arguments); 8157 } 8158 } 8159 } 8160 8161 /** 8162 * Gets the unique, logical identifier of this view in the activity, for autofill purposes. 8163 * 8164 * <p>The autofill id is created on demand, unless it is explicitly set by 8165 * {@link #setAutofillId(AutofillId)}. 8166 * 8167 * <p>See {@link #setAutofillId(AutofillId)} for more info. 8168 * 8169 * @return The View's autofill id. 8170 */ 8171 public final AutofillId getAutofillId() { 8172 if (mAutofillId == null) { 8173 // The autofill id needs to be unique, but its value doesn't matter, 8174 // so it's better to reuse the accessibility id to save space. 8175 mAutofillId = new AutofillId(getAutofillViewId()); 8176 } 8177 return mAutofillId; 8178 } 8179 8180 /** 8181 * Sets the unique, logical identifier of this view in the activity, for autofill purposes. 8182 * 8183 * <p>The autofill id is created on demand, and this method should only be called when a view is 8184 * reused after {@link #dispatchProvideAutofillStructure(ViewStructure, int)} is called, as 8185 * that method creates a snapshot of the view that is passed along to the autofill service. 8186 * 8187 * <p>This method is typically used when view subtrees are recycled to represent different 8188 * content* —in this case, the autofill id can be saved before the view content is swapped 8189 * out, and restored later when it's swapped back in. For example: 8190 * 8191 * <pre> 8192 * EditText reusableView = ...; 8193 * ViewGroup parentView = ...; 8194 * AutofillManager afm = ...; 8195 * 8196 * // Swap out the view and change its contents 8197 * AutofillId oldId = reusableView.getAutofillId(); 8198 * CharSequence oldText = reusableView.getText(); 8199 * parentView.removeView(reusableView); 8200 * AutofillId newId = afm.getNextAutofillId(); 8201 * reusableView.setText("New I am"); 8202 * reusableView.setAutofillId(newId); 8203 * parentView.addView(reusableView); 8204 * 8205 * // Later, swap the old content back in 8206 * parentView.removeView(reusableView); 8207 * reusableView.setAutofillId(oldId); 8208 * reusableView.setText(oldText); 8209 * parentView.addView(reusableView); 8210 * </pre> 8211 * 8212 * @param id an autofill ID that is unique in the {@link android.app.Activity} hosting the view, 8213 * or {@code null} to reset it. Usually it's an id previously allocated to another view (and 8214 * obtained through {@link #getAutofillId()}), or a new value obtained through 8215 * {@link AutofillManager#getNextAutofillId()}. 8216 * 8217 * @throws IllegalStateException if the view is already {@link #isAttachedToWindow() attached to 8218 * a window}. 8219 * 8220 * @throws IllegalArgumentException if the id is an autofill id associated with a virtual view. 8221 */ 8222 public void setAutofillId(@Nullable AutofillId id) { 8223 // TODO(b/37566627): add unit / CTS test for all possible combinations below 8224 if (android.view.autofill.Helper.sVerbose) { 8225 Log.v(VIEW_LOG_TAG, "setAutofill(): from " + mAutofillId + " to " + id); 8226 } 8227 if (isAttachedToWindow()) { 8228 throw new IllegalStateException("Cannot set autofill id when view is attached"); 8229 } 8230 if (id != null && id.isVirtual()) { 8231 throw new IllegalStateException("Cannot set autofill id assigned to virtual views"); 8232 } 8233 if (id == null && (mPrivateFlags3 & PFLAG3_AUTOFILLID_EXPLICITLY_SET) == 0) { 8234 // Ignore reset because it was never explicitly set before. 8235 return; 8236 } 8237 mAutofillId = id; 8238 if (id != null) { 8239 mAutofillViewId = id.getViewId(); 8240 mPrivateFlags3 |= PFLAG3_AUTOFILLID_EXPLICITLY_SET; 8241 } else { 8242 mAutofillViewId = NO_ID; 8243 mPrivateFlags3 &= ~PFLAG3_AUTOFILLID_EXPLICITLY_SET; 8244 } 8245 } 8246 8247 /** 8248 * Describes the autofill type of this view, so an 8249 * {@link android.service.autofill.AutofillService} can create the proper {@link AutofillValue} 8250 * when autofilling the view. 8251 * 8252 * <p>By default returns {@link #AUTOFILL_TYPE_NONE}, but views should override it to properly 8253 * support the Autofill Framework. 8254 * 8255 * @return either {@link #AUTOFILL_TYPE_NONE}, {@link #AUTOFILL_TYPE_TEXT}, 8256 * {@link #AUTOFILL_TYPE_LIST}, {@link #AUTOFILL_TYPE_DATE}, or {@link #AUTOFILL_TYPE_TOGGLE}. 8257 * 8258 * @see #onProvideAutofillStructure(ViewStructure, int) 8259 * @see #autofill(AutofillValue) 8260 */ 8261 public @AutofillType int getAutofillType() { 8262 return AUTOFILL_TYPE_NONE; 8263 } 8264 8265 /** 8266 * Gets the hints that help an {@link android.service.autofill.AutofillService} determine how 8267 * to autofill the view with the user's data. 8268 * 8269 * <p>See {@link #setAutofillHints(String...)} for more info about these hints. 8270 * 8271 * @return The hints set via the attribute or {@link #setAutofillHints(String...)}, or 8272 * {@code null} if no hints were set. 8273 * 8274 * @attr ref android.R.styleable#View_autofillHints 8275 */ 8276 @ViewDebug.ExportedProperty() 8277 @Nullable public String[] getAutofillHints() { 8278 return mAutofillHints; 8279 } 8280 8281 /** 8282 * @hide 8283 */ 8284 public boolean isAutofilled() { 8285 return (mPrivateFlags3 & PFLAG3_IS_AUTOFILLED) != 0; 8286 } 8287 8288 /** 8289 * Gets the {@link View}'s current autofill value. 8290 * 8291 * <p>By default returns {@code null}, but subclasses should override it and return an 8292 * appropriate value to properly support the Autofill Framework. 8293 * 8294 * @see #onProvideAutofillStructure(ViewStructure, int) 8295 * @see #autofill(AutofillValue) 8296 */ 8297 @Nullable 8298 public AutofillValue getAutofillValue() { 8299 return null; 8300 } 8301 8302 /** 8303 * Gets the mode for determining whether this view is important for autofill. 8304 * 8305 * <p>See {@link #setImportantForAutofill(int)} and {@link #isImportantForAutofill()} for more 8306 * info about this mode. 8307 * 8308 * @return {@link #IMPORTANT_FOR_AUTOFILL_AUTO} by default, or value passed to 8309 * {@link #setImportantForAutofill(int)}. 8310 * 8311 * @attr ref android.R.styleable#View_importantForAutofill 8312 */ 8313 @ViewDebug.ExportedProperty(mapping = { 8314 @ViewDebug.IntToString(from = IMPORTANT_FOR_AUTOFILL_AUTO, to = "auto"), 8315 @ViewDebug.IntToString(from = IMPORTANT_FOR_AUTOFILL_YES, to = "yes"), 8316 @ViewDebug.IntToString(from = IMPORTANT_FOR_AUTOFILL_NO, to = "no"), 8317 @ViewDebug.IntToString(from = IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS, 8318 to = "yesExcludeDescendants"), 8319 @ViewDebug.IntToString(from = IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS, 8320 to = "noExcludeDescendants")}) 8321 public @AutofillImportance int getImportantForAutofill() { 8322 return (mPrivateFlags3 8323 & PFLAG3_IMPORTANT_FOR_AUTOFILL_MASK) >> PFLAG3_IMPORTANT_FOR_AUTOFILL_SHIFT; 8324 } 8325 8326 /** 8327 * Sets the mode for determining whether this view is considered important for autofill. 8328 * 8329 * <p>The platform determines the importance for autofill automatically but you 8330 * can use this method to customize the behavior. For example: 8331 * 8332 * <ol> 8333 * <li>When the view contents is irrelevant for autofill (for example, a text field used in a 8334 * "Captcha" challenge), it should be {@link #IMPORTANT_FOR_AUTOFILL_NO}. 8335 * <li>When both the view and its children are irrelevant for autofill (for example, the root 8336 * view of an activity containing a spreadhseet editor), it should be 8337 * {@link #IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS}. 8338 * <li>When the view content is relevant for autofill but its children aren't (for example, 8339 * a credit card expiration date represented by a custom view that overrides the proper 8340 * autofill methods and has 2 children representing the month and year), it should 8341 * be {@link #IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS}. 8342 * </ol> 8343 * 8344 * <p><b>Note:</b> Setting the mode as {@link #IMPORTANT_FOR_AUTOFILL_NO} or 8345 * {@link #IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS} does not guarantee the view (and its 8346 * children) will be always be considered not important; for example, when the user explicitly 8347 * makes an autofill request, all views are considered important. See 8348 * {@link #isImportantForAutofill()} for more details about how the View's importance for 8349 * autofill is used. 8350 * 8351 * @param mode {@link #IMPORTANT_FOR_AUTOFILL_AUTO}, {@link #IMPORTANT_FOR_AUTOFILL_YES}, 8352 * {@link #IMPORTANT_FOR_AUTOFILL_NO}, {@link #IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS}, 8353 * or {@link #IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS}. 8354 * 8355 * @attr ref android.R.styleable#View_importantForAutofill 8356 */ 8357 public void setImportantForAutofill(@AutofillImportance int mode) { 8358 mPrivateFlags3 &= ~PFLAG3_IMPORTANT_FOR_AUTOFILL_MASK; 8359 mPrivateFlags3 |= (mode << PFLAG3_IMPORTANT_FOR_AUTOFILL_SHIFT) 8360 & PFLAG3_IMPORTANT_FOR_AUTOFILL_MASK; 8361 } 8362 8363 /** 8364 * Hints the Android System whether the {@link android.app.assist.AssistStructure.ViewNode} 8365 * associated with this view is considered important for autofill purposes. 8366 * 8367 * <p>Generally speaking, a view is important for autofill if: 8368 * <ol> 8369 * <li>The view can be autofilled by an {@link android.service.autofill.AutofillService}. 8370 * <li>The view contents can help an {@link android.service.autofill.AutofillService} 8371 * determine how other views can be autofilled. 8372 * <ol> 8373 * 8374 * <p>For example, view containers should typically return {@code false} for performance reasons 8375 * (since the important info is provided by their children), but if its properties have relevant 8376 * information (for example, a resource id called {@code credentials}, it should return 8377 * {@code true}. On the other hand, views representing labels or editable fields should 8378 * typically return {@code true}, but in some cases they could return {@code false} 8379 * (for example, if they're part of a "Captcha" mechanism). 8380 * 8381 * <p>The value returned by this method depends on the value returned by 8382 * {@link #getImportantForAutofill()}: 8383 * 8384 * <ol> 8385 * <li>if it returns {@link #IMPORTANT_FOR_AUTOFILL_YES} or 8386 * {@link #IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS}, then it returns {@code true} 8387 * <li>if it returns {@link #IMPORTANT_FOR_AUTOFILL_NO} or 8388 * {@link #IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS}, then it returns {@code false} 8389 * <li>if it returns {@link #IMPORTANT_FOR_AUTOFILL_AUTO}, then it uses some simple heuristics 8390 * that can return {@code true} in some cases (like a container with a resource id), 8391 * but {@code false} in most. 8392 * <li>otherwise, it returns {@code false}. 8393 * </ol> 8394 * 8395 * <p>When a view is considered important for autofill: 8396 * <ul> 8397 * <li>The view might automatically trigger an autofill request when focused on. 8398 * <li>The contents of the view are included in the {@link ViewStructure} used in an autofill 8399 * request. 8400 * </ul> 8401 * 8402 * <p>On the other hand, when a view is considered not important for autofill: 8403 * <ul> 8404 * <li>The view never automatically triggers autofill requests, but it can trigger a manual 8405 * request through {@link AutofillManager#requestAutofill(View)}. 8406 * <li>The contents of the view are not included in the {@link ViewStructure} used in an 8407 * autofill request, unless the request has the 8408 * {@link #AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS} flag. 8409 * </ul> 8410 * 8411 * @return whether the view is considered important for autofill. 8412 * 8413 * @see #setImportantForAutofill(int) 8414 * @see #IMPORTANT_FOR_AUTOFILL_AUTO 8415 * @see #IMPORTANT_FOR_AUTOFILL_YES 8416 * @see #IMPORTANT_FOR_AUTOFILL_NO 8417 * @see #IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS 8418 * @see #IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS 8419 * @see AutofillManager#requestAutofill(View) 8420 */ 8421 public final boolean isImportantForAutofill() { 8422 // Check parent mode to ensure we're not hidden. 8423 ViewParent parent = mParent; 8424 while (parent instanceof View) { 8425 final int parentImportance = ((View) parent).getImportantForAutofill(); 8426 if (parentImportance == IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS 8427 || parentImportance == IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS) { 8428 return false; 8429 } 8430 parent = parent.getParent(); 8431 } 8432 8433 final int importance = getImportantForAutofill(); 8434 8435 // First, check the explicit states. 8436 if (importance == IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS 8437 || importance == IMPORTANT_FOR_AUTOFILL_YES) { 8438 return true; 8439 } 8440 if (importance == IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS 8441 || importance == IMPORTANT_FOR_AUTOFILL_NO) { 8442 return false; 8443 } 8444 8445 // Then use some heuristics to handle AUTO. 8446 8447 // Always include views that have an explicit resource id. 8448 final int id = mID; 8449 if (id != NO_ID && !isViewIdGenerated(id)) { 8450 final Resources res = getResources(); 8451 String entry = null; 8452 String pkg = null; 8453 try { 8454 entry = res.getResourceEntryName(id); 8455 pkg = res.getResourcePackageName(id); 8456 } catch (Resources.NotFoundException e) { 8457 // ignore 8458 } 8459 if (entry != null && pkg != null && pkg.equals(mContext.getPackageName())) { 8460 return true; 8461 } 8462 } 8463 8464 // If the app developer explicitly set hints for it, it's important. 8465 if (getAutofillHints() != null) { 8466 return true; 8467 } 8468 8469 // Otherwise, assume it's not important... 8470 return false; 8471 } 8472 8473 @Nullable 8474 private AutofillManager getAutofillManager() { 8475 return mContext.getSystemService(AutofillManager.class); 8476 } 8477 8478 private boolean isAutofillable() { 8479 return getAutofillType() != AUTOFILL_TYPE_NONE && isImportantForAutofill() 8480 && getAutofillViewId() > LAST_APP_AUTOFILL_ID; 8481 } 8482 8483 /** @hide */ 8484 public boolean canNotifyAutofillEnterExitEvent() { 8485 return isAutofillable() && isAttachedToWindow(); 8486 } 8487 8488 private void populateVirtualStructure(ViewStructure structure, 8489 AccessibilityNodeProvider provider, AccessibilityNodeInfo info, 8490 boolean forAutofill) { 8491 structure.setId(AccessibilityNodeInfo.getVirtualDescendantId(info.getSourceNodeId()), 8492 null, null, info.getViewIdResourceName()); 8493 Rect rect = structure.getTempRect(); 8494 info.getBoundsInParent(rect); 8495 structure.setDimens(rect.left, rect.top, 0, 0, rect.width(), rect.height()); 8496 structure.setVisibility(VISIBLE); 8497 structure.setEnabled(info.isEnabled()); 8498 if (info.isClickable()) { 8499 structure.setClickable(true); 8500 } 8501 if (info.isFocusable()) { 8502 structure.setFocusable(true); 8503 } 8504 if (info.isFocused()) { 8505 structure.setFocused(true); 8506 } 8507 if (info.isAccessibilityFocused()) { 8508 structure.setAccessibilityFocused(true); 8509 } 8510 if (info.isSelected()) { 8511 structure.setSelected(true); 8512 } 8513 if (info.isLongClickable()) { 8514 structure.setLongClickable(true); 8515 } 8516 if (info.isCheckable()) { 8517 structure.setCheckable(true); 8518 if (info.isChecked()) { 8519 structure.setChecked(true); 8520 } 8521 } 8522 if (info.isContextClickable()) { 8523 structure.setContextClickable(true); 8524 } 8525 if (forAutofill) { 8526 structure.setAutofillId(new AutofillId(getAutofillId(), 8527 AccessibilityNodeInfo.getVirtualDescendantId(info.getSourceNodeId()))); 8528 } 8529 CharSequence cname = info.getClassName(); 8530 structure.setClassName(cname != null ? cname.toString() : null); 8531 structure.setContentDescription(info.getContentDescription()); 8532 if (forAutofill) { 8533 final int maxTextLength = info.getMaxTextLength(); 8534 if (maxTextLength != -1) { 8535 structure.setMaxTextLength(maxTextLength); 8536 } 8537 structure.setHint(info.getHintText()); 8538 } 8539 if ((info.getText() != null || info.getError() != null)) { 8540 structure.setText(info.getText(), info.getTextSelectionStart(), 8541 info.getTextSelectionEnd()); 8542 if (forAutofill) { 8543 if (info.isEditable()) { 8544 structure.setDataIsSensitive(true); 8545 structure.setAutofillType(AUTOFILL_TYPE_TEXT); 8546 final AutofillValue autofillValue = AutofillValue.forText(structure.getText()); 8547 structure.setAutofillValue(autofillValue); 8548 if (info.isPassword()) { 8549 structure.setInputType(InputType.TYPE_CLASS_TEXT 8550 | InputType.TYPE_TEXT_VARIATION_PASSWORD); 8551 } 8552 } else { 8553 structure.setDataIsSensitive(false); 8554 } 8555 } 8556 } 8557 final int NCHILDREN = info.getChildCount(); 8558 if (NCHILDREN > 0) { 8559 structure.setChildCount(NCHILDREN); 8560 for (int i=0; i<NCHILDREN; i++) { 8561 if (AccessibilityNodeInfo.getVirtualDescendantId(info.getChildNodeIds().get(i)) 8562 == AccessibilityNodeProvider.HOST_VIEW_ID) { 8563 Log.e(VIEW_LOG_TAG, "Virtual view pointing to its host. Ignoring"); 8564 continue; 8565 } 8566 AccessibilityNodeInfo cinfo = provider.createAccessibilityNodeInfo( 8567 AccessibilityNodeInfo.getVirtualDescendantId(info.getChildId(i))); 8568 ViewStructure child = structure.newChild(i); 8569 populateVirtualStructure(child, provider, cinfo, forAutofill); 8570 cinfo.recycle(); 8571 } 8572 } 8573 } 8574 8575 /** 8576 * Dispatch creation of {@link ViewStructure} down the hierarchy. The default 8577 * implementation calls {@link #onProvideStructure} and 8578 * {@link #onProvideVirtualStructure}. 8579 */ 8580 public void dispatchProvideStructure(ViewStructure structure) { 8581 dispatchProvideStructureForAssistOrAutofill(structure, false, 0); 8582 } 8583 8584 /** 8585 * Dispatches creation of a {@link ViewStructure}s for autofill purposes down the hierarchy, 8586 * when an Assist structure is being created as part of an autofill request. 8587 * 8588 * <p>The default implementation does the following: 8589 * <ul> 8590 * <li>Sets the {@link AutofillId} in the structure. 8591 * <li>Calls {@link #onProvideAutofillStructure(ViewStructure, int)}. 8592 * <li>Calls {@link #onProvideAutofillVirtualStructure(ViewStructure, int)}. 8593 * </ul> 8594 * 8595 * <p>Typically, this method should only be overridden by subclasses that provide a view 8596 * hierarchy (such as {@link ViewGroup}) - other classes should override 8597 * {@link #onProvideAutofillStructure(ViewStructure, int)} or 8598 * {@link #onProvideAutofillVirtualStructure(ViewStructure, int)} instead. 8599 * 8600 * <p>When overridden, it must: 8601 * 8602 * <ul> 8603 * <li>Either call 8604 * {@code super.dispatchProvideAutofillStructure(structure, flags)} or explicitly 8605 * set the {@link AutofillId} in the structure (for example, by calling 8606 * {@code structure.setAutofillId(getAutofillId())}). 8607 * <li>Decide how to handle the {@link #AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS} flag - when 8608 * set, all views in the structure should be considered important for autofill, 8609 * regardless of what {@link #isImportantForAutofill()} returns. We encourage you to 8610 * respect this flag to provide a better user experience - this flag is typically used 8611 * when an user explicitly requested autofill. If the flag is not set, 8612 * then only views marked as important for autofill should be included in the 8613 * structure - skipping non-important views optimizes the overall autofill performance. 8614 * </ul> 8615 * 8616 * @param structure fill in with structured view data for autofill purposes. 8617 * @param flags optional flags. 8618 * 8619 * @see #AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS 8620 */ 8621 public void dispatchProvideAutofillStructure(@NonNull ViewStructure structure, 8622 @AutofillFlags int flags) { 8623 dispatchProvideStructureForAssistOrAutofill(structure, true, flags); 8624 } 8625 8626 private void dispatchProvideStructureForAssistOrAutofill(ViewStructure structure, 8627 boolean forAutofill, @AutofillFlags int flags) { 8628 if (forAutofill) { 8629 structure.setAutofillId(getAutofillId()); 8630 onProvideAutofillStructure(structure, flags); 8631 onProvideAutofillVirtualStructure(structure, flags); 8632 } else if (!isAssistBlocked()) { 8633 onProvideStructure(structure); 8634 onProvideVirtualStructure(structure); 8635 } else { 8636 structure.setClassName(getAccessibilityClassName().toString()); 8637 structure.setAssistBlocked(true); 8638 } 8639 } 8640 8641 /** 8642 * @see #onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo) 8643 * 8644 * Note: Called from the default {@link AccessibilityDelegate}. 8645 * 8646 * @hide 8647 */ 8648 public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) { 8649 if (mAttachInfo == null) { 8650 return; 8651 } 8652 8653 Rect bounds = mAttachInfo.mTmpInvalRect; 8654 8655 getDrawingRect(bounds); 8656 info.setBoundsInParent(bounds); 8657 8658 getBoundsOnScreen(bounds, true); 8659 info.setBoundsInScreen(bounds); 8660 8661 ViewParent parent = getParentForAccessibility(); 8662 if (parent instanceof View) { 8663 info.setParent((View) parent); 8664 } 8665 8666 if (mID != View.NO_ID) { 8667 View rootView = getRootView(); 8668 if (rootView == null) { 8669 rootView = this; 8670 } 8671 8672 View label = rootView.findLabelForView(this, mID); 8673 if (label != null) { 8674 info.setLabeledBy(label); 8675 } 8676 8677 if ((mAttachInfo.mAccessibilityFetchFlags 8678 & AccessibilityNodeInfo.FLAG_REPORT_VIEW_IDS) != 0 8679 && Resources.resourceHasPackage(mID)) { 8680 try { 8681 String viewId = getResources().getResourceName(mID); 8682 info.setViewIdResourceName(viewId); 8683 } catch (Resources.NotFoundException nfe) { 8684 /* ignore */ 8685 } 8686 } 8687 } 8688 8689 if (mLabelForId != View.NO_ID) { 8690 View rootView = getRootView(); 8691 if (rootView == null) { 8692 rootView = this; 8693 } 8694 View labeled = rootView.findViewInsideOutShouldExist(this, mLabelForId); 8695 if (labeled != null) { 8696 info.setLabelFor(labeled); 8697 } 8698 } 8699 8700 if (mAccessibilityTraversalBeforeId != View.NO_ID) { 8701 View rootView = getRootView(); 8702 if (rootView == null) { 8703 rootView = this; 8704 } 8705 View next = rootView.findViewInsideOutShouldExist(this, 8706 mAccessibilityTraversalBeforeId); 8707 if (next != null && next.includeForAccessibility()) { 8708 info.setTraversalBefore(next); 8709 } 8710 } 8711 8712 if (mAccessibilityTraversalAfterId != View.NO_ID) { 8713 View rootView = getRootView(); 8714 if (rootView == null) { 8715 rootView = this; 8716 } 8717 View next = rootView.findViewInsideOutShouldExist(this, 8718 mAccessibilityTraversalAfterId); 8719 if (next != null && next.includeForAccessibility()) { 8720 info.setTraversalAfter(next); 8721 } 8722 } 8723 8724 info.setVisibleToUser(isVisibleToUser()); 8725 8726 info.setImportantForAccessibility(isImportantForAccessibility()); 8727 info.setPackageName(mContext.getPackageName()); 8728 info.setClassName(getAccessibilityClassName()); 8729 info.setContentDescription(getContentDescription()); 8730 8731 info.setEnabled(isEnabled()); 8732 info.setClickable(isClickable()); 8733 info.setFocusable(isFocusable()); 8734 info.setScreenReaderFocusable(isScreenReaderFocusable()); 8735 info.setFocused(isFocused()); 8736 info.setAccessibilityFocused(isAccessibilityFocused()); 8737 info.setSelected(isSelected()); 8738 info.setLongClickable(isLongClickable()); 8739 info.setContextClickable(isContextClickable()); 8740 info.setLiveRegion(getAccessibilityLiveRegion()); 8741 if ((mTooltipInfo != null) && (mTooltipInfo.mTooltipText != null)) { 8742 info.setTooltipText(mTooltipInfo.mTooltipText); 8743 info.addAction((mTooltipInfo.mTooltipPopup == null) 8744 ? AccessibilityNodeInfo.AccessibilityAction.ACTION_SHOW_TOOLTIP 8745 : AccessibilityNodeInfo.AccessibilityAction.ACTION_HIDE_TOOLTIP); 8746 } 8747 8748 // TODO: These make sense only if we are in an AdapterView but all 8749 // views can be selected. Maybe from accessibility perspective 8750 // we should report as selectable view in an AdapterView. 8751 info.addAction(AccessibilityNodeInfo.ACTION_SELECT); 8752 info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_SELECTION); 8753 8754 if (isFocusable()) { 8755 if (isFocused()) { 8756 info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_FOCUS); 8757 } else { 8758 info.addAction(AccessibilityNodeInfo.ACTION_FOCUS); 8759 } 8760 } 8761 8762 if (!isAccessibilityFocused()) { 8763 info.addAction(AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS); 8764 } else { 8765 info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS); 8766 } 8767 8768 if (isClickable() && isEnabled()) { 8769 info.addAction(AccessibilityNodeInfo.ACTION_CLICK); 8770 } 8771 8772 if (isLongClickable() && isEnabled()) { 8773 info.addAction(AccessibilityNodeInfo.ACTION_LONG_CLICK); 8774 } 8775 8776 if (isContextClickable() && isEnabled()) { 8777 info.addAction(AccessibilityAction.ACTION_CONTEXT_CLICK); 8778 } 8779 8780 CharSequence text = getIterableTextForAccessibility(); 8781 if (text != null && text.length() > 0) { 8782 info.setTextSelection(getAccessibilitySelectionStart(), getAccessibilitySelectionEnd()); 8783 8784 info.addAction(AccessibilityNodeInfo.ACTION_SET_SELECTION); 8785 info.addAction(AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY); 8786 info.addAction(AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY); 8787 info.setMovementGranularities(AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER 8788 | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD 8789 | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH); 8790 } 8791 8792 info.addAction(AccessibilityAction.ACTION_SHOW_ON_SCREEN); 8793 populateAccessibilityNodeInfoDrawingOrderInParent(info); 8794 info.setPaneTitle(mAccessibilityPaneTitle); 8795 } 8796 8797 /** 8798 * Adds extra data to an {@link AccessibilityNodeInfo} based on an explicit request for the 8799 * additional data. 8800 * <p> 8801 * This method only needs overloading if the node is marked as having extra data available. 8802 * </p> 8803 * 8804 * @param info The info to which to add the extra data. Never {@code null}. 8805 * @param extraDataKey A key specifying the type of extra data to add to the info. The 8806 * extra data should be added to the {@link Bundle} returned by 8807 * the info's {@link AccessibilityNodeInfo#getExtras} method. Never 8808 * {@code null}. 8809 * @param arguments A {@link Bundle} holding any arguments relevant for this request. May be 8810 * {@code null} if the service provided no arguments. 8811 * 8812 * @see AccessibilityNodeInfo#setAvailableExtraData(List) 8813 */ 8814 public void addExtraDataToAccessibilityNodeInfo( 8815 @NonNull AccessibilityNodeInfo info, @NonNull String extraDataKey, 8816 @Nullable Bundle arguments) { 8817 } 8818 8819 /** 8820 * Determine the order in which this view will be drawn relative to its siblings for a11y 8821 * 8822 * @param info The info whose drawing order should be populated 8823 */ 8824 private void populateAccessibilityNodeInfoDrawingOrderInParent(AccessibilityNodeInfo info) { 8825 /* 8826 * If the view's bounds haven't been set yet, layout has not completed. In that situation, 8827 * drawing order may not be well-defined, and some Views with custom drawing order may 8828 * not be initialized sufficiently to respond properly getChildDrawingOrder. 8829 */ 8830 if ((mPrivateFlags & PFLAG_HAS_BOUNDS) == 0) { 8831 info.setDrawingOrder(0); 8832 return; 8833 } 8834 int drawingOrderInParent = 1; 8835 // Iterate up the hierarchy if parents are not important for a11y 8836 View viewAtDrawingLevel = this; 8837 final ViewParent parent = getParentForAccessibility(); 8838 while (viewAtDrawingLevel != parent) { 8839 final ViewParent currentParent = viewAtDrawingLevel.getParent(); 8840 if (!(currentParent instanceof ViewGroup)) { 8841 // Should only happen for the Decor 8842 drawingOrderInParent = 0; 8843 break; 8844 } else { 8845 final ViewGroup parentGroup = (ViewGroup) currentParent; 8846 final int childCount = parentGroup.getChildCount(); 8847 if (childCount > 1) { 8848 List<View> preorderedList = parentGroup.buildOrderedChildList(); 8849 if (preorderedList != null) { 8850 final int childDrawIndex = preorderedList.indexOf(viewAtDrawingLevel); 8851 for (int i = 0; i < childDrawIndex; i++) { 8852 drawingOrderInParent += numViewsForAccessibility(preorderedList.get(i)); 8853 } 8854 } else { 8855 final int childIndex = parentGroup.indexOfChild(viewAtDrawingLevel); 8856 final boolean customOrder = parentGroup.isChildrenDrawingOrderEnabled(); 8857 final int childDrawIndex = ((childIndex >= 0) && customOrder) ? parentGroup 8858 .getChildDrawingOrder(childCount, childIndex) : childIndex; 8859 final int numChildrenToIterate = customOrder ? childCount : childDrawIndex; 8860 if (childDrawIndex != 0) { 8861 for (int i = 0; i < numChildrenToIterate; i++) { 8862 final int otherDrawIndex = (customOrder ? 8863 parentGroup.getChildDrawingOrder(childCount, i) : i); 8864 if (otherDrawIndex < childDrawIndex) { 8865 drawingOrderInParent += 8866 numViewsForAccessibility(parentGroup.getChildAt(i)); 8867 } 8868 } 8869 } 8870 } 8871 } 8872 } 8873 viewAtDrawingLevel = (View) currentParent; 8874 } 8875 info.setDrawingOrder(drawingOrderInParent); 8876 } 8877 8878 private static int numViewsForAccessibility(View view) { 8879 if (view != null) { 8880 if (view.includeForAccessibility()) { 8881 return 1; 8882 } else if (view instanceof ViewGroup) { 8883 return ((ViewGroup) view).getNumChildrenForAccessibility(); 8884 } 8885 } 8886 return 0; 8887 } 8888 8889 private View findLabelForView(View view, int labeledId) { 8890 if (mMatchLabelForPredicate == null) { 8891 mMatchLabelForPredicate = new MatchLabelForPredicate(); 8892 } 8893 mMatchLabelForPredicate.mLabeledId = labeledId; 8894 return findViewByPredicateInsideOut(view, mMatchLabelForPredicate); 8895 } 8896 8897 /** 8898 * Computes whether this virtual autofill view is visible to the user. 8899 * 8900 * <p><b>Note: </b>By default it returns {@code true}, but views providing a virtual hierarchy 8901 * view must override it. 8902 * 8903 * @return Whether the view is visible on the screen. 8904 */ 8905 public boolean isVisibleToUserForAutofill(int virtualId) { 8906 if (mContext.isAutofillCompatibilityEnabled()) { 8907 final AccessibilityNodeProvider provider = getAccessibilityNodeProvider(); 8908 if (provider != null) { 8909 final AccessibilityNodeInfo node = provider.createAccessibilityNodeInfo(virtualId); 8910 if (node != null) { 8911 return node.isVisibleToUser(); 8912 } 8913 // if node is null, assume it's not visible anymore 8914 } else { 8915 Log.w(VIEW_LOG_TAG, "isVisibleToUserForAutofill(" + virtualId + "): no provider"); 8916 } 8917 return false; 8918 } 8919 return true; 8920 } 8921 8922 /** 8923 * Computes whether this view is visible to the user. Such a view is 8924 * attached, visible, all its predecessors are visible, it is not clipped 8925 * entirely by its predecessors, and has an alpha greater than zero. 8926 * 8927 * @return Whether the view is visible on the screen. 8928 * 8929 * @hide 8930 */ 8931 public boolean isVisibleToUser() { 8932 return isVisibleToUser(null); 8933 } 8934 8935 /** 8936 * Computes whether the given portion of this view is visible to the user. 8937 * Such a view is attached, visible, all its predecessors are visible, 8938 * has an alpha greater than zero, and the specified portion is not 8939 * clipped entirely by its predecessors. 8940 * 8941 * @param boundInView the portion of the view to test; coordinates should be relative; may be 8942 * <code>null</code>, and the entire view will be tested in this case. 8943 * When <code>true</code> is returned by the function, the actual visible 8944 * region will be stored in this parameter; that is, if boundInView is fully 8945 * contained within the view, no modification will be made, otherwise regions 8946 * outside of the visible area of the view will be clipped. 8947 * 8948 * @return Whether the specified portion of the view is visible on the screen. 8949 * 8950 * @hide 8951 */ 8952 protected boolean isVisibleToUser(Rect boundInView) { 8953 if (mAttachInfo != null) { 8954 // Attached to invisible window means this view is not visible. 8955 if (mAttachInfo.mWindowVisibility != View.VISIBLE) { 8956 return false; 8957 } 8958 // An invisible predecessor or one with alpha zero means 8959 // that this view is not visible to the user. 8960 Object current = this; 8961 while (current instanceof View) { 8962 View view = (View) current; 8963 // We have attach info so this view is attached and there is no 8964 // need to check whether we reach to ViewRootImpl on the way up. 8965 if (view.getAlpha() <= 0 || view.getTransitionAlpha() <= 0 || 8966 view.getVisibility() != VISIBLE) { 8967 return false; 8968 } 8969 current = view.mParent; 8970 } 8971 // Check if the view is entirely covered by its predecessors. 8972 Rect visibleRect = mAttachInfo.mTmpInvalRect; 8973 Point offset = mAttachInfo.mPoint; 8974 if (!getGlobalVisibleRect(visibleRect, offset)) { 8975 return false; 8976 } 8977 // Check if the visible portion intersects the rectangle of interest. 8978 if (boundInView != null) { 8979 visibleRect.offset(-offset.x, -offset.y); 8980 return boundInView.intersect(visibleRect); 8981 } 8982 return true; 8983 } 8984 return false; 8985 } 8986 8987 /** 8988 * Returns the delegate for implementing accessibility support via 8989 * composition. For more details see {@link AccessibilityDelegate}. 8990 * 8991 * @return The delegate, or null if none set. 8992 * 8993 * @hide 8994 */ 8995 public AccessibilityDelegate getAccessibilityDelegate() { 8996 return mAccessibilityDelegate; 8997 } 8998 8999 /** 9000 * Sets a delegate for implementing accessibility support via composition 9001 * (as opposed to inheritance). For more details, see 9002 * {@link AccessibilityDelegate}. 9003 * <p> 9004 * <strong>Note:</strong> On platform versions prior to 9005 * {@link android.os.Build.VERSION_CODES#M API 23}, delegate methods on 9006 * views in the {@code android.widget.*} package are called <i>before</i> 9007 * host methods. This prevents certain properties such as class name from 9008 * being modified by overriding 9009 * {@link AccessibilityDelegate#onInitializeAccessibilityNodeInfo(View, AccessibilityNodeInfo)}, 9010 * as any changes will be overwritten by the host class. 9011 * <p> 9012 * Starting in {@link android.os.Build.VERSION_CODES#M API 23}, delegate 9013 * methods are called <i>after</i> host methods, which all properties to be 9014 * modified without being overwritten by the host class. 9015 * 9016 * @param delegate the object to which accessibility method calls should be 9017 * delegated 9018 * @see AccessibilityDelegate 9019 */ 9020 public void setAccessibilityDelegate(@Nullable AccessibilityDelegate delegate) { 9021 mAccessibilityDelegate = delegate; 9022 } 9023 9024 /** 9025 * Gets the provider for managing a virtual view hierarchy rooted at this View 9026 * and reported to {@link android.accessibilityservice.AccessibilityService}s 9027 * that explore the window content. 9028 * <p> 9029 * If this method returns an instance, this instance is responsible for managing 9030 * {@link AccessibilityNodeInfo}s describing the virtual sub-tree rooted at this 9031 * View including the one representing the View itself. Similarly the returned 9032 * instance is responsible for performing accessibility actions on any virtual 9033 * view or the root view itself. 9034 * </p> 9035 * <p> 9036 * If an {@link AccessibilityDelegate} has been specified via calling 9037 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 9038 * {@link AccessibilityDelegate#getAccessibilityNodeProvider(View)} 9039 * is responsible for handling this call. 9040 * </p> 9041 * 9042 * @return The provider. 9043 * 9044 * @see AccessibilityNodeProvider 9045 */ 9046 public AccessibilityNodeProvider getAccessibilityNodeProvider() { 9047 if (mAccessibilityDelegate != null) { 9048 return mAccessibilityDelegate.getAccessibilityNodeProvider(this); 9049 } else { 9050 return null; 9051 } 9052 } 9053 9054 /** 9055 * Gets the unique identifier of this view on the screen for accessibility purposes. 9056 * 9057 * @return The view accessibility id. 9058 * 9059 * @hide 9060 */ 9061 public int getAccessibilityViewId() { 9062 if (mAccessibilityViewId == NO_ID) { 9063 mAccessibilityViewId = sNextAccessibilityViewId++; 9064 } 9065 return mAccessibilityViewId; 9066 } 9067 9068 /** 9069 * Gets the unique identifier of this view on the screen for autofill purposes. 9070 * 9071 * @return The view autofill id. 9072 * 9073 * @hide 9074 */ 9075 public int getAutofillViewId() { 9076 if (mAutofillViewId == NO_ID) { 9077 mAutofillViewId = mContext.getNextAutofillId(); 9078 } 9079 return mAutofillViewId; 9080 } 9081 9082 /** 9083 * Gets the unique identifier of the window in which this View reseides. 9084 * 9085 * @return The window accessibility id. 9086 * 9087 * @hide 9088 */ 9089 public int getAccessibilityWindowId() { 9090 return mAttachInfo != null ? mAttachInfo.mAccessibilityWindowId 9091 : AccessibilityWindowInfo.UNDEFINED_WINDOW_ID; 9092 } 9093 9094 /** 9095 * Returns the {@link View}'s content description. 9096 * <p> 9097 * <strong>Note:</strong> Do not override this method, as it will have no 9098 * effect on the content description presented to accessibility services. 9099 * You must call {@link #setContentDescription(CharSequence)} to modify the 9100 * content description. 9101 * 9102 * @return the content description 9103 * @see #setContentDescription(CharSequence) 9104 * @attr ref android.R.styleable#View_contentDescription 9105 */ 9106 @ViewDebug.ExportedProperty(category = "accessibility") 9107 public CharSequence getContentDescription() { 9108 return mContentDescription; 9109 } 9110 9111 /** 9112 * Sets the {@link View}'s content description. 9113 * <p> 9114 * A content description briefly describes the view and is primarily used 9115 * for accessibility support to determine how a view should be presented to 9116 * the user. In the case of a view with no textual representation, such as 9117 * {@link android.widget.ImageButton}, a useful content description 9118 * explains what the view does. For example, an image button with a phone 9119 * icon that is used to place a call may use "Call" as its content 9120 * description. An image of a floppy disk that is used to save a file may 9121 * use "Save". 9122 * 9123 * @param contentDescription The content description. 9124 * @see #getContentDescription() 9125 * @attr ref android.R.styleable#View_contentDescription 9126 */ 9127 @RemotableViewMethod 9128 public void setContentDescription(CharSequence contentDescription) { 9129 if (mContentDescription == null) { 9130 if (contentDescription == null) { 9131 return; 9132 } 9133 } else if (mContentDescription.equals(contentDescription)) { 9134 return; 9135 } 9136 mContentDescription = contentDescription; 9137 final boolean nonEmptyDesc = contentDescription != null && contentDescription.length() > 0; 9138 if (nonEmptyDesc && getImportantForAccessibility() == IMPORTANT_FOR_ACCESSIBILITY_AUTO) { 9139 setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES); 9140 notifySubtreeAccessibilityStateChangedIfNeeded(); 9141 } else { 9142 notifyViewAccessibilityStateChangedIfNeeded( 9143 AccessibilityEvent.CONTENT_CHANGE_TYPE_CONTENT_DESCRIPTION); 9144 } 9145 } 9146 9147 /** 9148 * Sets the id of a view before which this one is visited in accessibility traversal. 9149 * A screen-reader must visit the content of this view before the content of the one 9150 * it precedes. For example, if view B is set to be before view A, then a screen-reader 9151 * will traverse the entire content of B before traversing the entire content of A, 9152 * regardles of what traversal strategy it is using. 9153 * <p> 9154 * Views that do not have specified before/after relationships are traversed in order 9155 * determined by the screen-reader. 9156 * </p> 9157 * <p> 9158 * Setting that this view is before a view that is not important for accessibility 9159 * or if this view is not important for accessibility will have no effect as the 9160 * screen-reader is not aware of unimportant views. 9161 * </p> 9162 * 9163 * @param beforeId The id of a view this one precedes in accessibility traversal. 9164 * 9165 * @attr ref android.R.styleable#View_accessibilityTraversalBefore 9166 * 9167 * @see #setImportantForAccessibility(int) 9168 */ 9169 @RemotableViewMethod 9170 public void setAccessibilityTraversalBefore(int beforeId) { 9171 if (mAccessibilityTraversalBeforeId == beforeId) { 9172 return; 9173 } 9174 mAccessibilityTraversalBeforeId = beforeId; 9175 notifyViewAccessibilityStateChangedIfNeeded( 9176 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 9177 } 9178 9179 /** 9180 * Gets the id of a view before which this one is visited in accessibility traversal. 9181 * 9182 * @return The id of a view this one precedes in accessibility traversal if 9183 * specified, otherwise {@link #NO_ID}. 9184 * 9185 * @see #setAccessibilityTraversalBefore(int) 9186 */ 9187 public int getAccessibilityTraversalBefore() { 9188 return mAccessibilityTraversalBeforeId; 9189 } 9190 9191 /** 9192 * Sets the id of a view after which this one is visited in accessibility traversal. 9193 * A screen-reader must visit the content of the other view before the content of this 9194 * one. For example, if view B is set to be after view A, then a screen-reader 9195 * will traverse the entire content of A before traversing the entire content of B, 9196 * regardles of what traversal strategy it is using. 9197 * <p> 9198 * Views that do not have specified before/after relationships are traversed in order 9199 * determined by the screen-reader. 9200 * </p> 9201 * <p> 9202 * Setting that this view is after a view that is not important for accessibility 9203 * or if this view is not important for accessibility will have no effect as the 9204 * screen-reader is not aware of unimportant views. 9205 * </p> 9206 * 9207 * @param afterId The id of a view this one succedees in accessibility traversal. 9208 * 9209 * @attr ref android.R.styleable#View_accessibilityTraversalAfter 9210 * 9211 * @see #setImportantForAccessibility(int) 9212 */ 9213 @RemotableViewMethod 9214 public void setAccessibilityTraversalAfter(int afterId) { 9215 if (mAccessibilityTraversalAfterId == afterId) { 9216 return; 9217 } 9218 mAccessibilityTraversalAfterId = afterId; 9219 notifyViewAccessibilityStateChangedIfNeeded( 9220 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 9221 } 9222 9223 /** 9224 * Gets the id of a view after which this one is visited in accessibility traversal. 9225 * 9226 * @return The id of a view this one succeedes in accessibility traversal if 9227 * specified, otherwise {@link #NO_ID}. 9228 * 9229 * @see #setAccessibilityTraversalAfter(int) 9230 */ 9231 public int getAccessibilityTraversalAfter() { 9232 return mAccessibilityTraversalAfterId; 9233 } 9234 9235 /** 9236 * Gets the id of a view for which this view serves as a label for 9237 * accessibility purposes. 9238 * 9239 * @return The labeled view id. 9240 */ 9241 @ViewDebug.ExportedProperty(category = "accessibility") 9242 public int getLabelFor() { 9243 return mLabelForId; 9244 } 9245 9246 /** 9247 * Sets the id of a view for which this view serves as a label for 9248 * accessibility purposes. 9249 * 9250 * @param id The labeled view id. 9251 */ 9252 @RemotableViewMethod 9253 public void setLabelFor(@IdRes int id) { 9254 if (mLabelForId == id) { 9255 return; 9256 } 9257 mLabelForId = id; 9258 if (mLabelForId != View.NO_ID 9259 && mID == View.NO_ID) { 9260 mID = generateViewId(); 9261 } 9262 notifyViewAccessibilityStateChangedIfNeeded( 9263 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 9264 } 9265 9266 /** 9267 * Invoked whenever this view loses focus, either by losing window focus or by losing 9268 * focus within its window. This method can be used to clear any state tied to the 9269 * focus. For instance, if a button is held pressed with the trackball and the window 9270 * loses focus, this method can be used to cancel the press. 9271 * 9272 * Subclasses of View overriding this method should always call super.onFocusLost(). 9273 * 9274 * @see #onFocusChanged(boolean, int, android.graphics.Rect) 9275 * @see #onWindowFocusChanged(boolean) 9276 * 9277 * @hide pending API council approval 9278 */ 9279 @CallSuper 9280 protected void onFocusLost() { 9281 resetPressedState(); 9282 } 9283 9284 private void resetPressedState() { 9285 if ((mViewFlags & ENABLED_MASK) == DISABLED) { 9286 return; 9287 } 9288 9289 if (isPressed()) { 9290 setPressed(false); 9291 9292 if (!mHasPerformedLongPress) { 9293 removeLongPressCallback(); 9294 } 9295 } 9296 } 9297 9298 /** 9299 * Returns true if this view has focus 9300 * 9301 * @return True if this view has focus, false otherwise. 9302 */ 9303 @ViewDebug.ExportedProperty(category = "focus") 9304 public boolean isFocused() { 9305 return (mPrivateFlags & PFLAG_FOCUSED) != 0; 9306 } 9307 9308 /** 9309 * Find the view in the hierarchy rooted at this view that currently has 9310 * focus. 9311 * 9312 * @return The view that currently has focus, or null if no focused view can 9313 * be found. 9314 */ 9315 public View findFocus() { 9316 return (mPrivateFlags & PFLAG_FOCUSED) != 0 ? this : null; 9317 } 9318 9319 /** 9320 * Indicates whether this view is one of the set of scrollable containers in 9321 * its window. 9322 * 9323 * @return whether this view is one of the set of scrollable containers in 9324 * its window 9325 * 9326 * @attr ref android.R.styleable#View_isScrollContainer 9327 */ 9328 public boolean isScrollContainer() { 9329 return (mPrivateFlags & PFLAG_SCROLL_CONTAINER_ADDED) != 0; 9330 } 9331 9332 /** 9333 * Change whether this view is one of the set of scrollable containers in 9334 * its window. This will be used to determine whether the window can 9335 * resize or must pan when a soft input area is open -- scrollable 9336 * containers allow the window to use resize mode since the container 9337 * will appropriately shrink. 9338 * 9339 * @attr ref android.R.styleable#View_isScrollContainer 9340 */ 9341 public void setScrollContainer(boolean isScrollContainer) { 9342 if (isScrollContainer) { 9343 if (mAttachInfo != null && (mPrivateFlags&PFLAG_SCROLL_CONTAINER_ADDED) == 0) { 9344 mAttachInfo.mScrollContainers.add(this); 9345 mPrivateFlags |= PFLAG_SCROLL_CONTAINER_ADDED; 9346 } 9347 mPrivateFlags |= PFLAG_SCROLL_CONTAINER; 9348 } else { 9349 if ((mPrivateFlags&PFLAG_SCROLL_CONTAINER_ADDED) != 0) { 9350 mAttachInfo.mScrollContainers.remove(this); 9351 } 9352 mPrivateFlags &= ~(PFLAG_SCROLL_CONTAINER|PFLAG_SCROLL_CONTAINER_ADDED); 9353 } 9354 } 9355 9356 /** 9357 * Returns the quality of the drawing cache. 9358 * 9359 * @return One of {@link #DRAWING_CACHE_QUALITY_AUTO}, 9360 * {@link #DRAWING_CACHE_QUALITY_LOW}, or {@link #DRAWING_CACHE_QUALITY_HIGH} 9361 * 9362 * @see #setDrawingCacheQuality(int) 9363 * @see #setDrawingCacheEnabled(boolean) 9364 * @see #isDrawingCacheEnabled() 9365 * 9366 * @attr ref android.R.styleable#View_drawingCacheQuality 9367 * 9368 * @deprecated The view drawing cache was largely made obsolete with the introduction of 9369 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 9370 * layers are largely unnecessary and can easily result in a net loss in performance due to the 9371 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 9372 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 9373 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 9374 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 9375 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 9376 * software-rendered usages are discouraged and have compatibility issues with hardware-only 9377 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 9378 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 9379 * reports or unit testing the {@link PixelCopy} API is recommended. 9380 */ 9381 @Deprecated 9382 @DrawingCacheQuality 9383 public int getDrawingCacheQuality() { 9384 return mViewFlags & DRAWING_CACHE_QUALITY_MASK; 9385 } 9386 9387 /** 9388 * Set the drawing cache quality of this view. This value is used only when the 9389 * drawing cache is enabled 9390 * 9391 * @param quality One of {@link #DRAWING_CACHE_QUALITY_AUTO}, 9392 * {@link #DRAWING_CACHE_QUALITY_LOW}, or {@link #DRAWING_CACHE_QUALITY_HIGH} 9393 * 9394 * @see #getDrawingCacheQuality() 9395 * @see #setDrawingCacheEnabled(boolean) 9396 * @see #isDrawingCacheEnabled() 9397 * 9398 * @attr ref android.R.styleable#View_drawingCacheQuality 9399 * 9400 * @deprecated The view drawing cache was largely made obsolete with the introduction of 9401 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 9402 * layers are largely unnecessary and can easily result in a net loss in performance due to the 9403 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 9404 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 9405 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 9406 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 9407 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 9408 * software-rendered usages are discouraged and have compatibility issues with hardware-only 9409 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 9410 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 9411 * reports or unit testing the {@link PixelCopy} API is recommended. 9412 */ 9413 @Deprecated 9414 public void setDrawingCacheQuality(@DrawingCacheQuality int quality) { 9415 setFlags(quality, DRAWING_CACHE_QUALITY_MASK); 9416 } 9417 9418 /** 9419 * Returns whether the screen should remain on, corresponding to the current 9420 * value of {@link #KEEP_SCREEN_ON}. 9421 * 9422 * @return Returns true if {@link #KEEP_SCREEN_ON} is set. 9423 * 9424 * @see #setKeepScreenOn(boolean) 9425 * 9426 * @attr ref android.R.styleable#View_keepScreenOn 9427 */ 9428 public boolean getKeepScreenOn() { 9429 return (mViewFlags & KEEP_SCREEN_ON) != 0; 9430 } 9431 9432 /** 9433 * Controls whether the screen should remain on, modifying the 9434 * value of {@link #KEEP_SCREEN_ON}. 9435 * 9436 * @param keepScreenOn Supply true to set {@link #KEEP_SCREEN_ON}. 9437 * 9438 * @see #getKeepScreenOn() 9439 * 9440 * @attr ref android.R.styleable#View_keepScreenOn 9441 */ 9442 public void setKeepScreenOn(boolean keepScreenOn) { 9443 setFlags(keepScreenOn ? KEEP_SCREEN_ON : 0, KEEP_SCREEN_ON); 9444 } 9445 9446 /** 9447 * Gets the id of the view to use when the next focus is {@link #FOCUS_LEFT}. 9448 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically. 9449 * 9450 * @attr ref android.R.styleable#View_nextFocusLeft 9451 */ 9452 public int getNextFocusLeftId() { 9453 return mNextFocusLeftId; 9454 } 9455 9456 /** 9457 * Sets the id of the view to use when the next focus is {@link #FOCUS_LEFT}. 9458 * @param nextFocusLeftId The next focus ID, or {@link #NO_ID} if the framework should 9459 * decide automatically. 9460 * 9461 * @attr ref android.R.styleable#View_nextFocusLeft 9462 */ 9463 public void setNextFocusLeftId(int nextFocusLeftId) { 9464 mNextFocusLeftId = nextFocusLeftId; 9465 } 9466 9467 /** 9468 * Gets the id of the view to use when the next focus is {@link #FOCUS_RIGHT}. 9469 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically. 9470 * 9471 * @attr ref android.R.styleable#View_nextFocusRight 9472 */ 9473 public int getNextFocusRightId() { 9474 return mNextFocusRightId; 9475 } 9476 9477 /** 9478 * Sets the id of the view to use when the next focus is {@link #FOCUS_RIGHT}. 9479 * @param nextFocusRightId The next focus ID, or {@link #NO_ID} if the framework should 9480 * decide automatically. 9481 * 9482 * @attr ref android.R.styleable#View_nextFocusRight 9483 */ 9484 public void setNextFocusRightId(int nextFocusRightId) { 9485 mNextFocusRightId = nextFocusRightId; 9486 } 9487 9488 /** 9489 * Gets the id of the view to use when the next focus is {@link #FOCUS_UP}. 9490 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically. 9491 * 9492 * @attr ref android.R.styleable#View_nextFocusUp 9493 */ 9494 public int getNextFocusUpId() { 9495 return mNextFocusUpId; 9496 } 9497 9498 /** 9499 * Sets the id of the view to use when the next focus is {@link #FOCUS_UP}. 9500 * @param nextFocusUpId The next focus ID, or {@link #NO_ID} if the framework should 9501 * decide automatically. 9502 * 9503 * @attr ref android.R.styleable#View_nextFocusUp 9504 */ 9505 public void setNextFocusUpId(int nextFocusUpId) { 9506 mNextFocusUpId = nextFocusUpId; 9507 } 9508 9509 /** 9510 * Gets the id of the view to use when the next focus is {@link #FOCUS_DOWN}. 9511 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically. 9512 * 9513 * @attr ref android.R.styleable#View_nextFocusDown 9514 */ 9515 public int getNextFocusDownId() { 9516 return mNextFocusDownId; 9517 } 9518 9519 /** 9520 * Sets the id of the view to use when the next focus is {@link #FOCUS_DOWN}. 9521 * @param nextFocusDownId The next focus ID, or {@link #NO_ID} if the framework should 9522 * decide automatically. 9523 * 9524 * @attr ref android.R.styleable#View_nextFocusDown 9525 */ 9526 public void setNextFocusDownId(int nextFocusDownId) { 9527 mNextFocusDownId = nextFocusDownId; 9528 } 9529 9530 /** 9531 * Gets the id of the view to use when the next focus is {@link #FOCUS_FORWARD}. 9532 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically. 9533 * 9534 * @attr ref android.R.styleable#View_nextFocusForward 9535 */ 9536 public int getNextFocusForwardId() { 9537 return mNextFocusForwardId; 9538 } 9539 9540 /** 9541 * Sets the id of the view to use when the next focus is {@link #FOCUS_FORWARD}. 9542 * @param nextFocusForwardId The next focus ID, or {@link #NO_ID} if the framework should 9543 * decide automatically. 9544 * 9545 * @attr ref android.R.styleable#View_nextFocusForward 9546 */ 9547 public void setNextFocusForwardId(int nextFocusForwardId) { 9548 mNextFocusForwardId = nextFocusForwardId; 9549 } 9550 9551 /** 9552 * Gets the id of the root of the next keyboard navigation cluster. 9553 * @return The next keyboard navigation cluster ID, or {@link #NO_ID} if the framework should 9554 * decide automatically. 9555 * 9556 * @attr ref android.R.styleable#View_nextClusterForward 9557 */ 9558 public int getNextClusterForwardId() { 9559 return mNextClusterForwardId; 9560 } 9561 9562 /** 9563 * Sets the id of the view to use as the root of the next keyboard navigation cluster. 9564 * @param nextClusterForwardId The next cluster ID, or {@link #NO_ID} if the framework should 9565 * decide automatically. 9566 * 9567 * @attr ref android.R.styleable#View_nextClusterForward 9568 */ 9569 public void setNextClusterForwardId(int nextClusterForwardId) { 9570 mNextClusterForwardId = nextClusterForwardId; 9571 } 9572 9573 /** 9574 * Returns the visibility of this view and all of its ancestors 9575 * 9576 * @return True if this view and all of its ancestors are {@link #VISIBLE} 9577 */ 9578 public boolean isShown() { 9579 View current = this; 9580 //noinspection ConstantConditions 9581 do { 9582 if ((current.mViewFlags & VISIBILITY_MASK) != VISIBLE) { 9583 return false; 9584 } 9585 ViewParent parent = current.mParent; 9586 if (parent == null) { 9587 return false; // We are not attached to the view root 9588 } 9589 if (!(parent instanceof View)) { 9590 return true; 9591 } 9592 current = (View) parent; 9593 } while (current != null); 9594 9595 return false; 9596 } 9597 9598 /** 9599 * Called by the view hierarchy when the content insets for a window have 9600 * changed, to allow it to adjust its content to fit within those windows. 9601 * The content insets tell you the space that the status bar, input method, 9602 * and other system windows infringe on the application's window. 9603 * 9604 * <p>You do not normally need to deal with this function, since the default 9605 * window decoration given to applications takes care of applying it to the 9606 * content of the window. If you use {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN} 9607 * or {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION} this will not be the case, 9608 * and your content can be placed under those system elements. You can then 9609 * use this method within your view hierarchy if you have parts of your UI 9610 * which you would like to ensure are not being covered. 9611 * 9612 * <p>The default implementation of this method simply applies the content 9613 * insets to the view's padding, consuming that content (modifying the 9614 * insets to be 0), and returning true. This behavior is off by default, but can 9615 * be enabled through {@link #setFitsSystemWindows(boolean)}. 9616 * 9617 * <p>This function's traversal down the hierarchy is depth-first. The same content 9618 * insets object is propagated down the hierarchy, so any changes made to it will 9619 * be seen by all following views (including potentially ones above in 9620 * the hierarchy since this is a depth-first traversal). The first view 9621 * that returns true will abort the entire traversal. 9622 * 9623 * <p>The default implementation works well for a situation where it is 9624 * used with a container that covers the entire window, allowing it to 9625 * apply the appropriate insets to its content on all edges. If you need 9626 * a more complicated layout (such as two different views fitting system 9627 * windows, one on the top of the window, and one on the bottom), 9628 * you can override the method and handle the insets however you would like. 9629 * Note that the insets provided by the framework are always relative to the 9630 * far edges of the window, not accounting for the location of the called view 9631 * within that window. (In fact when this method is called you do not yet know 9632 * where the layout will place the view, as it is done before layout happens.) 9633 * 9634 * <p>Note: unlike many View methods, there is no dispatch phase to this 9635 * call. If you are overriding it in a ViewGroup and want to allow the 9636 * call to continue to your children, you must be sure to call the super 9637 * implementation. 9638 * 9639 * <p>Here is a sample layout that makes use of fitting system windows 9640 * to have controls for a video view placed inside of the window decorations 9641 * that it hides and shows. This can be used with code like the second 9642 * sample (video player) shown in {@link #setSystemUiVisibility(int)}. 9643 * 9644 * {@sample development/samples/ApiDemos/res/layout/video_player.xml complete} 9645 * 9646 * @param insets Current content insets of the window. Prior to 9647 * {@link android.os.Build.VERSION_CODES#JELLY_BEAN} you must not modify 9648 * the insets or else you and Android will be unhappy. 9649 * 9650 * @return {@code true} if this view applied the insets and it should not 9651 * continue propagating further down the hierarchy, {@code false} otherwise. 9652 * @see #getFitsSystemWindows() 9653 * @see #setFitsSystemWindows(boolean) 9654 * @see #setSystemUiVisibility(int) 9655 * 9656 * @deprecated As of API 20 use {@link #dispatchApplyWindowInsets(WindowInsets)} to apply 9657 * insets to views. Views should override {@link #onApplyWindowInsets(WindowInsets)} or use 9658 * {@link #setOnApplyWindowInsetsListener(android.view.View.OnApplyWindowInsetsListener)} 9659 * to implement handling their own insets. 9660 */ 9661 @Deprecated 9662 protected boolean fitSystemWindows(Rect insets) { 9663 if ((mPrivateFlags3 & PFLAG3_APPLYING_INSETS) == 0) { 9664 if (insets == null) { 9665 // Null insets by definition have already been consumed. 9666 // This call cannot apply insets since there are none to apply, 9667 // so return false. 9668 return false; 9669 } 9670 // If we're not in the process of dispatching the newer apply insets call, 9671 // that means we're not in the compatibility path. Dispatch into the newer 9672 // apply insets path and take things from there. 9673 try { 9674 mPrivateFlags3 |= PFLAG3_FITTING_SYSTEM_WINDOWS; 9675 return dispatchApplyWindowInsets(new WindowInsets(insets)).isConsumed(); 9676 } finally { 9677 mPrivateFlags3 &= ~PFLAG3_FITTING_SYSTEM_WINDOWS; 9678 } 9679 } else { 9680 // We're being called from the newer apply insets path. 9681 // Perform the standard fallback behavior. 9682 return fitSystemWindowsInt(insets); 9683 } 9684 } 9685 9686 private boolean fitSystemWindowsInt(Rect insets) { 9687 if ((mViewFlags & FITS_SYSTEM_WINDOWS) == FITS_SYSTEM_WINDOWS) { 9688 mUserPaddingStart = UNDEFINED_PADDING; 9689 mUserPaddingEnd = UNDEFINED_PADDING; 9690 Rect localInsets = sThreadLocal.get(); 9691 if (localInsets == null) { 9692 localInsets = new Rect(); 9693 sThreadLocal.set(localInsets); 9694 } 9695 boolean res = computeFitSystemWindows(insets, localInsets); 9696 mUserPaddingLeftInitial = localInsets.left; 9697 mUserPaddingRightInitial = localInsets.right; 9698 internalSetPadding(localInsets.left, localInsets.top, 9699 localInsets.right, localInsets.bottom); 9700 return res; 9701 } 9702 return false; 9703 } 9704 9705 /** 9706 * Called when the view should apply {@link WindowInsets} according to its internal policy. 9707 * 9708 * <p>This method should be overridden by views that wish to apply a policy different from or 9709 * in addition to the default behavior. Clients that wish to force a view subtree 9710 * to apply insets should call {@link #dispatchApplyWindowInsets(WindowInsets)}.</p> 9711 * 9712 * <p>Clients may supply an {@link OnApplyWindowInsetsListener} to a view. If one is set 9713 * it will be called during dispatch instead of this method. The listener may optionally 9714 * call this method from its own implementation if it wishes to apply the view's default 9715 * insets policy in addition to its own.</p> 9716 * 9717 * <p>Implementations of this method should either return the insets parameter unchanged 9718 * or a new {@link WindowInsets} cloned from the supplied insets with any insets consumed 9719 * that this view applied itself. This allows new inset types added in future platform 9720 * versions to pass through existing implementations unchanged without being erroneously 9721 * consumed.</p> 9722 * 9723 * <p>By default if a view's {@link #setFitsSystemWindows(boolean) fitsSystemWindows} 9724 * property is set then the view will consume the system window insets and apply them 9725 * as padding for the view.</p> 9726 * 9727 * @param insets Insets to apply 9728 * @return The supplied insets with any applied insets consumed 9729 */ 9730 public WindowInsets onApplyWindowInsets(WindowInsets insets) { 9731 if ((mPrivateFlags3 & PFLAG3_FITTING_SYSTEM_WINDOWS) == 0) { 9732 // We weren't called from within a direct call to fitSystemWindows, 9733 // call into it as a fallback in case we're in a class that overrides it 9734 // and has logic to perform. 9735 if (fitSystemWindows(insets.getSystemWindowInsets())) { 9736 return insets.consumeSystemWindowInsets(); 9737 } 9738 } else { 9739 // We were called from within a direct call to fitSystemWindows. 9740 if (fitSystemWindowsInt(insets.getSystemWindowInsets())) { 9741 return insets.consumeSystemWindowInsets(); 9742 } 9743 } 9744 return insets; 9745 } 9746 9747 /** 9748 * Set an {@link OnApplyWindowInsetsListener} to take over the policy for applying 9749 * window insets to this view. The listener's 9750 * {@link OnApplyWindowInsetsListener#onApplyWindowInsets(View, WindowInsets) onApplyWindowInsets} 9751 * method will be called instead of the view's 9752 * {@link #onApplyWindowInsets(WindowInsets) onApplyWindowInsets} method. 9753 * 9754 * @param listener Listener to set 9755 * 9756 * @see #onApplyWindowInsets(WindowInsets) 9757 */ 9758 public void setOnApplyWindowInsetsListener(OnApplyWindowInsetsListener listener) { 9759 getListenerInfo().mOnApplyWindowInsetsListener = listener; 9760 } 9761 9762 /** 9763 * Request to apply the given window insets to this view or another view in its subtree. 9764 * 9765 * <p>This method should be called by clients wishing to apply insets corresponding to areas 9766 * obscured by window decorations or overlays. This can include the status and navigation bars, 9767 * action bars, input methods and more. New inset categories may be added in the future. 9768 * The method returns the insets provided minus any that were applied by this view or its 9769 * children.</p> 9770 * 9771 * <p>Clients wishing to provide custom behavior should override the 9772 * {@link #onApplyWindowInsets(WindowInsets)} method or alternatively provide a 9773 * {@link OnApplyWindowInsetsListener} via the 9774 * {@link #setOnApplyWindowInsetsListener(View.OnApplyWindowInsetsListener) setOnApplyWindowInsetsListener} 9775 * method.</p> 9776 * 9777 * <p>This method replaces the older {@link #fitSystemWindows(Rect) fitSystemWindows} method. 9778 * </p> 9779 * 9780 * @param insets Insets to apply 9781 * @return The provided insets minus the insets that were consumed 9782 */ 9783 public WindowInsets dispatchApplyWindowInsets(WindowInsets insets) { 9784 try { 9785 mPrivateFlags3 |= PFLAG3_APPLYING_INSETS; 9786 if (mListenerInfo != null && mListenerInfo.mOnApplyWindowInsetsListener != null) { 9787 return mListenerInfo.mOnApplyWindowInsetsListener.onApplyWindowInsets(this, insets); 9788 } else { 9789 return onApplyWindowInsets(insets); 9790 } 9791 } finally { 9792 mPrivateFlags3 &= ~PFLAG3_APPLYING_INSETS; 9793 } 9794 } 9795 9796 /** 9797 * Compute the view's coordinate within the surface. 9798 * 9799 * <p>Computes the coordinates of this view in its surface. The argument 9800 * must be an array of two integers. After the method returns, the array 9801 * contains the x and y location in that order.</p> 9802 * @hide 9803 * @param location an array of two integers in which to hold the coordinates 9804 */ 9805 public void getLocationInSurface(@Size(2) int[] location) { 9806 getLocationInWindow(location); 9807 if (mAttachInfo != null && mAttachInfo.mViewRootImpl != null) { 9808 location[0] += mAttachInfo.mViewRootImpl.mWindowAttributes.surfaceInsets.left; 9809 location[1] += mAttachInfo.mViewRootImpl.mWindowAttributes.surfaceInsets.top; 9810 } 9811 } 9812 9813 /** 9814 * Provide original WindowInsets that are dispatched to the view hierarchy. The insets are 9815 * only available if the view is attached. 9816 * 9817 * @return WindowInsets from the top of the view hierarchy or null if View is detached 9818 */ 9819 public WindowInsets getRootWindowInsets() { 9820 if (mAttachInfo != null) { 9821 return mAttachInfo.mViewRootImpl.getWindowInsets(false /* forceConstruct */); 9822 } 9823 return null; 9824 } 9825 9826 /** 9827 * @hide Compute the insets that should be consumed by this view and the ones 9828 * that should propagate to those under it. 9829 */ 9830 protected boolean computeFitSystemWindows(Rect inoutInsets, Rect outLocalInsets) { 9831 if ((mViewFlags & OPTIONAL_FITS_SYSTEM_WINDOWS) == 0 9832 || mAttachInfo == null 9833 || ((mAttachInfo.mSystemUiVisibility & SYSTEM_UI_LAYOUT_FLAGS) == 0 9834 && !mAttachInfo.mOverscanRequested)) { 9835 outLocalInsets.set(inoutInsets); 9836 inoutInsets.set(0, 0, 0, 0); 9837 return true; 9838 } else { 9839 // The application wants to take care of fitting system window for 9840 // the content... however we still need to take care of any overscan here. 9841 final Rect overscan = mAttachInfo.mOverscanInsets; 9842 outLocalInsets.set(overscan); 9843 inoutInsets.left -= overscan.left; 9844 inoutInsets.top -= overscan.top; 9845 inoutInsets.right -= overscan.right; 9846 inoutInsets.bottom -= overscan.bottom; 9847 return false; 9848 } 9849 } 9850 9851 /** 9852 * Compute insets that should be consumed by this view and the ones that should propagate 9853 * to those under it. 9854 * 9855 * @param in Insets currently being processed by this View, likely received as a parameter 9856 * to {@link #onApplyWindowInsets(WindowInsets)}. 9857 * @param outLocalInsets A Rect that will receive the insets that should be consumed 9858 * by this view 9859 * @return Insets that should be passed along to views under this one 9860 */ 9861 public WindowInsets computeSystemWindowInsets(WindowInsets in, Rect outLocalInsets) { 9862 if ((mViewFlags & OPTIONAL_FITS_SYSTEM_WINDOWS) == 0 9863 || mAttachInfo == null 9864 || (mAttachInfo.mSystemUiVisibility & SYSTEM_UI_LAYOUT_FLAGS) == 0) { 9865 outLocalInsets.set(in.getSystemWindowInsets()); 9866 return in.consumeSystemWindowInsets(); 9867 } else { 9868 outLocalInsets.set(0, 0, 0, 0); 9869 return in; 9870 } 9871 } 9872 9873 /** 9874 * Sets whether or not this view should account for system screen decorations 9875 * such as the status bar and inset its content; that is, controlling whether 9876 * the default implementation of {@link #fitSystemWindows(Rect)} will be 9877 * executed. See that method for more details. 9878 * 9879 * <p>Note that if you are providing your own implementation of 9880 * {@link #fitSystemWindows(Rect)}, then there is no need to set this 9881 * flag to true -- your implementation will be overriding the default 9882 * implementation that checks this flag. 9883 * 9884 * @param fitSystemWindows If true, then the default implementation of 9885 * {@link #fitSystemWindows(Rect)} will be executed. 9886 * 9887 * @attr ref android.R.styleable#View_fitsSystemWindows 9888 * @see #getFitsSystemWindows() 9889 * @see #fitSystemWindows(Rect) 9890 * @see #setSystemUiVisibility(int) 9891 */ 9892 public void setFitsSystemWindows(boolean fitSystemWindows) { 9893 setFlags(fitSystemWindows ? FITS_SYSTEM_WINDOWS : 0, FITS_SYSTEM_WINDOWS); 9894 } 9895 9896 /** 9897 * Check for state of {@link #setFitsSystemWindows(boolean)}. If this method 9898 * returns {@code true}, the default implementation of {@link #fitSystemWindows(Rect)} 9899 * will be executed. 9900 * 9901 * @return {@code true} if the default implementation of 9902 * {@link #fitSystemWindows(Rect)} will be executed. 9903 * 9904 * @attr ref android.R.styleable#View_fitsSystemWindows 9905 * @see #setFitsSystemWindows(boolean) 9906 * @see #fitSystemWindows(Rect) 9907 * @see #setSystemUiVisibility(int) 9908 */ 9909 @ViewDebug.ExportedProperty 9910 public boolean getFitsSystemWindows() { 9911 return (mViewFlags & FITS_SYSTEM_WINDOWS) == FITS_SYSTEM_WINDOWS; 9912 } 9913 9914 /** @hide */ 9915 public boolean fitsSystemWindows() { 9916 return getFitsSystemWindows(); 9917 } 9918 9919 /** 9920 * Ask that a new dispatch of {@link #fitSystemWindows(Rect)} be performed. 9921 * @deprecated Use {@link #requestApplyInsets()} for newer platform versions. 9922 */ 9923 @Deprecated 9924 public void requestFitSystemWindows() { 9925 if (mParent != null) { 9926 mParent.requestFitSystemWindows(); 9927 } 9928 } 9929 9930 /** 9931 * Ask that a new dispatch of {@link #onApplyWindowInsets(WindowInsets)} be performed. 9932 */ 9933 public void requestApplyInsets() { 9934 requestFitSystemWindows(); 9935 } 9936 9937 /** 9938 * For use by PhoneWindow to make its own system window fitting optional. 9939 * @hide 9940 */ 9941 public void makeOptionalFitsSystemWindows() { 9942 setFlags(OPTIONAL_FITS_SYSTEM_WINDOWS, OPTIONAL_FITS_SYSTEM_WINDOWS); 9943 } 9944 9945 /** 9946 * Returns the outsets, which areas of the device that aren't a surface, but we would like to 9947 * treat them as such. 9948 * @hide 9949 */ 9950 public void getOutsets(Rect outOutsetRect) { 9951 if (mAttachInfo != null) { 9952 outOutsetRect.set(mAttachInfo.mOutsets); 9953 } else { 9954 outOutsetRect.setEmpty(); 9955 } 9956 } 9957 9958 /** 9959 * Returns the visibility status for this view. 9960 * 9961 * @return One of {@link #VISIBLE}, {@link #INVISIBLE}, or {@link #GONE}. 9962 * @attr ref android.R.styleable#View_visibility 9963 */ 9964 @ViewDebug.ExportedProperty(mapping = { 9965 @ViewDebug.IntToString(from = VISIBLE, to = "VISIBLE"), 9966 @ViewDebug.IntToString(from = INVISIBLE, to = "INVISIBLE"), 9967 @ViewDebug.IntToString(from = GONE, to = "GONE") 9968 }) 9969 @Visibility 9970 public int getVisibility() { 9971 return mViewFlags & VISIBILITY_MASK; 9972 } 9973 9974 /** 9975 * Set the visibility state of this view. 9976 * 9977 * @param visibility One of {@link #VISIBLE}, {@link #INVISIBLE}, or {@link #GONE}. 9978 * @attr ref android.R.styleable#View_visibility 9979 */ 9980 @RemotableViewMethod 9981 public void setVisibility(@Visibility int visibility) { 9982 setFlags(visibility, VISIBILITY_MASK); 9983 } 9984 9985 /** 9986 * Returns the enabled status for this view. The interpretation of the 9987 * enabled state varies by subclass. 9988 * 9989 * @return True if this view is enabled, false otherwise. 9990 */ 9991 @ViewDebug.ExportedProperty 9992 public boolean isEnabled() { 9993 return (mViewFlags & ENABLED_MASK) == ENABLED; 9994 } 9995 9996 /** 9997 * Set the enabled state of this view. The interpretation of the enabled 9998 * state varies by subclass. 9999 * 10000 * @param enabled True if this view is enabled, false otherwise. 10001 */ 10002 @RemotableViewMethod 10003 public void setEnabled(boolean enabled) { 10004 if (enabled == isEnabled()) return; 10005 10006 setFlags(enabled ? ENABLED : DISABLED, ENABLED_MASK); 10007 10008 /* 10009 * The View most likely has to change its appearance, so refresh 10010 * the drawable state. 10011 */ 10012 refreshDrawableState(); 10013 10014 // Invalidate too, since the default behavior for views is to be 10015 // be drawn at 50% alpha rather than to change the drawable. 10016 invalidate(true); 10017 10018 if (!enabled) { 10019 cancelPendingInputEvents(); 10020 } 10021 } 10022 10023 /** 10024 * Set whether this view can receive the focus. 10025 * <p> 10026 * Setting this to false will also ensure that this view is not focusable 10027 * in touch mode. 10028 * 10029 * @param focusable If true, this view can receive the focus. 10030 * 10031 * @see #setFocusableInTouchMode(boolean) 10032 * @see #setFocusable(int) 10033 * @attr ref android.R.styleable#View_focusable 10034 */ 10035 public void setFocusable(boolean focusable) { 10036 setFocusable(focusable ? FOCUSABLE : NOT_FOCUSABLE); 10037 } 10038 10039 /** 10040 * Sets whether this view can receive focus. 10041 * <p> 10042 * Setting this to {@link #FOCUSABLE_AUTO} tells the framework to determine focusability 10043 * automatically based on the view's interactivity. This is the default. 10044 * <p> 10045 * Setting this to NOT_FOCUSABLE will ensure that this view is also not focusable 10046 * in touch mode. 10047 * 10048 * @param focusable One of {@link #NOT_FOCUSABLE}, {@link #FOCUSABLE}, 10049 * or {@link #FOCUSABLE_AUTO}. 10050 * @see #setFocusableInTouchMode(boolean) 10051 * @attr ref android.R.styleable#View_focusable 10052 */ 10053 public void setFocusable(@Focusable int focusable) { 10054 if ((focusable & (FOCUSABLE_AUTO | FOCUSABLE)) == 0) { 10055 setFlags(0, FOCUSABLE_IN_TOUCH_MODE); 10056 } 10057 setFlags(focusable, FOCUSABLE_MASK); 10058 } 10059 10060 /** 10061 * Set whether this view can receive focus while in touch mode. 10062 * 10063 * Setting this to true will also ensure that this view is focusable. 10064 * 10065 * @param focusableInTouchMode If true, this view can receive the focus while 10066 * in touch mode. 10067 * 10068 * @see #setFocusable(boolean) 10069 * @attr ref android.R.styleable#View_focusableInTouchMode 10070 */ 10071 public void setFocusableInTouchMode(boolean focusableInTouchMode) { 10072 // Focusable in touch mode should always be set before the focusable flag 10073 // otherwise, setting the focusable flag will trigger a focusableViewAvailable() 10074 // which, in touch mode, will not successfully request focus on this view 10075 // because the focusable in touch mode flag is not set 10076 setFlags(focusableInTouchMode ? FOCUSABLE_IN_TOUCH_MODE : 0, FOCUSABLE_IN_TOUCH_MODE); 10077 10078 // Clear FOCUSABLE_AUTO if set. 10079 if (focusableInTouchMode) { 10080 // Clears FOCUSABLE_AUTO if set. 10081 setFlags(FOCUSABLE, FOCUSABLE_MASK); 10082 } 10083 } 10084 10085 /** 10086 * Sets the hints that help an {@link android.service.autofill.AutofillService} determine how 10087 * to autofill the view with the user's data. 10088 * 10089 * <p>Typically, there is only one way to autofill a view, but there could be more than one. 10090 * For example, if the application accepts either an username or email address to identify 10091 * an user. 10092 * 10093 * <p>These hints are not validated by the Android System, but passed "as is" to the service. 10094 * Hence, they can have any value, but it's recommended to use the {@code AUTOFILL_HINT_} 10095 * constants such as: 10096 * {@link #AUTOFILL_HINT_USERNAME}, {@link #AUTOFILL_HINT_PASSWORD}, 10097 * {@link #AUTOFILL_HINT_EMAIL_ADDRESS}, 10098 * {@link #AUTOFILL_HINT_NAME}, 10099 * {@link #AUTOFILL_HINT_PHONE}, 10100 * {@link #AUTOFILL_HINT_POSTAL_ADDRESS}, {@link #AUTOFILL_HINT_POSTAL_CODE}, 10101 * {@link #AUTOFILL_HINT_CREDIT_CARD_NUMBER}, {@link #AUTOFILL_HINT_CREDIT_CARD_SECURITY_CODE}, 10102 * {@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE}, 10103 * {@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DAY}, 10104 * {@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH} or 10105 * {@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR}. 10106 * 10107 * @param autofillHints The autofill hints to set. If the array is emtpy, {@code null} is set. 10108 * @attr ref android.R.styleable#View_autofillHints 10109 */ 10110 public void setAutofillHints(@Nullable String... autofillHints) { 10111 if (autofillHints == null || autofillHints.length == 0) { 10112 mAutofillHints = null; 10113 } else { 10114 mAutofillHints = autofillHints; 10115 } 10116 } 10117 10118 /** 10119 * @hide 10120 */ 10121 @TestApi 10122 public void setAutofilled(boolean isAutofilled) { 10123 boolean wasChanged = isAutofilled != isAutofilled(); 10124 10125 if (wasChanged) { 10126 if (isAutofilled) { 10127 mPrivateFlags3 |= PFLAG3_IS_AUTOFILLED; 10128 } else { 10129 mPrivateFlags3 &= ~PFLAG3_IS_AUTOFILLED; 10130 } 10131 10132 invalidate(); 10133 } 10134 } 10135 10136 /** 10137 * Set whether this view should have sound effects enabled for events such as 10138 * clicking and touching. 10139 * 10140 * <p>You may wish to disable sound effects for a view if you already play sounds, 10141 * for instance, a dial key that plays dtmf tones. 10142 * 10143 * @param soundEffectsEnabled whether sound effects are enabled for this view. 10144 * @see #isSoundEffectsEnabled() 10145 * @see #playSoundEffect(int) 10146 * @attr ref android.R.styleable#View_soundEffectsEnabled 10147 */ 10148 public void setSoundEffectsEnabled(boolean soundEffectsEnabled) { 10149 setFlags(soundEffectsEnabled ? SOUND_EFFECTS_ENABLED: 0, SOUND_EFFECTS_ENABLED); 10150 } 10151 10152 /** 10153 * @return whether this view should have sound effects enabled for events such as 10154 * clicking and touching. 10155 * 10156 * @see #setSoundEffectsEnabled(boolean) 10157 * @see #playSoundEffect(int) 10158 * @attr ref android.R.styleable#View_soundEffectsEnabled 10159 */ 10160 @ViewDebug.ExportedProperty 10161 public boolean isSoundEffectsEnabled() { 10162 return SOUND_EFFECTS_ENABLED == (mViewFlags & SOUND_EFFECTS_ENABLED); 10163 } 10164 10165 /** 10166 * Set whether this view should have haptic feedback for events such as 10167 * long presses. 10168 * 10169 * <p>You may wish to disable haptic feedback if your view already controls 10170 * its own haptic feedback. 10171 * 10172 * @param hapticFeedbackEnabled whether haptic feedback enabled for this view. 10173 * @see #isHapticFeedbackEnabled() 10174 * @see #performHapticFeedback(int) 10175 * @attr ref android.R.styleable#View_hapticFeedbackEnabled 10176 */ 10177 public void setHapticFeedbackEnabled(boolean hapticFeedbackEnabled) { 10178 setFlags(hapticFeedbackEnabled ? HAPTIC_FEEDBACK_ENABLED: 0, HAPTIC_FEEDBACK_ENABLED); 10179 } 10180 10181 /** 10182 * @return whether this view should have haptic feedback enabled for events 10183 * long presses. 10184 * 10185 * @see #setHapticFeedbackEnabled(boolean) 10186 * @see #performHapticFeedback(int) 10187 * @attr ref android.R.styleable#View_hapticFeedbackEnabled 10188 */ 10189 @ViewDebug.ExportedProperty 10190 public boolean isHapticFeedbackEnabled() { 10191 return HAPTIC_FEEDBACK_ENABLED == (mViewFlags & HAPTIC_FEEDBACK_ENABLED); 10192 } 10193 10194 /** 10195 * Returns the layout direction for this view. 10196 * 10197 * @return One of {@link #LAYOUT_DIRECTION_LTR}, 10198 * {@link #LAYOUT_DIRECTION_RTL}, 10199 * {@link #LAYOUT_DIRECTION_INHERIT} or 10200 * {@link #LAYOUT_DIRECTION_LOCALE}. 10201 * 10202 * @attr ref android.R.styleable#View_layoutDirection 10203 * 10204 * @hide 10205 */ 10206 @ViewDebug.ExportedProperty(category = "layout", mapping = { 10207 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_LTR, to = "LTR"), 10208 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_RTL, to = "RTL"), 10209 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_INHERIT, to = "INHERIT"), 10210 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_LOCALE, to = "LOCALE") 10211 }) 10212 @LayoutDir 10213 public int getRawLayoutDirection() { 10214 return (mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_MASK) >> PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 10215 } 10216 10217 /** 10218 * Set the layout direction for this view. This will propagate a reset of layout direction 10219 * resolution to the view's children and resolve layout direction for this view. 10220 * 10221 * @param layoutDirection the layout direction to set. Should be one of: 10222 * 10223 * {@link #LAYOUT_DIRECTION_LTR}, 10224 * {@link #LAYOUT_DIRECTION_RTL}, 10225 * {@link #LAYOUT_DIRECTION_INHERIT}, 10226 * {@link #LAYOUT_DIRECTION_LOCALE}. 10227 * 10228 * Resolution will be done if the value is set to LAYOUT_DIRECTION_INHERIT. The resolution 10229 * proceeds up the parent chain of the view to get the value. If there is no parent, then it 10230 * will return the default {@link #LAYOUT_DIRECTION_LTR}. 10231 * 10232 * @attr ref android.R.styleable#View_layoutDirection 10233 */ 10234 @RemotableViewMethod 10235 public void setLayoutDirection(@LayoutDir int layoutDirection) { 10236 if (getRawLayoutDirection() != layoutDirection) { 10237 // Reset the current layout direction and the resolved one 10238 mPrivateFlags2 &= ~PFLAG2_LAYOUT_DIRECTION_MASK; 10239 resetRtlProperties(); 10240 // Set the new layout direction (filtered) 10241 mPrivateFlags2 |= 10242 ((layoutDirection << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT) & PFLAG2_LAYOUT_DIRECTION_MASK); 10243 // We need to resolve all RTL properties as they all depend on layout direction 10244 resolveRtlPropertiesIfNeeded(); 10245 requestLayout(); 10246 invalidate(true); 10247 } 10248 } 10249 10250 /** 10251 * Returns the resolved layout direction for this view. 10252 * 10253 * @return {@link #LAYOUT_DIRECTION_RTL} if the layout direction is RTL or returns 10254 * {@link #LAYOUT_DIRECTION_LTR} if the layout direction is not RTL. 10255 * 10256 * For compatibility, this will return {@link #LAYOUT_DIRECTION_LTR} if API version 10257 * is lower than {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR1}. 10258 * 10259 * @attr ref android.R.styleable#View_layoutDirection 10260 */ 10261 @ViewDebug.ExportedProperty(category = "layout", mapping = { 10262 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_LTR, to = "RESOLVED_DIRECTION_LTR"), 10263 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_RTL, to = "RESOLVED_DIRECTION_RTL") 10264 }) 10265 @ResolvedLayoutDir 10266 public int getLayoutDirection() { 10267 final int targetSdkVersion = getContext().getApplicationInfo().targetSdkVersion; 10268 if (targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR1) { 10269 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED; 10270 return LAYOUT_DIRECTION_RESOLVED_DEFAULT; 10271 } 10272 return ((mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL) == 10273 PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL) ? LAYOUT_DIRECTION_RTL : LAYOUT_DIRECTION_LTR; 10274 } 10275 10276 /** 10277 * Indicates whether or not this view's layout is right-to-left. This is resolved from 10278 * layout attribute and/or the inherited value from the parent 10279 * 10280 * @return true if the layout is right-to-left. 10281 * 10282 * @hide 10283 */ 10284 @ViewDebug.ExportedProperty(category = "layout") 10285 public boolean isLayoutRtl() { 10286 return (getLayoutDirection() == LAYOUT_DIRECTION_RTL); 10287 } 10288 10289 /** 10290 * Indicates whether the view is currently tracking transient state that the 10291 * app should not need to concern itself with saving and restoring, but that 10292 * the framework should take special note to preserve when possible. 10293 * 10294 * <p>A view with transient state cannot be trivially rebound from an external 10295 * data source, such as an adapter binding item views in a list. This may be 10296 * because the view is performing an animation, tracking user selection 10297 * of content, or similar.</p> 10298 * 10299 * @return true if the view has transient state 10300 */ 10301 @ViewDebug.ExportedProperty(category = "layout") 10302 public boolean hasTransientState() { 10303 return (mPrivateFlags2 & PFLAG2_HAS_TRANSIENT_STATE) == PFLAG2_HAS_TRANSIENT_STATE; 10304 } 10305 10306 /** 10307 * Set whether this view is currently tracking transient state that the 10308 * framework should attempt to preserve when possible. This flag is reference counted, 10309 * so every call to setHasTransientState(true) should be paired with a later call 10310 * to setHasTransientState(false). 10311 * 10312 * <p>A view with transient state cannot be trivially rebound from an external 10313 * data source, such as an adapter binding item views in a list. This may be 10314 * because the view is performing an animation, tracking user selection 10315 * of content, or similar.</p> 10316 * 10317 * @param hasTransientState true if this view has transient state 10318 */ 10319 public void setHasTransientState(boolean hasTransientState) { 10320 final boolean oldHasTransientState = hasTransientState(); 10321 mTransientStateCount = hasTransientState ? mTransientStateCount + 1 : 10322 mTransientStateCount - 1; 10323 if (mTransientStateCount < 0) { 10324 mTransientStateCount = 0; 10325 Log.e(VIEW_LOG_TAG, "hasTransientState decremented below 0: " + 10326 "unmatched pair of setHasTransientState calls"); 10327 } else if ((hasTransientState && mTransientStateCount == 1) || 10328 (!hasTransientState && mTransientStateCount == 0)) { 10329 // update flag if we've just incremented up from 0 or decremented down to 0 10330 mPrivateFlags2 = (mPrivateFlags2 & ~PFLAG2_HAS_TRANSIENT_STATE) | 10331 (hasTransientState ? PFLAG2_HAS_TRANSIENT_STATE : 0); 10332 final boolean newHasTransientState = hasTransientState(); 10333 if (mParent != null && newHasTransientState != oldHasTransientState) { 10334 try { 10335 mParent.childHasTransientStateChanged(this, newHasTransientState); 10336 } catch (AbstractMethodError e) { 10337 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 10338 " does not fully implement ViewParent", e); 10339 } 10340 } 10341 } 10342 } 10343 10344 /** 10345 * Returns true if this view is currently attached to a window. 10346 */ 10347 public boolean isAttachedToWindow() { 10348 return mAttachInfo != null; 10349 } 10350 10351 /** 10352 * Returns true if this view has been through at least one layout since it 10353 * was last attached to or detached from a window. 10354 */ 10355 public boolean isLaidOut() { 10356 return (mPrivateFlags3 & PFLAG3_IS_LAID_OUT) == PFLAG3_IS_LAID_OUT; 10357 } 10358 10359 /** 10360 * @return {@code true} if laid-out and not about to do another layout. 10361 */ 10362 boolean isLayoutValid() { 10363 return isLaidOut() && ((mPrivateFlags & PFLAG_FORCE_LAYOUT) == 0); 10364 } 10365 10366 /** 10367 * If this view doesn't do any drawing on its own, set this flag to 10368 * allow further optimizations. By default, this flag is not set on 10369 * View, but could be set on some View subclasses such as ViewGroup. 10370 * 10371 * Typically, if you override {@link #onDraw(android.graphics.Canvas)} 10372 * you should clear this flag. 10373 * 10374 * @param willNotDraw whether or not this View draw on its own 10375 */ 10376 public void setWillNotDraw(boolean willNotDraw) { 10377 setFlags(willNotDraw ? WILL_NOT_DRAW : 0, DRAW_MASK); 10378 } 10379 10380 /** 10381 * Returns whether or not this View draws on its own. 10382 * 10383 * @return true if this view has nothing to draw, false otherwise 10384 */ 10385 @ViewDebug.ExportedProperty(category = "drawing") 10386 public boolean willNotDraw() { 10387 return (mViewFlags & DRAW_MASK) == WILL_NOT_DRAW; 10388 } 10389 10390 /** 10391 * When a View's drawing cache is enabled, drawing is redirected to an 10392 * offscreen bitmap. Some views, like an ImageView, must be able to 10393 * bypass this mechanism if they already draw a single bitmap, to avoid 10394 * unnecessary usage of the memory. 10395 * 10396 * @param willNotCacheDrawing true if this view does not cache its 10397 * drawing, false otherwise 10398 */ 10399 public void setWillNotCacheDrawing(boolean willNotCacheDrawing) { 10400 setFlags(willNotCacheDrawing ? WILL_NOT_CACHE_DRAWING : 0, WILL_NOT_CACHE_DRAWING); 10401 } 10402 10403 /** 10404 * Returns whether or not this View can cache its drawing or not. 10405 * 10406 * @return true if this view does not cache its drawing, false otherwise 10407 */ 10408 @ViewDebug.ExportedProperty(category = "drawing") 10409 public boolean willNotCacheDrawing() { 10410 return (mViewFlags & WILL_NOT_CACHE_DRAWING) == WILL_NOT_CACHE_DRAWING; 10411 } 10412 10413 /** 10414 * Indicates whether this view reacts to click events or not. 10415 * 10416 * @return true if the view is clickable, false otherwise 10417 * 10418 * @see #setClickable(boolean) 10419 * @attr ref android.R.styleable#View_clickable 10420 */ 10421 @ViewDebug.ExportedProperty 10422 public boolean isClickable() { 10423 return (mViewFlags & CLICKABLE) == CLICKABLE; 10424 } 10425 10426 /** 10427 * Enables or disables click events for this view. When a view 10428 * is clickable it will change its state to "pressed" on every click. 10429 * Subclasses should set the view clickable to visually react to 10430 * user's clicks. 10431 * 10432 * @param clickable true to make the view clickable, false otherwise 10433 * 10434 * @see #isClickable() 10435 * @attr ref android.R.styleable#View_clickable 10436 */ 10437 public void setClickable(boolean clickable) { 10438 setFlags(clickable ? CLICKABLE : 0, CLICKABLE); 10439 } 10440 10441 /** 10442 * Indicates whether this view reacts to long click events or not. 10443 * 10444 * @return true if the view is long clickable, false otherwise 10445 * 10446 * @see #setLongClickable(boolean) 10447 * @attr ref android.R.styleable#View_longClickable 10448 */ 10449 public boolean isLongClickable() { 10450 return (mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE; 10451 } 10452 10453 /** 10454 * Enables or disables long click events for this view. When a view is long 10455 * clickable it reacts to the user holding down the button for a longer 10456 * duration than a tap. This event can either launch the listener or a 10457 * context menu. 10458 * 10459 * @param longClickable true to make the view long clickable, false otherwise 10460 * @see #isLongClickable() 10461 * @attr ref android.R.styleable#View_longClickable 10462 */ 10463 public void setLongClickable(boolean longClickable) { 10464 setFlags(longClickable ? LONG_CLICKABLE : 0, LONG_CLICKABLE); 10465 } 10466 10467 /** 10468 * Indicates whether this view reacts to context clicks or not. 10469 * 10470 * @return true if the view is context clickable, false otherwise 10471 * @see #setContextClickable(boolean) 10472 * @attr ref android.R.styleable#View_contextClickable 10473 */ 10474 public boolean isContextClickable() { 10475 return (mViewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE; 10476 } 10477 10478 /** 10479 * Enables or disables context clicking for this view. This event can launch the listener. 10480 * 10481 * @param contextClickable true to make the view react to a context click, false otherwise 10482 * @see #isContextClickable() 10483 * @attr ref android.R.styleable#View_contextClickable 10484 */ 10485 public void setContextClickable(boolean contextClickable) { 10486 setFlags(contextClickable ? CONTEXT_CLICKABLE : 0, CONTEXT_CLICKABLE); 10487 } 10488 10489 /** 10490 * Sets the pressed state for this view and provides a touch coordinate for 10491 * animation hinting. 10492 * 10493 * @param pressed Pass true to set the View's internal state to "pressed", 10494 * or false to reverts the View's internal state from a 10495 * previously set "pressed" state. 10496 * @param x The x coordinate of the touch that caused the press 10497 * @param y The y coordinate of the touch that caused the press 10498 */ 10499 private void setPressed(boolean pressed, float x, float y) { 10500 if (pressed) { 10501 drawableHotspotChanged(x, y); 10502 } 10503 10504 setPressed(pressed); 10505 } 10506 10507 /** 10508 * Sets the pressed state for this view. 10509 * 10510 * @see #isClickable() 10511 * @see #setClickable(boolean) 10512 * 10513 * @param pressed Pass true to set the View's internal state to "pressed", or false to reverts 10514 * the View's internal state from a previously set "pressed" state. 10515 */ 10516 public void setPressed(boolean pressed) { 10517 final boolean needsRefresh = pressed != ((mPrivateFlags & PFLAG_PRESSED) == PFLAG_PRESSED); 10518 10519 if (pressed) { 10520 mPrivateFlags |= PFLAG_PRESSED; 10521 } else { 10522 mPrivateFlags &= ~PFLAG_PRESSED; 10523 } 10524 10525 if (needsRefresh) { 10526 refreshDrawableState(); 10527 } 10528 dispatchSetPressed(pressed); 10529 } 10530 10531 /** 10532 * Dispatch setPressed to all of this View's children. 10533 * 10534 * @see #setPressed(boolean) 10535 * 10536 * @param pressed The new pressed state 10537 */ 10538 protected void dispatchSetPressed(boolean pressed) { 10539 } 10540 10541 /** 10542 * Indicates whether the view is currently in pressed state. Unless 10543 * {@link #setPressed(boolean)} is explicitly called, only clickable views can enter 10544 * the pressed state. 10545 * 10546 * @see #setPressed(boolean) 10547 * @see #isClickable() 10548 * @see #setClickable(boolean) 10549 * 10550 * @return true if the view is currently pressed, false otherwise 10551 */ 10552 @ViewDebug.ExportedProperty 10553 public boolean isPressed() { 10554 return (mPrivateFlags & PFLAG_PRESSED) == PFLAG_PRESSED; 10555 } 10556 10557 /** 10558 * @hide 10559 * Indicates whether this view will participate in data collection through 10560 * {@link ViewStructure}. If true, it will not provide any data 10561 * for itself or its children. If false, the normal data collection will be allowed. 10562 * 10563 * @return Returns false if assist data collection is not blocked, else true. 10564 * 10565 * @see #setAssistBlocked(boolean) 10566 * @attr ref android.R.styleable#View_assistBlocked 10567 */ 10568 public boolean isAssistBlocked() { 10569 return (mPrivateFlags3 & PFLAG3_ASSIST_BLOCKED) != 0; 10570 } 10571 10572 /** 10573 * @hide 10574 * Controls whether assist data collection from this view and its children is enabled 10575 * (that is, whether {@link #onProvideStructure} and 10576 * {@link #onProvideVirtualStructure} will be called). The default value is false, 10577 * allowing normal assist collection. Setting this to false will disable assist collection. 10578 * 10579 * @param enabled Set to true to <em>disable</em> assist data collection, or false 10580 * (the default) to allow it. 10581 * 10582 * @see #isAssistBlocked() 10583 * @see #onProvideStructure 10584 * @see #onProvideVirtualStructure 10585 * @attr ref android.R.styleable#View_assistBlocked 10586 */ 10587 public void setAssistBlocked(boolean enabled) { 10588 if (enabled) { 10589 mPrivateFlags3 |= PFLAG3_ASSIST_BLOCKED; 10590 } else { 10591 mPrivateFlags3 &= ~PFLAG3_ASSIST_BLOCKED; 10592 } 10593 } 10594 10595 /** 10596 * Indicates whether this view will save its state (that is, 10597 * whether its {@link #onSaveInstanceState} method will be called). 10598 * 10599 * @return Returns true if the view state saving is enabled, else false. 10600 * 10601 * @see #setSaveEnabled(boolean) 10602 * @attr ref android.R.styleable#View_saveEnabled 10603 */ 10604 public boolean isSaveEnabled() { 10605 return (mViewFlags & SAVE_DISABLED_MASK) != SAVE_DISABLED; 10606 } 10607 10608 /** 10609 * Controls whether the saving of this view's state is 10610 * enabled (that is, whether its {@link #onSaveInstanceState} method 10611 * will be called). Note that even if freezing is enabled, the 10612 * view still must have an id assigned to it (via {@link #setId(int)}) 10613 * for its state to be saved. This flag can only disable the 10614 * saving of this view; any child views may still have their state saved. 10615 * 10616 * @param enabled Set to false to <em>disable</em> state saving, or true 10617 * (the default) to allow it. 10618 * 10619 * @see #isSaveEnabled() 10620 * @see #setId(int) 10621 * @see #onSaveInstanceState() 10622 * @attr ref android.R.styleable#View_saveEnabled 10623 */ 10624 public void setSaveEnabled(boolean enabled) { 10625 setFlags(enabled ? 0 : SAVE_DISABLED, SAVE_DISABLED_MASK); 10626 } 10627 10628 /** 10629 * Gets whether the framework should discard touches when the view's 10630 * window is obscured by another visible window. 10631 * Refer to the {@link View} security documentation for more details. 10632 * 10633 * @return True if touch filtering is enabled. 10634 * 10635 * @see #setFilterTouchesWhenObscured(boolean) 10636 * @attr ref android.R.styleable#View_filterTouchesWhenObscured 10637 */ 10638 @ViewDebug.ExportedProperty 10639 public boolean getFilterTouchesWhenObscured() { 10640 return (mViewFlags & FILTER_TOUCHES_WHEN_OBSCURED) != 0; 10641 } 10642 10643 /** 10644 * Sets whether the framework should discard touches when the view's 10645 * window is obscured by another visible window. 10646 * Refer to the {@link View} security documentation for more details. 10647 * 10648 * @param enabled True if touch filtering should be enabled. 10649 * 10650 * @see #getFilterTouchesWhenObscured 10651 * @attr ref android.R.styleable#View_filterTouchesWhenObscured 10652 */ 10653 public void setFilterTouchesWhenObscured(boolean enabled) { 10654 setFlags(enabled ? FILTER_TOUCHES_WHEN_OBSCURED : 0, 10655 FILTER_TOUCHES_WHEN_OBSCURED); 10656 } 10657 10658 /** 10659 * Indicates whether the entire hierarchy under this view will save its 10660 * state when a state saving traversal occurs from its parent. The default 10661 * is true; if false, these views will not be saved unless 10662 * {@link #saveHierarchyState(SparseArray)} is called directly on this view. 10663 * 10664 * @return Returns true if the view state saving from parent is enabled, else false. 10665 * 10666 * @see #setSaveFromParentEnabled(boolean) 10667 */ 10668 public boolean isSaveFromParentEnabled() { 10669 return (mViewFlags & PARENT_SAVE_DISABLED_MASK) != PARENT_SAVE_DISABLED; 10670 } 10671 10672 /** 10673 * Controls whether the entire hierarchy under this view will save its 10674 * state when a state saving traversal occurs from its parent. The default 10675 * is true; if false, these views will not be saved unless 10676 * {@link #saveHierarchyState(SparseArray)} is called directly on this view. 10677 * 10678 * @param enabled Set to false to <em>disable</em> state saving, or true 10679 * (the default) to allow it. 10680 * 10681 * @see #isSaveFromParentEnabled() 10682 * @see #setId(int) 10683 * @see #onSaveInstanceState() 10684 */ 10685 public void setSaveFromParentEnabled(boolean enabled) { 10686 setFlags(enabled ? 0 : PARENT_SAVE_DISABLED, PARENT_SAVE_DISABLED_MASK); 10687 } 10688 10689 10690 /** 10691 * Returns whether this View is currently able to take focus. 10692 * 10693 * @return True if this view can take focus, or false otherwise. 10694 */ 10695 @ViewDebug.ExportedProperty(category = "focus") 10696 public final boolean isFocusable() { 10697 return FOCUSABLE == (mViewFlags & FOCUSABLE); 10698 } 10699 10700 /** 10701 * Returns the focusable setting for this view. 10702 * 10703 * @return One of {@link #NOT_FOCUSABLE}, {@link #FOCUSABLE}, or {@link #FOCUSABLE_AUTO}. 10704 * @attr ref android.R.styleable#View_focusable 10705 */ 10706 @ViewDebug.ExportedProperty(mapping = { 10707 @ViewDebug.IntToString(from = NOT_FOCUSABLE, to = "NOT_FOCUSABLE"), 10708 @ViewDebug.IntToString(from = FOCUSABLE, to = "FOCUSABLE"), 10709 @ViewDebug.IntToString(from = FOCUSABLE_AUTO, to = "FOCUSABLE_AUTO") 10710 }, category = "focus") 10711 @Focusable 10712 public int getFocusable() { 10713 return (mViewFlags & FOCUSABLE_AUTO) > 0 ? FOCUSABLE_AUTO : mViewFlags & FOCUSABLE; 10714 } 10715 10716 /** 10717 * When a view is focusable, it may not want to take focus when in touch mode. 10718 * For example, a button would like focus when the user is navigating via a D-pad 10719 * so that the user can click on it, but once the user starts touching the screen, 10720 * the button shouldn't take focus 10721 * @return Whether the view is focusable in touch mode. 10722 * @attr ref android.R.styleable#View_focusableInTouchMode 10723 */ 10724 @ViewDebug.ExportedProperty(category = "focus") 10725 public final boolean isFocusableInTouchMode() { 10726 return FOCUSABLE_IN_TOUCH_MODE == (mViewFlags & FOCUSABLE_IN_TOUCH_MODE); 10727 } 10728 10729 /** 10730 * Returns whether the view should be treated as a focusable unit by screen reader 10731 * accessibility tools. 10732 * @see #setScreenReaderFocusable(boolean) 10733 * 10734 * @return Whether the view should be treated as a focusable unit by screen reader. 10735 */ 10736 public boolean isScreenReaderFocusable() { 10737 return (mPrivateFlags3 & PFLAG3_SCREEN_READER_FOCUSABLE) != 0; 10738 } 10739 10740 /** 10741 * When screen readers (one type of accessibility tool) decide what should be read to the 10742 * user, they typically look for input focusable ({@link #isFocusable()}) parents of 10743 * non-focusable text items, and read those focusable parents and their non-focusable children 10744 * as a unit. In some situations, this behavior is desirable for views that should not take 10745 * input focus. Setting an item to be screen reader focusable requests that the view be 10746 * treated as a unit by screen readers without any effect on input focusability. The default 10747 * value of {@code false} lets screen readers use other signals, like focusable, to determine 10748 * how to group items. 10749 * 10750 * @param screenReaderFocusable Whether the view should be treated as a unit by screen reader 10751 * accessibility tools. 10752 */ 10753 public void setScreenReaderFocusable(boolean screenReaderFocusable) { 10754 int pflags3 = mPrivateFlags3; 10755 if (screenReaderFocusable) { 10756 pflags3 |= PFLAG3_SCREEN_READER_FOCUSABLE; 10757 } else { 10758 pflags3 &= ~PFLAG3_SCREEN_READER_FOCUSABLE; 10759 } 10760 10761 if (pflags3 != mPrivateFlags3) { 10762 mPrivateFlags3 = pflags3; 10763 notifyViewAccessibilityStateChangedIfNeeded( 10764 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 10765 } 10766 } 10767 10768 /** 10769 * Find the nearest view in the specified direction that can take focus. 10770 * This does not actually give focus to that view. 10771 * 10772 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT 10773 * 10774 * @return The nearest focusable in the specified direction, or null if none 10775 * can be found. 10776 */ 10777 public View focusSearch(@FocusRealDirection int direction) { 10778 if (mParent != null) { 10779 return mParent.focusSearch(this, direction); 10780 } else { 10781 return null; 10782 } 10783 } 10784 10785 /** 10786 * Returns whether this View is a root of a keyboard navigation cluster. 10787 * 10788 * @return True if this view is a root of a cluster, or false otherwise. 10789 * @attr ref android.R.styleable#View_keyboardNavigationCluster 10790 */ 10791 @ViewDebug.ExportedProperty(category = "focus") 10792 public final boolean isKeyboardNavigationCluster() { 10793 return (mPrivateFlags3 & PFLAG3_CLUSTER) != 0; 10794 } 10795 10796 /** 10797 * Searches up the view hierarchy to find the top-most cluster. All deeper/nested clusters 10798 * will be ignored. 10799 * 10800 * @return the keyboard navigation cluster that this view is in (can be this view) 10801 * or {@code null} if not in one 10802 */ 10803 View findKeyboardNavigationCluster() { 10804 if (mParent instanceof View) { 10805 View cluster = ((View) mParent).findKeyboardNavigationCluster(); 10806 if (cluster != null) { 10807 return cluster; 10808 } else if (isKeyboardNavigationCluster()) { 10809 return this; 10810 } 10811 } 10812 return null; 10813 } 10814 10815 /** 10816 * Set whether this view is a root of a keyboard navigation cluster. 10817 * 10818 * @param isCluster If true, this view is a root of a cluster. 10819 * 10820 * @attr ref android.R.styleable#View_keyboardNavigationCluster 10821 */ 10822 public void setKeyboardNavigationCluster(boolean isCluster) { 10823 if (isCluster) { 10824 mPrivateFlags3 |= PFLAG3_CLUSTER; 10825 } else { 10826 mPrivateFlags3 &= ~PFLAG3_CLUSTER; 10827 } 10828 } 10829 10830 /** 10831 * Sets this View as the one which receives focus the next time cluster navigation jumps 10832 * to the cluster containing this View. This does NOT change focus even if the cluster 10833 * containing this view is current. 10834 * 10835 * @hide 10836 */ 10837 @TestApi 10838 public final void setFocusedInCluster() { 10839 setFocusedInCluster(findKeyboardNavigationCluster()); 10840 } 10841 10842 private void setFocusedInCluster(View cluster) { 10843 if (this instanceof ViewGroup) { 10844 ((ViewGroup) this).mFocusedInCluster = null; 10845 } 10846 if (cluster == this) { 10847 return; 10848 } 10849 ViewParent parent = mParent; 10850 View child = this; 10851 while (parent instanceof ViewGroup) { 10852 ((ViewGroup) parent).mFocusedInCluster = child; 10853 if (parent == cluster) { 10854 break; 10855 } 10856 child = (View) parent; 10857 parent = parent.getParent(); 10858 } 10859 } 10860 10861 private void updateFocusedInCluster(View oldFocus, @FocusDirection int direction) { 10862 if (oldFocus != null) { 10863 View oldCluster = oldFocus.findKeyboardNavigationCluster(); 10864 View cluster = findKeyboardNavigationCluster(); 10865 if (oldCluster != cluster) { 10866 // Going from one cluster to another, so save last-focused. 10867 // This covers cluster jumps because they are always FOCUS_DOWN 10868 oldFocus.setFocusedInCluster(oldCluster); 10869 if (!(oldFocus.mParent instanceof ViewGroup)) { 10870 return; 10871 } 10872 if (direction == FOCUS_FORWARD || direction == FOCUS_BACKWARD) { 10873 // This is a result of ordered navigation so consider navigation through 10874 // the previous cluster "complete" and clear its last-focused memory. 10875 ((ViewGroup) oldFocus.mParent).clearFocusedInCluster(oldFocus); 10876 } else if (oldFocus instanceof ViewGroup 10877 && ((ViewGroup) oldFocus).getDescendantFocusability() 10878 == ViewGroup.FOCUS_AFTER_DESCENDANTS 10879 && ViewRootImpl.isViewDescendantOf(this, oldFocus)) { 10880 // This means oldFocus is not focusable since it obviously has a focusable 10881 // child (this). Don't restore focus to it in the future. 10882 ((ViewGroup) oldFocus.mParent).clearFocusedInCluster(oldFocus); 10883 } 10884 } 10885 } 10886 } 10887 10888 /** 10889 * Returns whether this View should receive focus when the focus is restored for the view 10890 * hierarchy containing this view. 10891 * <p> 10892 * Focus gets restored for a view hierarchy when the root of the hierarchy gets added to a 10893 * window or serves as a target of cluster navigation. 10894 * 10895 * @see #restoreDefaultFocus() 10896 * 10897 * @return {@code true} if this view is the default-focus view, {@code false} otherwise 10898 * @attr ref android.R.styleable#View_focusedByDefault 10899 */ 10900 @ViewDebug.ExportedProperty(category = "focus") 10901 public final boolean isFocusedByDefault() { 10902 return (mPrivateFlags3 & PFLAG3_FOCUSED_BY_DEFAULT) != 0; 10903 } 10904 10905 /** 10906 * Sets whether this View should receive focus when the focus is restored for the view 10907 * hierarchy containing this view. 10908 * <p> 10909 * Focus gets restored for a view hierarchy when the root of the hierarchy gets added to a 10910 * window or serves as a target of cluster navigation. 10911 * 10912 * @param isFocusedByDefault {@code true} to set this view as the default-focus view, 10913 * {@code false} otherwise. 10914 * 10915 * @see #restoreDefaultFocus() 10916 * 10917 * @attr ref android.R.styleable#View_focusedByDefault 10918 */ 10919 public void setFocusedByDefault(boolean isFocusedByDefault) { 10920 if (isFocusedByDefault == ((mPrivateFlags3 & PFLAG3_FOCUSED_BY_DEFAULT) != 0)) { 10921 return; 10922 } 10923 10924 if (isFocusedByDefault) { 10925 mPrivateFlags3 |= PFLAG3_FOCUSED_BY_DEFAULT; 10926 } else { 10927 mPrivateFlags3 &= ~PFLAG3_FOCUSED_BY_DEFAULT; 10928 } 10929 10930 if (mParent instanceof ViewGroup) { 10931 if (isFocusedByDefault) { 10932 ((ViewGroup) mParent).setDefaultFocus(this); 10933 } else { 10934 ((ViewGroup) mParent).clearDefaultFocus(this); 10935 } 10936 } 10937 } 10938 10939 /** 10940 * Returns whether the view hierarchy with this view as a root contain a default-focus view. 10941 * 10942 * @return {@code true} if this view has default focus, {@code false} otherwise 10943 */ 10944 boolean hasDefaultFocus() { 10945 return isFocusedByDefault(); 10946 } 10947 10948 /** 10949 * Find the nearest keyboard navigation cluster in the specified direction. 10950 * This does not actually give focus to that cluster. 10951 * 10952 * @param currentCluster The starting point of the search. Null means the current cluster is not 10953 * found yet 10954 * @param direction Direction to look 10955 * 10956 * @return The nearest keyboard navigation cluster in the specified direction, or null if none 10957 * can be found 10958 */ 10959 public View keyboardNavigationClusterSearch(View currentCluster, 10960 @FocusDirection int direction) { 10961 if (isKeyboardNavigationCluster()) { 10962 currentCluster = this; 10963 } 10964 if (isRootNamespace()) { 10965 // Root namespace means we should consider ourselves the top of the 10966 // tree for group searching; otherwise we could be group searching 10967 // into other tabs. see LocalActivityManager and TabHost for more info. 10968 return FocusFinder.getInstance().findNextKeyboardNavigationCluster( 10969 this, currentCluster, direction); 10970 } else if (mParent != null) { 10971 return mParent.keyboardNavigationClusterSearch(currentCluster, direction); 10972 } 10973 return null; 10974 } 10975 10976 /** 10977 * This method is the last chance for the focused view and its ancestors to 10978 * respond to an arrow key. This is called when the focused view did not 10979 * consume the key internally, nor could the view system find a new view in 10980 * the requested direction to give focus to. 10981 * 10982 * @param focused The currently focused view. 10983 * @param direction The direction focus wants to move. One of FOCUS_UP, 10984 * FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT. 10985 * @return True if the this view consumed this unhandled move. 10986 */ 10987 public boolean dispatchUnhandledMove(View focused, @FocusRealDirection int direction) { 10988 return false; 10989 } 10990 10991 /** 10992 * Sets whether this View should use a default focus highlight when it gets focused but doesn't 10993 * have {@link android.R.attr#state_focused} defined in its background. 10994 * 10995 * @param defaultFocusHighlightEnabled {@code true} to set this view to use a default focus 10996 * highlight, {@code false} otherwise. 10997 * 10998 * @attr ref android.R.styleable#View_defaultFocusHighlightEnabled 10999 */ 11000 public void setDefaultFocusHighlightEnabled(boolean defaultFocusHighlightEnabled) { 11001 mDefaultFocusHighlightEnabled = defaultFocusHighlightEnabled; 11002 } 11003 11004 /** 11005 11006 /** 11007 * Returns whether this View should use a default focus highlight when it gets focused but 11008 * doesn't have {@link android.R.attr#state_focused} defined in its background. 11009 * 11010 * @return True if this View should use a default focus highlight. 11011 * @attr ref android.R.styleable#View_defaultFocusHighlightEnabled 11012 */ 11013 @ViewDebug.ExportedProperty(category = "focus") 11014 public final boolean getDefaultFocusHighlightEnabled() { 11015 return mDefaultFocusHighlightEnabled; 11016 } 11017 11018 /** 11019 * If a user manually specified the next view id for a particular direction, 11020 * use the root to look up the view. 11021 * @param root The root view of the hierarchy containing this view. 11022 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, FOCUS_RIGHT, FOCUS_FORWARD, 11023 * or FOCUS_BACKWARD. 11024 * @return The user specified next view, or null if there is none. 11025 */ 11026 View findUserSetNextFocus(View root, @FocusDirection int direction) { 11027 switch (direction) { 11028 case FOCUS_LEFT: 11029 if (mNextFocusLeftId == View.NO_ID) return null; 11030 return findViewInsideOutShouldExist(root, mNextFocusLeftId); 11031 case FOCUS_RIGHT: 11032 if (mNextFocusRightId == View.NO_ID) return null; 11033 return findViewInsideOutShouldExist(root, mNextFocusRightId); 11034 case FOCUS_UP: 11035 if (mNextFocusUpId == View.NO_ID) return null; 11036 return findViewInsideOutShouldExist(root, mNextFocusUpId); 11037 case FOCUS_DOWN: 11038 if (mNextFocusDownId == View.NO_ID) return null; 11039 return findViewInsideOutShouldExist(root, mNextFocusDownId); 11040 case FOCUS_FORWARD: 11041 if (mNextFocusForwardId == View.NO_ID) return null; 11042 return findViewInsideOutShouldExist(root, mNextFocusForwardId); 11043 case FOCUS_BACKWARD: { 11044 if (mID == View.NO_ID) return null; 11045 final int id = mID; 11046 return root.findViewByPredicateInsideOut(this, new Predicate<View>() { 11047 @Override 11048 public boolean test(View t) { 11049 return t.mNextFocusForwardId == id; 11050 } 11051 }); 11052 } 11053 } 11054 return null; 11055 } 11056 11057 /** 11058 * If a user manually specified the next keyboard-navigation cluster for a particular direction, 11059 * use the root to look up the view. 11060 * 11061 * @param root the root view of the hierarchy containing this view 11062 * @param direction {@link #FOCUS_FORWARD} or {@link #FOCUS_BACKWARD} 11063 * @return the user-specified next cluster, or {@code null} if there is none 11064 */ 11065 View findUserSetNextKeyboardNavigationCluster(View root, @FocusDirection int direction) { 11066 switch (direction) { 11067 case FOCUS_FORWARD: 11068 if (mNextClusterForwardId == View.NO_ID) return null; 11069 return findViewInsideOutShouldExist(root, mNextClusterForwardId); 11070 case FOCUS_BACKWARD: { 11071 if (mID == View.NO_ID) return null; 11072 final int id = mID; 11073 return root.findViewByPredicateInsideOut(this, 11074 (Predicate<View>) t -> t.mNextClusterForwardId == id); 11075 } 11076 } 11077 return null; 11078 } 11079 11080 private View findViewInsideOutShouldExist(View root, int id) { 11081 if (mMatchIdPredicate == null) { 11082 mMatchIdPredicate = new MatchIdPredicate(); 11083 } 11084 mMatchIdPredicate.mId = id; 11085 View result = root.findViewByPredicateInsideOut(this, mMatchIdPredicate); 11086 if (result == null) { 11087 Log.w(VIEW_LOG_TAG, "couldn't find view with id " + id); 11088 } 11089 return result; 11090 } 11091 11092 /** 11093 * Find and return all focusable views that are descendants of this view, 11094 * possibly including this view if it is focusable itself. 11095 * 11096 * @param direction The direction of the focus 11097 * @return A list of focusable views 11098 */ 11099 public ArrayList<View> getFocusables(@FocusDirection int direction) { 11100 ArrayList<View> result = new ArrayList<View>(24); 11101 addFocusables(result, direction); 11102 return result; 11103 } 11104 11105 /** 11106 * Add any focusable views that are descendants of this view (possibly 11107 * including this view if it is focusable itself) to views. If we are in touch mode, 11108 * only add views that are also focusable in touch mode. 11109 * 11110 * @param views Focusable views found so far 11111 * @param direction The direction of the focus 11112 */ 11113 public void addFocusables(ArrayList<View> views, @FocusDirection int direction) { 11114 addFocusables(views, direction, isInTouchMode() ? FOCUSABLES_TOUCH_MODE : FOCUSABLES_ALL); 11115 } 11116 11117 /** 11118 * Adds any focusable views that are descendants of this view (possibly 11119 * including this view if it is focusable itself) to views. This method 11120 * adds all focusable views regardless if we are in touch mode or 11121 * only views focusable in touch mode if we are in touch mode or 11122 * only views that can take accessibility focus if accessibility is enabled 11123 * depending on the focusable mode parameter. 11124 * 11125 * @param views Focusable views found so far or null if all we are interested is 11126 * the number of focusables. 11127 * @param direction The direction of the focus. 11128 * @param focusableMode The type of focusables to be added. 11129 * 11130 * @see #FOCUSABLES_ALL 11131 * @see #FOCUSABLES_TOUCH_MODE 11132 */ 11133 public void addFocusables(ArrayList<View> views, @FocusDirection int direction, 11134 @FocusableMode int focusableMode) { 11135 if (views == null) { 11136 return; 11137 } 11138 if (!canTakeFocus()) { 11139 return; 11140 } 11141 if ((focusableMode & FOCUSABLES_TOUCH_MODE) == FOCUSABLES_TOUCH_MODE 11142 && !isFocusableInTouchMode()) { 11143 return; 11144 } 11145 views.add(this); 11146 } 11147 11148 /** 11149 * Adds any keyboard navigation cluster roots that are descendants of this view (possibly 11150 * including this view if it is a cluster root itself) to views. 11151 * 11152 * @param views Keyboard navigation cluster roots found so far 11153 * @param direction Direction to look 11154 */ 11155 public void addKeyboardNavigationClusters( 11156 @NonNull Collection<View> views, 11157 int direction) { 11158 if (!isKeyboardNavigationCluster()) { 11159 return; 11160 } 11161 if (!hasFocusable()) { 11162 return; 11163 } 11164 views.add(this); 11165 } 11166 11167 /** 11168 * Finds the Views that contain given text. The containment is case insensitive. 11169 * The search is performed by either the text that the View renders or the content 11170 * description that describes the view for accessibility purposes and the view does 11171 * not render or both. Clients can specify how the search is to be performed via 11172 * passing the {@link #FIND_VIEWS_WITH_TEXT} and 11173 * {@link #FIND_VIEWS_WITH_CONTENT_DESCRIPTION} flags. 11174 * 11175 * @param outViews The output list of matching Views. 11176 * @param searched The text to match against. 11177 * 11178 * @see #FIND_VIEWS_WITH_TEXT 11179 * @see #FIND_VIEWS_WITH_CONTENT_DESCRIPTION 11180 * @see #setContentDescription(CharSequence) 11181 */ 11182 public void findViewsWithText(ArrayList<View> outViews, CharSequence searched, 11183 @FindViewFlags int flags) { 11184 if (getAccessibilityNodeProvider() != null) { 11185 if ((flags & FIND_VIEWS_WITH_ACCESSIBILITY_NODE_PROVIDERS) != 0) { 11186 outViews.add(this); 11187 } 11188 } else if ((flags & FIND_VIEWS_WITH_CONTENT_DESCRIPTION) != 0 11189 && (searched != null && searched.length() > 0) 11190 && (mContentDescription != null && mContentDescription.length() > 0)) { 11191 String searchedLowerCase = searched.toString().toLowerCase(); 11192 String contentDescriptionLowerCase = mContentDescription.toString().toLowerCase(); 11193 if (contentDescriptionLowerCase.contains(searchedLowerCase)) { 11194 outViews.add(this); 11195 } 11196 } 11197 } 11198 11199 /** 11200 * Find and return all touchable views that are descendants of this view, 11201 * possibly including this view if it is touchable itself. 11202 * 11203 * @return A list of touchable views 11204 */ 11205 public ArrayList<View> getTouchables() { 11206 ArrayList<View> result = new ArrayList<View>(); 11207 addTouchables(result); 11208 return result; 11209 } 11210 11211 /** 11212 * Add any touchable views that are descendants of this view (possibly 11213 * including this view if it is touchable itself) to views. 11214 * 11215 * @param views Touchable views found so far 11216 */ 11217 public void addTouchables(ArrayList<View> views) { 11218 final int viewFlags = mViewFlags; 11219 11220 if (((viewFlags & CLICKABLE) == CLICKABLE || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE 11221 || (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE) 11222 && (viewFlags & ENABLED_MASK) == ENABLED) { 11223 views.add(this); 11224 } 11225 } 11226 11227 /** 11228 * Returns whether this View is accessibility focused. 11229 * 11230 * @return True if this View is accessibility focused. 11231 */ 11232 public boolean isAccessibilityFocused() { 11233 return (mPrivateFlags2 & PFLAG2_ACCESSIBILITY_FOCUSED) != 0; 11234 } 11235 11236 /** 11237 * Call this to try to give accessibility focus to this view. 11238 * 11239 * A view will not actually take focus if {@link AccessibilityManager#isEnabled()} 11240 * returns false or the view is no visible or the view already has accessibility 11241 * focus. 11242 * 11243 * See also {@link #focusSearch(int)}, which is what you call to say that you 11244 * have focus, and you want your parent to look for the next one. 11245 * 11246 * @return Whether this view actually took accessibility focus. 11247 * 11248 * @hide 11249 */ 11250 public boolean requestAccessibilityFocus() { 11251 AccessibilityManager manager = AccessibilityManager.getInstance(mContext); 11252 if (!manager.isEnabled() || !manager.isTouchExplorationEnabled()) { 11253 return false; 11254 } 11255 if ((mViewFlags & VISIBILITY_MASK) != VISIBLE) { 11256 return false; 11257 } 11258 if ((mPrivateFlags2 & PFLAG2_ACCESSIBILITY_FOCUSED) == 0) { 11259 mPrivateFlags2 |= PFLAG2_ACCESSIBILITY_FOCUSED; 11260 ViewRootImpl viewRootImpl = getViewRootImpl(); 11261 if (viewRootImpl != null) { 11262 viewRootImpl.setAccessibilityFocus(this, null); 11263 } 11264 invalidate(); 11265 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED); 11266 return true; 11267 } 11268 return false; 11269 } 11270 11271 /** 11272 * Call this to try to clear accessibility focus of this view. 11273 * 11274 * See also {@link #focusSearch(int)}, which is what you call to say that you 11275 * have focus, and you want your parent to look for the next one. 11276 * 11277 * @hide 11278 */ 11279 public void clearAccessibilityFocus() { 11280 clearAccessibilityFocusNoCallbacks(0); 11281 11282 // Clear the global reference of accessibility focus if this view or 11283 // any of its descendants had accessibility focus. This will NOT send 11284 // an event or update internal state if focus is cleared from a 11285 // descendant view, which may leave views in inconsistent states. 11286 final ViewRootImpl viewRootImpl = getViewRootImpl(); 11287 if (viewRootImpl != null) { 11288 final View focusHost = viewRootImpl.getAccessibilityFocusedHost(); 11289 if (focusHost != null && ViewRootImpl.isViewDescendantOf(focusHost, this)) { 11290 viewRootImpl.setAccessibilityFocus(null, null); 11291 } 11292 } 11293 } 11294 11295 private void sendAccessibilityHoverEvent(int eventType) { 11296 // Since we are not delivering to a client accessibility events from not 11297 // important views (unless the clinet request that) we need to fire the 11298 // event from the deepest view exposed to the client. As a consequence if 11299 // the user crosses a not exposed view the client will see enter and exit 11300 // of the exposed predecessor followed by and enter and exit of that same 11301 // predecessor when entering and exiting the not exposed descendant. This 11302 // is fine since the client has a clear idea which view is hovered at the 11303 // price of a couple more events being sent. This is a simple and 11304 // working solution. 11305 View source = this; 11306 while (true) { 11307 if (source.includeForAccessibility()) { 11308 source.sendAccessibilityEvent(eventType); 11309 return; 11310 } 11311 ViewParent parent = source.getParent(); 11312 if (parent instanceof View) { 11313 source = (View) parent; 11314 } else { 11315 return; 11316 } 11317 } 11318 } 11319 11320 /** 11321 * Clears accessibility focus without calling any callback methods 11322 * normally invoked in {@link #clearAccessibilityFocus()}. This method 11323 * is used separately from that one for clearing accessibility focus when 11324 * giving this focus to another view. 11325 * 11326 * @param action The action, if any, that led to focus being cleared. Set to 11327 * AccessibilityNodeInfo#ACTION_ACCESSIBILITY_FOCUS to specify that focus is moving within 11328 * the window. 11329 */ 11330 void clearAccessibilityFocusNoCallbacks(int action) { 11331 if ((mPrivateFlags2 & PFLAG2_ACCESSIBILITY_FOCUSED) != 0) { 11332 mPrivateFlags2 &= ~PFLAG2_ACCESSIBILITY_FOCUSED; 11333 invalidate(); 11334 if (AccessibilityManager.getInstance(mContext).isEnabled()) { 11335 AccessibilityEvent event = AccessibilityEvent.obtain( 11336 AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED); 11337 event.setAction(action); 11338 if (mAccessibilityDelegate != null) { 11339 mAccessibilityDelegate.sendAccessibilityEventUnchecked(this, event); 11340 } else { 11341 sendAccessibilityEventUnchecked(event); 11342 } 11343 } 11344 } 11345 } 11346 11347 /** 11348 * Call this to try to give focus to a specific view or to one of its 11349 * descendants. 11350 * 11351 * A view will not actually take focus if it is not focusable ({@link #isFocusable} returns 11352 * false), or if it can't be focused due to other conditions (not focusable in touch mode 11353 * ({@link #isFocusableInTouchMode}) while the device is in touch mode, not visible, not 11354 * enabled, or has no size). 11355 * 11356 * See also {@link #focusSearch(int)}, which is what you call to say that you 11357 * have focus, and you want your parent to look for the next one. 11358 * 11359 * This is equivalent to calling {@link #requestFocus(int, Rect)} with arguments 11360 * {@link #FOCUS_DOWN} and <code>null</code>. 11361 * 11362 * @return Whether this view or one of its descendants actually took focus. 11363 */ 11364 public final boolean requestFocus() { 11365 return requestFocus(View.FOCUS_DOWN); 11366 } 11367 11368 /** 11369 * This will request focus for whichever View was last focused within this 11370 * cluster before a focus-jump out of it. 11371 * 11372 * @hide 11373 */ 11374 @TestApi 11375 public boolean restoreFocusInCluster(@FocusRealDirection int direction) { 11376 // Prioritize focusableByDefault over algorithmic focus selection. 11377 if (restoreDefaultFocus()) { 11378 return true; 11379 } 11380 return requestFocus(direction); 11381 } 11382 11383 /** 11384 * This will request focus for whichever View not in a cluster was last focused before a 11385 * focus-jump to a cluster. If no non-cluster View has previously had focus, this will focus 11386 * the "first" focusable view it finds. 11387 * 11388 * @hide 11389 */ 11390 @TestApi 11391 public boolean restoreFocusNotInCluster() { 11392 return requestFocus(View.FOCUS_DOWN); 11393 } 11394 11395 /** 11396 * Gives focus to the default-focus view in the view hierarchy that has this view as a root. 11397 * If the default-focus view cannot be found, falls back to calling {@link #requestFocus(int)}. 11398 * 11399 * @return Whether this view or one of its descendants actually took focus 11400 */ 11401 public boolean restoreDefaultFocus() { 11402 return requestFocus(View.FOCUS_DOWN); 11403 } 11404 11405 /** 11406 * Call this to try to give focus to a specific view or to one of its 11407 * descendants and give it a hint about what direction focus is heading. 11408 * 11409 * A view will not actually take focus if it is not focusable ({@link #isFocusable} returns 11410 * false), or if it is focusable and it is not focusable in touch mode 11411 * ({@link #isFocusableInTouchMode}) while the device is in touch mode. 11412 * 11413 * See also {@link #focusSearch(int)}, which is what you call to say that you 11414 * have focus, and you want your parent to look for the next one. 11415 * 11416 * This is equivalent to calling {@link #requestFocus(int, Rect)} with 11417 * <code>null</code> set for the previously focused rectangle. 11418 * 11419 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT 11420 * @return Whether this view or one of its descendants actually took focus. 11421 */ 11422 public final boolean requestFocus(int direction) { 11423 return requestFocus(direction, null); 11424 } 11425 11426 /** 11427 * Call this to try to give focus to a specific view or to one of its descendants 11428 * and give it hints about the direction and a specific rectangle that the focus 11429 * is coming from. The rectangle can help give larger views a finer grained hint 11430 * about where focus is coming from, and therefore, where to show selection, or 11431 * forward focus change internally. 11432 * 11433 * A view will not actually take focus if it is not focusable ({@link #isFocusable} returns 11434 * false), or if it is focusable and it is not focusable in touch mode 11435 * ({@link #isFocusableInTouchMode}) while the device is in touch mode. 11436 * 11437 * A View will not take focus if it is not visible. 11438 * 11439 * A View will not take focus if one of its parents has 11440 * {@link android.view.ViewGroup#getDescendantFocusability()} equal to 11441 * {@link ViewGroup#FOCUS_BLOCK_DESCENDANTS}. 11442 * 11443 * See also {@link #focusSearch(int)}, which is what you call to say that you 11444 * have focus, and you want your parent to look for the next one. 11445 * 11446 * You may wish to override this method if your custom {@link View} has an internal 11447 * {@link View} that it wishes to forward the request to. 11448 * 11449 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT 11450 * @param previouslyFocusedRect The rectangle (in this View's coordinate system) 11451 * to give a finer grained hint about where focus is coming from. May be null 11452 * if there is no hint. 11453 * @return Whether this view or one of its descendants actually took focus. 11454 */ 11455 public boolean requestFocus(int direction, Rect previouslyFocusedRect) { 11456 return requestFocusNoSearch(direction, previouslyFocusedRect); 11457 } 11458 11459 private boolean requestFocusNoSearch(int direction, Rect previouslyFocusedRect) { 11460 // need to be focusable 11461 if (!canTakeFocus()) { 11462 return false; 11463 } 11464 11465 // need to be focusable in touch mode if in touch mode 11466 if (isInTouchMode() && 11467 (FOCUSABLE_IN_TOUCH_MODE != (mViewFlags & FOCUSABLE_IN_TOUCH_MODE))) { 11468 return false; 11469 } 11470 11471 // need to not have any parents blocking us 11472 if (hasAncestorThatBlocksDescendantFocus()) { 11473 return false; 11474 } 11475 11476 if (!isLayoutValid()) { 11477 mPrivateFlags |= PFLAG_WANTS_FOCUS; 11478 } else { 11479 clearParentsWantFocus(); 11480 } 11481 11482 handleFocusGainInternal(direction, previouslyFocusedRect); 11483 return true; 11484 } 11485 11486 void clearParentsWantFocus() { 11487 if (mParent instanceof View) { 11488 ((View) mParent).mPrivateFlags &= ~PFLAG_WANTS_FOCUS; 11489 ((View) mParent).clearParentsWantFocus(); 11490 } 11491 } 11492 11493 /** 11494 * Call this to try to give focus to a specific view or to one of its descendants. This is a 11495 * special variant of {@link #requestFocus() } that will allow views that are not focusable in 11496 * touch mode to request focus when they are touched. 11497 * 11498 * @return Whether this view or one of its descendants actually took focus. 11499 * 11500 * @see #isInTouchMode() 11501 * 11502 */ 11503 public final boolean requestFocusFromTouch() { 11504 // Leave touch mode if we need to 11505 if (isInTouchMode()) { 11506 ViewRootImpl viewRoot = getViewRootImpl(); 11507 if (viewRoot != null) { 11508 viewRoot.ensureTouchMode(false); 11509 } 11510 } 11511 return requestFocus(View.FOCUS_DOWN); 11512 } 11513 11514 /** 11515 * @return Whether any ancestor of this view blocks descendant focus. 11516 */ 11517 private boolean hasAncestorThatBlocksDescendantFocus() { 11518 final boolean focusableInTouchMode = isFocusableInTouchMode(); 11519 ViewParent ancestor = mParent; 11520 while (ancestor instanceof ViewGroup) { 11521 final ViewGroup vgAncestor = (ViewGroup) ancestor; 11522 if (vgAncestor.getDescendantFocusability() == ViewGroup.FOCUS_BLOCK_DESCENDANTS 11523 || (!focusableInTouchMode && vgAncestor.shouldBlockFocusForTouchscreen())) { 11524 return true; 11525 } else { 11526 ancestor = vgAncestor.getParent(); 11527 } 11528 } 11529 return false; 11530 } 11531 11532 /** 11533 * Gets the mode for determining whether this View is important for accessibility. 11534 * A view is important for accessibility if it fires accessibility events and if it 11535 * is reported to accessibility services that query the screen. 11536 * 11537 * @return The mode for determining whether a view is important for accessibility, one 11538 * of {@link #IMPORTANT_FOR_ACCESSIBILITY_AUTO}, {@link #IMPORTANT_FOR_ACCESSIBILITY_YES}, 11539 * {@link #IMPORTANT_FOR_ACCESSIBILITY_NO}, or 11540 * {@link #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS}. 11541 * 11542 * @attr ref android.R.styleable#View_importantForAccessibility 11543 * 11544 * @see #IMPORTANT_FOR_ACCESSIBILITY_YES 11545 * @see #IMPORTANT_FOR_ACCESSIBILITY_NO 11546 * @see #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS 11547 * @see #IMPORTANT_FOR_ACCESSIBILITY_AUTO 11548 */ 11549 @ViewDebug.ExportedProperty(category = "accessibility", mapping = { 11550 @ViewDebug.IntToString(from = IMPORTANT_FOR_ACCESSIBILITY_AUTO, to = "auto"), 11551 @ViewDebug.IntToString(from = IMPORTANT_FOR_ACCESSIBILITY_YES, to = "yes"), 11552 @ViewDebug.IntToString(from = IMPORTANT_FOR_ACCESSIBILITY_NO, to = "no"), 11553 @ViewDebug.IntToString(from = IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS, 11554 to = "noHideDescendants") 11555 }) 11556 public int getImportantForAccessibility() { 11557 return (mPrivateFlags2 & PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK) 11558 >> PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT; 11559 } 11560 11561 /** 11562 * Sets the live region mode for this view. This indicates to accessibility 11563 * services whether they should automatically notify the user about changes 11564 * to the view's content description or text, or to the content descriptions 11565 * or text of the view's children (where applicable). 11566 * <p> 11567 * For example, in a login screen with a TextView that displays an "incorrect 11568 * password" notification, that view should be marked as a live region with 11569 * mode {@link #ACCESSIBILITY_LIVE_REGION_POLITE}. 11570 * <p> 11571 * To disable change notifications for this view, use 11572 * {@link #ACCESSIBILITY_LIVE_REGION_NONE}. This is the default live region 11573 * mode for most views. 11574 * <p> 11575 * To indicate that the user should be notified of changes, use 11576 * {@link #ACCESSIBILITY_LIVE_REGION_POLITE}. 11577 * <p> 11578 * If the view's changes should interrupt ongoing speech and notify the user 11579 * immediately, use {@link #ACCESSIBILITY_LIVE_REGION_ASSERTIVE}. 11580 * 11581 * @param mode The live region mode for this view, one of: 11582 * <ul> 11583 * <li>{@link #ACCESSIBILITY_LIVE_REGION_NONE} 11584 * <li>{@link #ACCESSIBILITY_LIVE_REGION_POLITE} 11585 * <li>{@link #ACCESSIBILITY_LIVE_REGION_ASSERTIVE} 11586 * </ul> 11587 * @attr ref android.R.styleable#View_accessibilityLiveRegion 11588 */ 11589 public void setAccessibilityLiveRegion(int mode) { 11590 if (mode != getAccessibilityLiveRegion()) { 11591 mPrivateFlags2 &= ~PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK; 11592 mPrivateFlags2 |= (mode << PFLAG2_ACCESSIBILITY_LIVE_REGION_SHIFT) 11593 & PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK; 11594 notifyViewAccessibilityStateChangedIfNeeded( 11595 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 11596 } 11597 } 11598 11599 /** 11600 * Gets the live region mode for this View. 11601 * 11602 * @return The live region mode for the view. 11603 * 11604 * @attr ref android.R.styleable#View_accessibilityLiveRegion 11605 * 11606 * @see #setAccessibilityLiveRegion(int) 11607 */ 11608 public int getAccessibilityLiveRegion() { 11609 return (mPrivateFlags2 & PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK) 11610 >> PFLAG2_ACCESSIBILITY_LIVE_REGION_SHIFT; 11611 } 11612 11613 /** 11614 * Sets how to determine whether this view is important for accessibility 11615 * which is if it fires accessibility events and if it is reported to 11616 * accessibility services that query the screen. 11617 * 11618 * @param mode How to determine whether this view is important for accessibility. 11619 * 11620 * @attr ref android.R.styleable#View_importantForAccessibility 11621 * 11622 * @see #IMPORTANT_FOR_ACCESSIBILITY_YES 11623 * @see #IMPORTANT_FOR_ACCESSIBILITY_NO 11624 * @see #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS 11625 * @see #IMPORTANT_FOR_ACCESSIBILITY_AUTO 11626 */ 11627 public void setImportantForAccessibility(int mode) { 11628 final int oldMode = getImportantForAccessibility(); 11629 if (mode != oldMode) { 11630 final boolean hideDescendants = 11631 mode == IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS; 11632 11633 // If this node or its descendants are no longer important, try to 11634 // clear accessibility focus. 11635 if (mode == IMPORTANT_FOR_ACCESSIBILITY_NO || hideDescendants) { 11636 final View focusHost = findAccessibilityFocusHost(hideDescendants); 11637 if (focusHost != null) { 11638 focusHost.clearAccessibilityFocus(); 11639 } 11640 } 11641 11642 // If we're moving between AUTO and another state, we might not need 11643 // to send a subtree changed notification. We'll store the computed 11644 // importance, since we'll need to check it later to make sure. 11645 final boolean maySkipNotify = oldMode == IMPORTANT_FOR_ACCESSIBILITY_AUTO 11646 || mode == IMPORTANT_FOR_ACCESSIBILITY_AUTO; 11647 final boolean oldIncludeForAccessibility = maySkipNotify && includeForAccessibility(); 11648 mPrivateFlags2 &= ~PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK; 11649 mPrivateFlags2 |= (mode << PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT) 11650 & PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK; 11651 if (!maySkipNotify || oldIncludeForAccessibility != includeForAccessibility()) { 11652 notifySubtreeAccessibilityStateChangedIfNeeded(); 11653 } else { 11654 notifyViewAccessibilityStateChangedIfNeeded( 11655 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 11656 } 11657 } 11658 } 11659 11660 /** 11661 * Returns the view within this view's hierarchy that is hosting 11662 * accessibility focus. 11663 * 11664 * @param searchDescendants whether to search for focus in descendant views 11665 * @return the view hosting accessibility focus, or {@code null} 11666 */ 11667 private View findAccessibilityFocusHost(boolean searchDescendants) { 11668 if (isAccessibilityFocusedViewOrHost()) { 11669 return this; 11670 } 11671 11672 if (searchDescendants) { 11673 final ViewRootImpl viewRoot = getViewRootImpl(); 11674 if (viewRoot != null) { 11675 final View focusHost = viewRoot.getAccessibilityFocusedHost(); 11676 if (focusHost != null && ViewRootImpl.isViewDescendantOf(focusHost, this)) { 11677 return focusHost; 11678 } 11679 } 11680 } 11681 11682 return null; 11683 } 11684 11685 /** 11686 * Computes whether this view should be exposed for accessibility. In 11687 * general, views that are interactive or provide information are exposed 11688 * while views that serve only as containers are hidden. 11689 * <p> 11690 * If an ancestor of this view has importance 11691 * {@link #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS}, this method 11692 * returns <code>false</code>. 11693 * <p> 11694 * Otherwise, the value is computed according to the view's 11695 * {@link #getImportantForAccessibility()} value: 11696 * <ol> 11697 * <li>{@link #IMPORTANT_FOR_ACCESSIBILITY_NO} or 11698 * {@link #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS}, return <code>false 11699 * </code> 11700 * <li>{@link #IMPORTANT_FOR_ACCESSIBILITY_YES}, return <code>true</code> 11701 * <li>{@link #IMPORTANT_FOR_ACCESSIBILITY_AUTO}, return <code>true</code> if 11702 * view satisfies any of the following: 11703 * <ul> 11704 * <li>Is actionable, e.g. {@link #isClickable()}, 11705 * {@link #isLongClickable()}, or {@link #isFocusable()} 11706 * <li>Has an {@link AccessibilityDelegate} 11707 * <li>Has an interaction listener, e.g. {@link OnTouchListener}, 11708 * {@link OnKeyListener}, etc. 11709 * <li>Is an accessibility live region, e.g. 11710 * {@link #getAccessibilityLiveRegion()} is not 11711 * {@link #ACCESSIBILITY_LIVE_REGION_NONE}. 11712 * </ul> 11713 * <li>Has an accessibility pane title, see {@link #setAccessibilityPaneTitle}</li> 11714 * </ol> 11715 * 11716 * @return Whether the view is exposed for accessibility. 11717 * @see #setImportantForAccessibility(int) 11718 * @see #getImportantForAccessibility() 11719 */ 11720 public boolean isImportantForAccessibility() { 11721 final int mode = (mPrivateFlags2 & PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK) 11722 >> PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT; 11723 if (mode == IMPORTANT_FOR_ACCESSIBILITY_NO 11724 || mode == IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS) { 11725 return false; 11726 } 11727 11728 // Check parent mode to ensure we're not hidden. 11729 ViewParent parent = mParent; 11730 while (parent instanceof View) { 11731 if (((View) parent).getImportantForAccessibility() 11732 == IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS) { 11733 return false; 11734 } 11735 parent = parent.getParent(); 11736 } 11737 11738 return mode == IMPORTANT_FOR_ACCESSIBILITY_YES || isActionableForAccessibility() 11739 || hasListenersForAccessibility() || getAccessibilityNodeProvider() != null 11740 || getAccessibilityLiveRegion() != ACCESSIBILITY_LIVE_REGION_NONE 11741 || isAccessibilityPane(); 11742 } 11743 11744 /** 11745 * Gets the parent for accessibility purposes. Note that the parent for 11746 * accessibility is not necessary the immediate parent. It is the first 11747 * predecessor that is important for accessibility. 11748 * 11749 * @return The parent for accessibility purposes. 11750 */ 11751 public ViewParent getParentForAccessibility() { 11752 if (mParent instanceof View) { 11753 View parentView = (View) mParent; 11754 if (parentView.includeForAccessibility()) { 11755 return mParent; 11756 } else { 11757 return mParent.getParentForAccessibility(); 11758 } 11759 } 11760 return null; 11761 } 11762 11763 /** 11764 * Adds the children of this View relevant for accessibility to the given list 11765 * as output. Since some Views are not important for accessibility the added 11766 * child views are not necessarily direct children of this view, rather they are 11767 * the first level of descendants important for accessibility. 11768 * 11769 * @param outChildren The output list that will receive children for accessibility. 11770 */ 11771 public void addChildrenForAccessibility(ArrayList<View> outChildren) { 11772 11773 } 11774 11775 /** 11776 * Whether to regard this view for accessibility. A view is regarded for 11777 * accessibility if it is important for accessibility or the querying 11778 * accessibility service has explicitly requested that view not 11779 * important for accessibility are regarded. 11780 * 11781 * @return Whether to regard the view for accessibility. 11782 * 11783 * @hide 11784 */ 11785 public boolean includeForAccessibility() { 11786 if (mAttachInfo != null) { 11787 return (mAttachInfo.mAccessibilityFetchFlags 11788 & AccessibilityNodeInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS) != 0 11789 || isImportantForAccessibility(); 11790 } 11791 return false; 11792 } 11793 11794 /** 11795 * Returns whether the View is considered actionable from 11796 * accessibility perspective. Such view are important for 11797 * accessibility. 11798 * 11799 * @return True if the view is actionable for accessibility. 11800 * 11801 * @hide 11802 */ 11803 public boolean isActionableForAccessibility() { 11804 return (isClickable() || isLongClickable() || isFocusable()); 11805 } 11806 11807 /** 11808 * Returns whether the View has registered callbacks which makes it 11809 * important for accessibility. 11810 * 11811 * @return True if the view is actionable for accessibility. 11812 */ 11813 private boolean hasListenersForAccessibility() { 11814 ListenerInfo info = getListenerInfo(); 11815 return mTouchDelegate != null || info.mOnKeyListener != null 11816 || info.mOnTouchListener != null || info.mOnGenericMotionListener != null 11817 || info.mOnHoverListener != null || info.mOnDragListener != null; 11818 } 11819 11820 /** 11821 * Notifies that the accessibility state of this view changed. The change 11822 * is local to this view and does not represent structural changes such 11823 * as children and parent. For example, the view became focusable. The 11824 * notification is at at most once every 11825 * {@link ViewConfiguration#getSendRecurringAccessibilityEventsInterval()} 11826 * to avoid unnecessary load to the system. Also once a view has a pending 11827 * notification this method is a NOP until the notification has been sent. 11828 * 11829 * @hide 11830 */ 11831 public void notifyViewAccessibilityStateChangedIfNeeded(int changeType) { 11832 if (!AccessibilityManager.getInstance(mContext).isEnabled() || mAttachInfo == null) { 11833 return; 11834 } 11835 11836 // Changes to views with a pane title count as window state changes, as the pane title 11837 // marks them as significant parts of the UI. 11838 if ((changeType != AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE) 11839 && isAccessibilityPane()) { 11840 // If the pane isn't visible, content changed events are sufficient unless we're 11841 // reporting that the view just disappeared 11842 if ((getVisibility() == VISIBLE) 11843 || (changeType == AccessibilityEvent.CONTENT_CHANGE_TYPE_PANE_DISAPPEARED)) { 11844 final AccessibilityEvent event = AccessibilityEvent.obtain(); 11845 event.setEventType(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED); 11846 event.setContentChangeTypes(changeType); 11847 event.setSource(this); 11848 onPopulateAccessibilityEvent(event); 11849 if (mParent != null) { 11850 try { 11851 mParent.requestSendAccessibilityEvent(this, event); 11852 } catch (AbstractMethodError e) { 11853 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() 11854 + " does not fully implement ViewParent", e); 11855 } 11856 } 11857 return; 11858 } 11859 } 11860 11861 // If this is a live region, we should send a subtree change event 11862 // from this view immediately. Otherwise, we can let it propagate up. 11863 if (getAccessibilityLiveRegion() != ACCESSIBILITY_LIVE_REGION_NONE) { 11864 final AccessibilityEvent event = AccessibilityEvent.obtain(); 11865 event.setEventType(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED); 11866 event.setContentChangeTypes(changeType); 11867 sendAccessibilityEventUnchecked(event); 11868 } else if (mParent != null) { 11869 try { 11870 mParent.notifySubtreeAccessibilityStateChanged(this, this, changeType); 11871 } catch (AbstractMethodError e) { 11872 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 11873 " does not fully implement ViewParent", e); 11874 } 11875 } 11876 } 11877 11878 /** 11879 * Notifies that the accessibility state of this view changed. The change 11880 * is *not* local to this view and does represent structural changes such 11881 * as children and parent. For example, the view size changed. The 11882 * notification is at at most once every 11883 * {@link ViewConfiguration#getSendRecurringAccessibilityEventsInterval()} 11884 * to avoid unnecessary load to the system. Also once a view has a pending 11885 * notification this method is a NOP until the notification has been sent. 11886 * 11887 * @hide 11888 */ 11889 public void notifySubtreeAccessibilityStateChangedIfNeeded() { 11890 if (!AccessibilityManager.getInstance(mContext).isEnabled() || mAttachInfo == null) { 11891 return; 11892 } 11893 11894 if ((mPrivateFlags2 & PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED) == 0) { 11895 mPrivateFlags2 |= PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED; 11896 if (mParent != null) { 11897 try { 11898 mParent.notifySubtreeAccessibilityStateChanged( 11899 this, this, AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE); 11900 } catch (AbstractMethodError e) { 11901 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 11902 " does not fully implement ViewParent", e); 11903 } 11904 } 11905 } 11906 } 11907 11908 /** 11909 * Change the visibility of the View without triggering any other changes. This is 11910 * important for transitions, where visibility changes should not adjust focus or 11911 * trigger a new layout. This is only used when the visibility has already been changed 11912 * and we need a transient value during an animation. When the animation completes, 11913 * the original visibility value is always restored. 11914 * 11915 * @param visibility One of {@link #VISIBLE}, {@link #INVISIBLE}, or {@link #GONE}. 11916 * @hide 11917 */ 11918 public void setTransitionVisibility(@Visibility int visibility) { 11919 mViewFlags = (mViewFlags & ~View.VISIBILITY_MASK) | visibility; 11920 } 11921 11922 /** 11923 * Reset the flag indicating the accessibility state of the subtree rooted 11924 * at this view changed. 11925 */ 11926 void resetSubtreeAccessibilityStateChanged() { 11927 mPrivateFlags2 &= ~PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED; 11928 } 11929 11930 /** 11931 * Report an accessibility action to this view's parents for delegated processing. 11932 * 11933 * <p>Implementations of {@link #performAccessibilityAction(int, Bundle)} may internally 11934 * call this method to delegate an accessibility action to a supporting parent. If the parent 11935 * returns true from its 11936 * {@link ViewParent#onNestedPrePerformAccessibilityAction(View, int, android.os.Bundle)} 11937 * method this method will return true to signify that the action was consumed.</p> 11938 * 11939 * <p>This method is useful for implementing nested scrolling child views. If 11940 * {@link #isNestedScrollingEnabled()} returns true and the action is a scrolling action 11941 * a custom view implementation may invoke this method to allow a parent to consume the 11942 * scroll first. If this method returns true the custom view should skip its own scrolling 11943 * behavior.</p> 11944 * 11945 * @param action Accessibility action to delegate 11946 * @param arguments Optional action arguments 11947 * @return true if the action was consumed by a parent 11948 */ 11949 public boolean dispatchNestedPrePerformAccessibilityAction(int action, Bundle arguments) { 11950 for (ViewParent p = getParent(); p != null; p = p.getParent()) { 11951 if (p.onNestedPrePerformAccessibilityAction(this, action, arguments)) { 11952 return true; 11953 } 11954 } 11955 return false; 11956 } 11957 11958 /** 11959 * Performs the specified accessibility action on the view. For 11960 * possible accessibility actions look at {@link AccessibilityNodeInfo}. 11961 * <p> 11962 * If an {@link AccessibilityDelegate} has been specified via calling 11963 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 11964 * {@link AccessibilityDelegate#performAccessibilityAction(View, int, Bundle)} 11965 * is responsible for handling this call. 11966 * </p> 11967 * 11968 * <p>The default implementation will delegate 11969 * {@link AccessibilityNodeInfo#ACTION_SCROLL_BACKWARD} and 11970 * {@link AccessibilityNodeInfo#ACTION_SCROLL_FORWARD} to nested scrolling parents if 11971 * {@link #isNestedScrollingEnabled() nested scrolling is enabled} on this view.</p> 11972 * 11973 * @param action The action to perform. 11974 * @param arguments Optional action arguments. 11975 * @return Whether the action was performed. 11976 */ 11977 public boolean performAccessibilityAction(int action, Bundle arguments) { 11978 if (mAccessibilityDelegate != null) { 11979 return mAccessibilityDelegate.performAccessibilityAction(this, action, arguments); 11980 } else { 11981 return performAccessibilityActionInternal(action, arguments); 11982 } 11983 } 11984 11985 /** 11986 * @see #performAccessibilityAction(int, Bundle) 11987 * 11988 * Note: Called from the default {@link AccessibilityDelegate}. 11989 * 11990 * @hide 11991 */ 11992 public boolean performAccessibilityActionInternal(int action, Bundle arguments) { 11993 if (isNestedScrollingEnabled() 11994 && (action == AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD 11995 || action == AccessibilityNodeInfo.ACTION_SCROLL_FORWARD 11996 || action == R.id.accessibilityActionScrollUp 11997 || action == R.id.accessibilityActionScrollLeft 11998 || action == R.id.accessibilityActionScrollDown 11999 || action == R.id.accessibilityActionScrollRight)) { 12000 if (dispatchNestedPrePerformAccessibilityAction(action, arguments)) { 12001 return true; 12002 } 12003 } 12004 12005 switch (action) { 12006 case AccessibilityNodeInfo.ACTION_CLICK: { 12007 if (isClickable()) { 12008 performClickInternal(); 12009 return true; 12010 } 12011 } break; 12012 case AccessibilityNodeInfo.ACTION_LONG_CLICK: { 12013 if (isLongClickable()) { 12014 performLongClick(); 12015 return true; 12016 } 12017 } break; 12018 case AccessibilityNodeInfo.ACTION_FOCUS: { 12019 if (!hasFocus()) { 12020 // Get out of touch mode since accessibility 12021 // wants to move focus around. 12022 getViewRootImpl().ensureTouchMode(false); 12023 return requestFocus(); 12024 } 12025 } break; 12026 case AccessibilityNodeInfo.ACTION_CLEAR_FOCUS: { 12027 if (hasFocus()) { 12028 clearFocus(); 12029 return !isFocused(); 12030 } 12031 } break; 12032 case AccessibilityNodeInfo.ACTION_SELECT: { 12033 if (!isSelected()) { 12034 setSelected(true); 12035 return isSelected(); 12036 } 12037 } break; 12038 case AccessibilityNodeInfo.ACTION_CLEAR_SELECTION: { 12039 if (isSelected()) { 12040 setSelected(false); 12041 return !isSelected(); 12042 } 12043 } break; 12044 case AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS: { 12045 if (!isAccessibilityFocused()) { 12046 return requestAccessibilityFocus(); 12047 } 12048 } break; 12049 case AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS: { 12050 if (isAccessibilityFocused()) { 12051 clearAccessibilityFocus(); 12052 return true; 12053 } 12054 } break; 12055 case AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY: { 12056 if (arguments != null) { 12057 final int granularity = arguments.getInt( 12058 AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT); 12059 final boolean extendSelection = arguments.getBoolean( 12060 AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN); 12061 return traverseAtGranularity(granularity, true, extendSelection); 12062 } 12063 } break; 12064 case AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY: { 12065 if (arguments != null) { 12066 final int granularity = arguments.getInt( 12067 AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT); 12068 final boolean extendSelection = arguments.getBoolean( 12069 AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN); 12070 return traverseAtGranularity(granularity, false, extendSelection); 12071 } 12072 } break; 12073 case AccessibilityNodeInfo.ACTION_SET_SELECTION: { 12074 CharSequence text = getIterableTextForAccessibility(); 12075 if (text == null) { 12076 return false; 12077 } 12078 final int start = (arguments != null) ? arguments.getInt( 12079 AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT, -1) : -1; 12080 final int end = (arguments != null) ? arguments.getInt( 12081 AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT, -1) : -1; 12082 // Only cursor position can be specified (selection length == 0) 12083 if ((getAccessibilitySelectionStart() != start 12084 || getAccessibilitySelectionEnd() != end) 12085 && (start == end)) { 12086 setAccessibilitySelection(start, end); 12087 notifyViewAccessibilityStateChangedIfNeeded( 12088 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 12089 return true; 12090 } 12091 } break; 12092 case R.id.accessibilityActionShowOnScreen: { 12093 if (mAttachInfo != null) { 12094 final Rect r = mAttachInfo.mTmpInvalRect; 12095 getDrawingRect(r); 12096 return requestRectangleOnScreen(r, true); 12097 } 12098 } break; 12099 case R.id.accessibilityActionContextClick: { 12100 if (isContextClickable()) { 12101 performContextClick(); 12102 return true; 12103 } 12104 } break; 12105 case R.id.accessibilityActionShowTooltip: { 12106 if ((mTooltipInfo != null) && (mTooltipInfo.mTooltipPopup != null)) { 12107 // Tooltip already showing 12108 return false; 12109 } 12110 return showLongClickTooltip(0, 0); 12111 } 12112 case R.id.accessibilityActionHideTooltip: { 12113 if ((mTooltipInfo == null) || (mTooltipInfo.mTooltipPopup == null)) { 12114 // No tooltip showing 12115 return false; 12116 } 12117 hideTooltip(); 12118 return true; 12119 } 12120 } 12121 return false; 12122 } 12123 12124 private boolean traverseAtGranularity(int granularity, boolean forward, 12125 boolean extendSelection) { 12126 CharSequence text = getIterableTextForAccessibility(); 12127 if (text == null || text.length() == 0) { 12128 return false; 12129 } 12130 TextSegmentIterator iterator = getIteratorForGranularity(granularity); 12131 if (iterator == null) { 12132 return false; 12133 } 12134 int current = getAccessibilitySelectionEnd(); 12135 if (current == ACCESSIBILITY_CURSOR_POSITION_UNDEFINED) { 12136 current = forward ? 0 : text.length(); 12137 } 12138 final int[] range = forward ? iterator.following(current) : iterator.preceding(current); 12139 if (range == null) { 12140 return false; 12141 } 12142 final int segmentStart = range[0]; 12143 final int segmentEnd = range[1]; 12144 int selectionStart; 12145 int selectionEnd; 12146 if (extendSelection && isAccessibilitySelectionExtendable()) { 12147 selectionStart = getAccessibilitySelectionStart(); 12148 if (selectionStart == ACCESSIBILITY_CURSOR_POSITION_UNDEFINED) { 12149 selectionStart = forward ? segmentStart : segmentEnd; 12150 } 12151 selectionEnd = forward ? segmentEnd : segmentStart; 12152 } else { 12153 selectionStart = selectionEnd= forward ? segmentEnd : segmentStart; 12154 } 12155 setAccessibilitySelection(selectionStart, selectionEnd); 12156 final int action = forward ? AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY 12157 : AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY; 12158 sendViewTextTraversedAtGranularityEvent(action, granularity, segmentStart, segmentEnd); 12159 return true; 12160 } 12161 12162 /** 12163 * Gets the text reported for accessibility purposes. 12164 * 12165 * @return The accessibility text. 12166 * 12167 * @hide 12168 */ 12169 public CharSequence getIterableTextForAccessibility() { 12170 return getContentDescription(); 12171 } 12172 12173 /** 12174 * Gets whether accessibility selection can be extended. 12175 * 12176 * @return If selection is extensible. 12177 * 12178 * @hide 12179 */ 12180 public boolean isAccessibilitySelectionExtendable() { 12181 return false; 12182 } 12183 12184 /** 12185 * @hide 12186 */ 12187 public int getAccessibilitySelectionStart() { 12188 return mAccessibilityCursorPosition; 12189 } 12190 12191 /** 12192 * @hide 12193 */ 12194 public int getAccessibilitySelectionEnd() { 12195 return getAccessibilitySelectionStart(); 12196 } 12197 12198 /** 12199 * @hide 12200 */ 12201 public void setAccessibilitySelection(int start, int end) { 12202 if (start == end && end == mAccessibilityCursorPosition) { 12203 return; 12204 } 12205 if (start >= 0 && start == end && end <= getIterableTextForAccessibility().length()) { 12206 mAccessibilityCursorPosition = start; 12207 } else { 12208 mAccessibilityCursorPosition = ACCESSIBILITY_CURSOR_POSITION_UNDEFINED; 12209 } 12210 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED); 12211 } 12212 12213 private void sendViewTextTraversedAtGranularityEvent(int action, int granularity, 12214 int fromIndex, int toIndex) { 12215 if (mParent == null) { 12216 return; 12217 } 12218 AccessibilityEvent event = AccessibilityEvent.obtain( 12219 AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY); 12220 onInitializeAccessibilityEvent(event); 12221 onPopulateAccessibilityEvent(event); 12222 event.setFromIndex(fromIndex); 12223 event.setToIndex(toIndex); 12224 event.setAction(action); 12225 event.setMovementGranularity(granularity); 12226 mParent.requestSendAccessibilityEvent(this, event); 12227 } 12228 12229 /** 12230 * @hide 12231 */ 12232 public TextSegmentIterator getIteratorForGranularity(int granularity) { 12233 switch (granularity) { 12234 case AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER: { 12235 CharSequence text = getIterableTextForAccessibility(); 12236 if (text != null && text.length() > 0) { 12237 CharacterTextSegmentIterator iterator = 12238 CharacterTextSegmentIterator.getInstance( 12239 mContext.getResources().getConfiguration().locale); 12240 iterator.initialize(text.toString()); 12241 return iterator; 12242 } 12243 } break; 12244 case AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD: { 12245 CharSequence text = getIterableTextForAccessibility(); 12246 if (text != null && text.length() > 0) { 12247 WordTextSegmentIterator iterator = 12248 WordTextSegmentIterator.getInstance( 12249 mContext.getResources().getConfiguration().locale); 12250 iterator.initialize(text.toString()); 12251 return iterator; 12252 } 12253 } break; 12254 case AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH: { 12255 CharSequence text = getIterableTextForAccessibility(); 12256 if (text != null && text.length() > 0) { 12257 ParagraphTextSegmentIterator iterator = 12258 ParagraphTextSegmentIterator.getInstance(); 12259 iterator.initialize(text.toString()); 12260 return iterator; 12261 } 12262 } break; 12263 } 12264 return null; 12265 } 12266 12267 /** 12268 * Tells whether the {@link View} is in the state between {@link #onStartTemporaryDetach()} 12269 * and {@link #onFinishTemporaryDetach()}. 12270 * 12271 * <p>This method always returns {@code true} when called directly or indirectly from 12272 * {@link #onStartTemporaryDetach()}. The return value when called directly or indirectly from 12273 * {@link #onFinishTemporaryDetach()}, however, depends on the OS version. 12274 * <ul> 12275 * <li>{@code true} on {@link android.os.Build.VERSION_CODES#N API 24}</li> 12276 * <li>{@code false} on {@link android.os.Build.VERSION_CODES#N_MR1 API 25}} and later</li> 12277 * </ul> 12278 * </p> 12279 * 12280 * @return {@code true} when the View is in the state between {@link #onStartTemporaryDetach()} 12281 * and {@link #onFinishTemporaryDetach()}. 12282 */ 12283 public final boolean isTemporarilyDetached() { 12284 return (mPrivateFlags3 & PFLAG3_TEMPORARY_DETACH) != 0; 12285 } 12286 12287 /** 12288 * Dispatch {@link #onStartTemporaryDetach()} to this View and its direct children if this is 12289 * a container View. 12290 */ 12291 @CallSuper 12292 public void dispatchStartTemporaryDetach() { 12293 mPrivateFlags3 |= PFLAG3_TEMPORARY_DETACH; 12294 notifyEnterOrExitForAutoFillIfNeeded(false); 12295 onStartTemporaryDetach(); 12296 } 12297 12298 /** 12299 * This is called when a container is going to temporarily detach a child, with 12300 * {@link ViewGroup#detachViewFromParent(View) ViewGroup.detachViewFromParent}. 12301 * It will either be followed by {@link #onFinishTemporaryDetach()} or 12302 * {@link #onDetachedFromWindow()} when the container is done. 12303 */ 12304 public void onStartTemporaryDetach() { 12305 removeUnsetPressCallback(); 12306 mPrivateFlags |= PFLAG_CANCEL_NEXT_UP_EVENT; 12307 } 12308 12309 /** 12310 * Dispatch {@link #onFinishTemporaryDetach()} to this View and its direct children if this is 12311 * a container View. 12312 */ 12313 @CallSuper 12314 public void dispatchFinishTemporaryDetach() { 12315 mPrivateFlags3 &= ~PFLAG3_TEMPORARY_DETACH; 12316 onFinishTemporaryDetach(); 12317 if (hasWindowFocus() && hasFocus()) { 12318 InputMethodManager.getInstance().focusIn(this); 12319 } 12320 notifyEnterOrExitForAutoFillIfNeeded(true); 12321 } 12322 12323 /** 12324 * Called after {@link #onStartTemporaryDetach} when the container is done 12325 * changing the view. 12326 */ 12327 public void onFinishTemporaryDetach() { 12328 } 12329 12330 /** 12331 * Return the global {@link KeyEvent.DispatcherState KeyEvent.DispatcherState} 12332 * for this view's window. Returns null if the view is not currently attached 12333 * to the window. Normally you will not need to use this directly, but 12334 * just use the standard high-level event callbacks like 12335 * {@link #onKeyDown(int, KeyEvent)}. 12336 */ 12337 public KeyEvent.DispatcherState getKeyDispatcherState() { 12338 return mAttachInfo != null ? mAttachInfo.mKeyDispatchState : null; 12339 } 12340 12341 /** 12342 * Dispatch a key event before it is processed by any input method 12343 * associated with the view hierarchy. This can be used to intercept 12344 * key events in special situations before the IME consumes them; a 12345 * typical example would be handling the BACK key to update the application's 12346 * UI instead of allowing the IME to see it and close itself. 12347 * 12348 * @param event The key event to be dispatched. 12349 * @return True if the event was handled, false otherwise. 12350 */ 12351 public boolean dispatchKeyEventPreIme(KeyEvent event) { 12352 return onKeyPreIme(event.getKeyCode(), event); 12353 } 12354 12355 /** 12356 * Dispatch a key event to the next view on the focus path. This path runs 12357 * from the top of the view tree down to the currently focused view. If this 12358 * view has focus, it will dispatch to itself. Otherwise it will dispatch 12359 * the next node down the focus path. This method also fires any key 12360 * listeners. 12361 * 12362 * @param event The key event to be dispatched. 12363 * @return True if the event was handled, false otherwise. 12364 */ 12365 public boolean dispatchKeyEvent(KeyEvent event) { 12366 if (mInputEventConsistencyVerifier != null) { 12367 mInputEventConsistencyVerifier.onKeyEvent(event, 0); 12368 } 12369 12370 // Give any attached key listener a first crack at the event. 12371 //noinspection SimplifiableIfStatement 12372 ListenerInfo li = mListenerInfo; 12373 if (li != null && li.mOnKeyListener != null && (mViewFlags & ENABLED_MASK) == ENABLED 12374 && li.mOnKeyListener.onKey(this, event.getKeyCode(), event)) { 12375 return true; 12376 } 12377 12378 if (event.dispatch(this, mAttachInfo != null 12379 ? mAttachInfo.mKeyDispatchState : null, this)) { 12380 return true; 12381 } 12382 12383 if (mInputEventConsistencyVerifier != null) { 12384 mInputEventConsistencyVerifier.onUnhandledEvent(event, 0); 12385 } 12386 return false; 12387 } 12388 12389 /** 12390 * Dispatches a key shortcut event. 12391 * 12392 * @param event The key event to be dispatched. 12393 * @return True if the event was handled by the view, false otherwise. 12394 */ 12395 public boolean dispatchKeyShortcutEvent(KeyEvent event) { 12396 return onKeyShortcut(event.getKeyCode(), event); 12397 } 12398 12399 /** 12400 * Pass the touch screen motion event down to the target view, or this 12401 * view if it is the target. 12402 * 12403 * @param event The motion event to be dispatched. 12404 * @return True if the event was handled by the view, false otherwise. 12405 */ 12406 public boolean dispatchTouchEvent(MotionEvent event) { 12407 // If the event should be handled by accessibility focus first. 12408 if (event.isTargetAccessibilityFocus()) { 12409 // We don't have focus or no virtual descendant has it, do not handle the event. 12410 if (!isAccessibilityFocusedViewOrHost()) { 12411 return false; 12412 } 12413 // We have focus and got the event, then use normal event dispatch. 12414 event.setTargetAccessibilityFocus(false); 12415 } 12416 12417 boolean result = false; 12418 12419 if (mInputEventConsistencyVerifier != null) { 12420 mInputEventConsistencyVerifier.onTouchEvent(event, 0); 12421 } 12422 12423 final int actionMasked = event.getActionMasked(); 12424 if (actionMasked == MotionEvent.ACTION_DOWN) { 12425 // Defensive cleanup for new gesture 12426 stopNestedScroll(); 12427 } 12428 12429 if (onFilterTouchEventForSecurity(event)) { 12430 if ((mViewFlags & ENABLED_MASK) == ENABLED && handleScrollBarDragging(event)) { 12431 result = true; 12432 } 12433 //noinspection SimplifiableIfStatement 12434 ListenerInfo li = mListenerInfo; 12435 if (li != null && li.mOnTouchListener != null 12436 && (mViewFlags & ENABLED_MASK) == ENABLED 12437 && li.mOnTouchListener.onTouch(this, event)) { 12438 result = true; 12439 } 12440 12441 if (!result && onTouchEvent(event)) { 12442 result = true; 12443 } 12444 } 12445 12446 if (!result && mInputEventConsistencyVerifier != null) { 12447 mInputEventConsistencyVerifier.onUnhandledEvent(event, 0); 12448 } 12449 12450 // Clean up after nested scrolls if this is the end of a gesture; 12451 // also cancel it if we tried an ACTION_DOWN but we didn't want the rest 12452 // of the gesture. 12453 if (actionMasked == MotionEvent.ACTION_UP || 12454 actionMasked == MotionEvent.ACTION_CANCEL || 12455 (actionMasked == MotionEvent.ACTION_DOWN && !result)) { 12456 stopNestedScroll(); 12457 } 12458 12459 return result; 12460 } 12461 12462 boolean isAccessibilityFocusedViewOrHost() { 12463 return isAccessibilityFocused() || (getViewRootImpl() != null && getViewRootImpl() 12464 .getAccessibilityFocusedHost() == this); 12465 } 12466 12467 /** 12468 * Filter the touch event to apply security policies. 12469 * 12470 * @param event The motion event to be filtered. 12471 * @return True if the event should be dispatched, false if the event should be dropped. 12472 * 12473 * @see #getFilterTouchesWhenObscured 12474 */ 12475 public boolean onFilterTouchEventForSecurity(MotionEvent event) { 12476 //noinspection RedundantIfStatement 12477 if ((mViewFlags & FILTER_TOUCHES_WHEN_OBSCURED) != 0 12478 && (event.getFlags() & MotionEvent.FLAG_WINDOW_IS_OBSCURED) != 0) { 12479 // Window is obscured, drop this touch. 12480 return false; 12481 } 12482 return true; 12483 } 12484 12485 /** 12486 * Pass a trackball motion event down to the focused view. 12487 * 12488 * @param event The motion event to be dispatched. 12489 * @return True if the event was handled by the view, false otherwise. 12490 */ 12491 public boolean dispatchTrackballEvent(MotionEvent event) { 12492 if (mInputEventConsistencyVerifier != null) { 12493 mInputEventConsistencyVerifier.onTrackballEvent(event, 0); 12494 } 12495 12496 return onTrackballEvent(event); 12497 } 12498 12499 /** 12500 * Pass a captured pointer event down to the focused view. 12501 * 12502 * @param event The motion event to be dispatched. 12503 * @return True if the event was handled by the view, false otherwise. 12504 */ 12505 public boolean dispatchCapturedPointerEvent(MotionEvent event) { 12506 if (!hasPointerCapture()) { 12507 return false; 12508 } 12509 //noinspection SimplifiableIfStatement 12510 ListenerInfo li = mListenerInfo; 12511 if (li != null && li.mOnCapturedPointerListener != null 12512 && li.mOnCapturedPointerListener.onCapturedPointer(this, event)) { 12513 return true; 12514 } 12515 return onCapturedPointerEvent(event); 12516 } 12517 12518 /** 12519 * Dispatch a generic motion event. 12520 * <p> 12521 * Generic motion events with source class {@link InputDevice#SOURCE_CLASS_POINTER} 12522 * are delivered to the view under the pointer. All other generic motion events are 12523 * delivered to the focused view. Hover events are handled specially and are delivered 12524 * to {@link #onHoverEvent(MotionEvent)}. 12525 * </p> 12526 * 12527 * @param event The motion event to be dispatched. 12528 * @return True if the event was handled by the view, false otherwise. 12529 */ 12530 public boolean dispatchGenericMotionEvent(MotionEvent event) { 12531 if (mInputEventConsistencyVerifier != null) { 12532 mInputEventConsistencyVerifier.onGenericMotionEvent(event, 0); 12533 } 12534 12535 final int source = event.getSource(); 12536 if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) { 12537 final int action = event.getAction(); 12538 if (action == MotionEvent.ACTION_HOVER_ENTER 12539 || action == MotionEvent.ACTION_HOVER_MOVE 12540 || action == MotionEvent.ACTION_HOVER_EXIT) { 12541 if (dispatchHoverEvent(event)) { 12542 return true; 12543 } 12544 } else if (dispatchGenericPointerEvent(event)) { 12545 return true; 12546 } 12547 } else if (dispatchGenericFocusedEvent(event)) { 12548 return true; 12549 } 12550 12551 if (dispatchGenericMotionEventInternal(event)) { 12552 return true; 12553 } 12554 12555 if (mInputEventConsistencyVerifier != null) { 12556 mInputEventConsistencyVerifier.onUnhandledEvent(event, 0); 12557 } 12558 return false; 12559 } 12560 12561 private boolean dispatchGenericMotionEventInternal(MotionEvent event) { 12562 //noinspection SimplifiableIfStatement 12563 ListenerInfo li = mListenerInfo; 12564 if (li != null && li.mOnGenericMotionListener != null 12565 && (mViewFlags & ENABLED_MASK) == ENABLED 12566 && li.mOnGenericMotionListener.onGenericMotion(this, event)) { 12567 return true; 12568 } 12569 12570 if (onGenericMotionEvent(event)) { 12571 return true; 12572 } 12573 12574 final int actionButton = event.getActionButton(); 12575 switch (event.getActionMasked()) { 12576 case MotionEvent.ACTION_BUTTON_PRESS: 12577 if (isContextClickable() && !mInContextButtonPress && !mHasPerformedLongPress 12578 && (actionButton == MotionEvent.BUTTON_STYLUS_PRIMARY 12579 || actionButton == MotionEvent.BUTTON_SECONDARY)) { 12580 if (performContextClick(event.getX(), event.getY())) { 12581 mInContextButtonPress = true; 12582 setPressed(true, event.getX(), event.getY()); 12583 removeTapCallback(); 12584 removeLongPressCallback(); 12585 return true; 12586 } 12587 } 12588 break; 12589 12590 case MotionEvent.ACTION_BUTTON_RELEASE: 12591 if (mInContextButtonPress && (actionButton == MotionEvent.BUTTON_STYLUS_PRIMARY 12592 || actionButton == MotionEvent.BUTTON_SECONDARY)) { 12593 mInContextButtonPress = false; 12594 mIgnoreNextUpEvent = true; 12595 } 12596 break; 12597 } 12598 12599 if (mInputEventConsistencyVerifier != null) { 12600 mInputEventConsistencyVerifier.onUnhandledEvent(event, 0); 12601 } 12602 return false; 12603 } 12604 12605 /** 12606 * Dispatch a hover event. 12607 * <p> 12608 * Do not call this method directly. 12609 * Call {@link #dispatchGenericMotionEvent(MotionEvent)} instead. 12610 * </p> 12611 * 12612 * @param event The motion event to be dispatched. 12613 * @return True if the event was handled by the view, false otherwise. 12614 */ 12615 protected boolean dispatchHoverEvent(MotionEvent event) { 12616 ListenerInfo li = mListenerInfo; 12617 //noinspection SimplifiableIfStatement 12618 if (li != null && li.mOnHoverListener != null 12619 && (mViewFlags & ENABLED_MASK) == ENABLED 12620 && li.mOnHoverListener.onHover(this, event)) { 12621 return true; 12622 } 12623 12624 return onHoverEvent(event); 12625 } 12626 12627 /** 12628 * Returns true if the view has a child to which it has recently sent 12629 * {@link MotionEvent#ACTION_HOVER_ENTER}. If this view is hovered and 12630 * it does not have a hovered child, then it must be the innermost hovered view. 12631 * @hide 12632 */ 12633 protected boolean hasHoveredChild() { 12634 return false; 12635 } 12636 12637 /** 12638 * Dispatch a generic motion event to the view under the first pointer. 12639 * <p> 12640 * Do not call this method directly. 12641 * Call {@link #dispatchGenericMotionEvent(MotionEvent)} instead. 12642 * </p> 12643 * 12644 * @param event The motion event to be dispatched. 12645 * @return True if the event was handled by the view, false otherwise. 12646 */ 12647 protected boolean dispatchGenericPointerEvent(MotionEvent event) { 12648 return false; 12649 } 12650 12651 /** 12652 * Dispatch a generic motion event to the currently focused view. 12653 * <p> 12654 * Do not call this method directly. 12655 * Call {@link #dispatchGenericMotionEvent(MotionEvent)} instead. 12656 * </p> 12657 * 12658 * @param event The motion event to be dispatched. 12659 * @return True if the event was handled by the view, false otherwise. 12660 */ 12661 protected boolean dispatchGenericFocusedEvent(MotionEvent event) { 12662 return false; 12663 } 12664 12665 /** 12666 * Dispatch a pointer event. 12667 * <p> 12668 * Dispatches touch related pointer events to {@link #onTouchEvent(MotionEvent)} and all 12669 * other events to {@link #onGenericMotionEvent(MotionEvent)}. This separation of concerns 12670 * reinforces the invariant that {@link #onTouchEvent(MotionEvent)} is really about touches 12671 * and should not be expected to handle other pointing device features. 12672 * </p> 12673 * 12674 * @param event The motion event to be dispatched. 12675 * @return True if the event was handled by the view, false otherwise. 12676 * @hide 12677 */ 12678 public final boolean dispatchPointerEvent(MotionEvent event) { 12679 if (event.isTouchEvent()) { 12680 return dispatchTouchEvent(event); 12681 } else { 12682 return dispatchGenericMotionEvent(event); 12683 } 12684 } 12685 12686 /** 12687 * Called when the window containing this view gains or loses window focus. 12688 * ViewGroups should override to route to their children. 12689 * 12690 * @param hasFocus True if the window containing this view now has focus, 12691 * false otherwise. 12692 */ 12693 public void dispatchWindowFocusChanged(boolean hasFocus) { 12694 onWindowFocusChanged(hasFocus); 12695 } 12696 12697 /** 12698 * Called when the window containing this view gains or loses focus. Note 12699 * that this is separate from view focus: to receive key events, both 12700 * your view and its window must have focus. If a window is displayed 12701 * on top of yours that takes input focus, then your own window will lose 12702 * focus but the view focus will remain unchanged. 12703 * 12704 * @param hasWindowFocus True if the window containing this view now has 12705 * focus, false otherwise. 12706 */ 12707 public void onWindowFocusChanged(boolean hasWindowFocus) { 12708 InputMethodManager imm = InputMethodManager.peekInstance(); 12709 if (!hasWindowFocus) { 12710 if (isPressed()) { 12711 setPressed(false); 12712 } 12713 mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN; 12714 if (imm != null && (mPrivateFlags & PFLAG_FOCUSED) != 0) { 12715 imm.focusOut(this); 12716 } 12717 removeLongPressCallback(); 12718 removeTapCallback(); 12719 onFocusLost(); 12720 } else if (imm != null && (mPrivateFlags & PFLAG_FOCUSED) != 0) { 12721 imm.focusIn(this); 12722 } 12723 12724 refreshDrawableState(); 12725 } 12726 12727 /** 12728 * Returns true if this view is in a window that currently has window focus. 12729 * Note that this is not the same as the view itself having focus. 12730 * 12731 * @return True if this view is in a window that currently has window focus. 12732 */ 12733 public boolean hasWindowFocus() { 12734 return mAttachInfo != null && mAttachInfo.mHasWindowFocus; 12735 } 12736 12737 /** 12738 * Dispatch a view visibility change down the view hierarchy. 12739 * ViewGroups should override to route to their children. 12740 * @param changedView The view whose visibility changed. Could be 'this' or 12741 * an ancestor view. 12742 * @param visibility The new visibility of changedView: {@link #VISIBLE}, 12743 * {@link #INVISIBLE} or {@link #GONE}. 12744 */ 12745 protected void dispatchVisibilityChanged(@NonNull View changedView, 12746 @Visibility int visibility) { 12747 onVisibilityChanged(changedView, visibility); 12748 } 12749 12750 /** 12751 * Called when the visibility of the view or an ancestor of the view has 12752 * changed. 12753 * 12754 * @param changedView The view whose visibility changed. May be 12755 * {@code this} or an ancestor view. 12756 * @param visibility The new visibility, one of {@link #VISIBLE}, 12757 * {@link #INVISIBLE} or {@link #GONE}. 12758 */ 12759 protected void onVisibilityChanged(@NonNull View changedView, @Visibility int visibility) { 12760 } 12761 12762 /** 12763 * Dispatch a hint about whether this view is displayed. For instance, when 12764 * a View moves out of the screen, it might receives a display hint indicating 12765 * the view is not displayed. Applications should not <em>rely</em> on this hint 12766 * as there is no guarantee that they will receive one. 12767 * 12768 * @param hint A hint about whether or not this view is displayed: 12769 * {@link #VISIBLE} or {@link #INVISIBLE}. 12770 */ 12771 public void dispatchDisplayHint(@Visibility int hint) { 12772 onDisplayHint(hint); 12773 } 12774 12775 /** 12776 * Gives this view a hint about whether is displayed or not. For instance, when 12777 * a View moves out of the screen, it might receives a display hint indicating 12778 * the view is not displayed. Applications should not <em>rely</em> on this hint 12779 * as there is no guarantee that they will receive one. 12780 * 12781 * @param hint A hint about whether or not this view is displayed: 12782 * {@link #VISIBLE} or {@link #INVISIBLE}. 12783 */ 12784 protected void onDisplayHint(@Visibility int hint) { 12785 } 12786 12787 /** 12788 * Dispatch a window visibility change down the view hierarchy. 12789 * ViewGroups should override to route to their children. 12790 * 12791 * @param visibility The new visibility of the window. 12792 * 12793 * @see #onWindowVisibilityChanged(int) 12794 */ 12795 public void dispatchWindowVisibilityChanged(@Visibility int visibility) { 12796 onWindowVisibilityChanged(visibility); 12797 } 12798 12799 /** 12800 * Called when the window containing has change its visibility 12801 * (between {@link #GONE}, {@link #INVISIBLE}, and {@link #VISIBLE}). Note 12802 * that this tells you whether or not your window is being made visible 12803 * to the window manager; this does <em>not</em> tell you whether or not 12804 * your window is obscured by other windows on the screen, even if it 12805 * is itself visible. 12806 * 12807 * @param visibility The new visibility of the window. 12808 */ 12809 protected void onWindowVisibilityChanged(@Visibility int visibility) { 12810 if (visibility == VISIBLE) { 12811 initialAwakenScrollBars(); 12812 } 12813 } 12814 12815 /** 12816 * Internal dispatching method for {@link #onVisibilityAggregated}. Overridden by 12817 * ViewGroup. Intended to only be called when {@link #isAttachedToWindow()}, 12818 * {@link #getWindowVisibility()} is {@link #VISIBLE} and this view's parent {@link #isShown()}. 12819 * 12820 * @param isVisible true if this view's visibility to the user is uninterrupted by its 12821 * ancestors or by window visibility 12822 * @return true if this view is visible to the user, not counting clipping or overlapping 12823 */ 12824 boolean dispatchVisibilityAggregated(boolean isVisible) { 12825 final boolean thisVisible = getVisibility() == VISIBLE; 12826 // If we're not visible but something is telling us we are, ignore it. 12827 if (thisVisible || !isVisible) { 12828 onVisibilityAggregated(isVisible); 12829 } 12830 return thisVisible && isVisible; 12831 } 12832 12833 /** 12834 * Called when the user-visibility of this View is potentially affected by a change 12835 * to this view itself, an ancestor view or the window this view is attached to. 12836 * 12837 * @param isVisible true if this view and all of its ancestors are {@link #VISIBLE} 12838 * and this view's window is also visible 12839 */ 12840 @CallSuper 12841 public void onVisibilityAggregated(boolean isVisible) { 12842 // Update our internal visibility tracking so we can detect changes 12843 boolean oldVisible = (mPrivateFlags3 & PFLAG3_AGGREGATED_VISIBLE) != 0; 12844 mPrivateFlags3 = isVisible ? (mPrivateFlags3 | PFLAG3_AGGREGATED_VISIBLE) 12845 : (mPrivateFlags3 & ~PFLAG3_AGGREGATED_VISIBLE); 12846 if (isVisible && mAttachInfo != null) { 12847 initialAwakenScrollBars(); 12848 } 12849 12850 final Drawable dr = mBackground; 12851 if (dr != null && isVisible != dr.isVisible()) { 12852 dr.setVisible(isVisible, false); 12853 } 12854 final Drawable hl = mDefaultFocusHighlight; 12855 if (hl != null && isVisible != hl.isVisible()) { 12856 hl.setVisible(isVisible, false); 12857 } 12858 final Drawable fg = mForegroundInfo != null ? mForegroundInfo.mDrawable : null; 12859 if (fg != null && isVisible != fg.isVisible()) { 12860 fg.setVisible(isVisible, false); 12861 } 12862 12863 if (isAutofillable()) { 12864 AutofillManager afm = getAutofillManager(); 12865 12866 if (afm != null && getAutofillViewId() > LAST_APP_AUTOFILL_ID) { 12867 if (mVisibilityChangeForAutofillHandler != null) { 12868 mVisibilityChangeForAutofillHandler.removeMessages(0); 12869 } 12870 12871 // If the view is in the background but still part of the hierarchy this is called 12872 // with isVisible=false. Hence visibility==false requires further checks 12873 if (isVisible) { 12874 afm.notifyViewVisibilityChanged(this, true); 12875 } else { 12876 if (mVisibilityChangeForAutofillHandler == null) { 12877 mVisibilityChangeForAutofillHandler = 12878 new VisibilityChangeForAutofillHandler(afm, this); 12879 } 12880 // Let current operation (e.g. removal of the view from the hierarchy) 12881 // finish before checking state 12882 mVisibilityChangeForAutofillHandler.obtainMessage(0, this).sendToTarget(); 12883 } 12884 } 12885 } 12886 if (!TextUtils.isEmpty(getAccessibilityPaneTitle())) { 12887 if (isVisible != oldVisible) { 12888 notifyViewAccessibilityStateChangedIfNeeded(isVisible 12889 ? AccessibilityEvent.CONTENT_CHANGE_TYPE_PANE_APPEARED 12890 : AccessibilityEvent.CONTENT_CHANGE_TYPE_PANE_DISAPPEARED); 12891 } 12892 } 12893 } 12894 12895 /** 12896 * Returns the current visibility of the window this view is attached to 12897 * (either {@link #GONE}, {@link #INVISIBLE}, or {@link #VISIBLE}). 12898 * 12899 * @return Returns the current visibility of the view's window. 12900 */ 12901 @Visibility 12902 public int getWindowVisibility() { 12903 return mAttachInfo != null ? mAttachInfo.mWindowVisibility : GONE; 12904 } 12905 12906 /** 12907 * Retrieve the overall visible display size in which the window this view is 12908 * attached to has been positioned in. This takes into account screen 12909 * decorations above the window, for both cases where the window itself 12910 * is being position inside of them or the window is being placed under 12911 * then and covered insets are used for the window to position its content 12912 * inside. In effect, this tells you the available area where content can 12913 * be placed and remain visible to users. 12914 * 12915 * <p>This function requires an IPC back to the window manager to retrieve 12916 * the requested information, so should not be used in performance critical 12917 * code like drawing. 12918 * 12919 * @param outRect Filled in with the visible display frame. If the view 12920 * is not attached to a window, this is simply the raw display size. 12921 */ 12922 public void getWindowVisibleDisplayFrame(Rect outRect) { 12923 if (mAttachInfo != null) { 12924 try { 12925 mAttachInfo.mSession.getDisplayFrame(mAttachInfo.mWindow, outRect); 12926 } catch (RemoteException e) { 12927 return; 12928 } 12929 // XXX This is really broken, and probably all needs to be done 12930 // in the window manager, and we need to know more about whether 12931 // we want the area behind or in front of the IME. 12932 final Rect insets = mAttachInfo.mVisibleInsets; 12933 outRect.left += insets.left; 12934 outRect.top += insets.top; 12935 outRect.right -= insets.right; 12936 outRect.bottom -= insets.bottom; 12937 return; 12938 } 12939 // The view is not attached to a display so we don't have a context. 12940 // Make a best guess about the display size. 12941 Display d = DisplayManagerGlobal.getInstance().getRealDisplay(Display.DEFAULT_DISPLAY); 12942 d.getRectSize(outRect); 12943 } 12944 12945 /** 12946 * Like {@link #getWindowVisibleDisplayFrame}, but returns the "full" display frame this window 12947 * is currently in without any insets. 12948 * 12949 * @hide 12950 */ 12951 public void getWindowDisplayFrame(Rect outRect) { 12952 if (mAttachInfo != null) { 12953 try { 12954 mAttachInfo.mSession.getDisplayFrame(mAttachInfo.mWindow, outRect); 12955 } catch (RemoteException e) { 12956 return; 12957 } 12958 return; 12959 } 12960 // The view is not attached to a display so we don't have a context. 12961 // Make a best guess about the display size. 12962 Display d = DisplayManagerGlobal.getInstance().getRealDisplay(Display.DEFAULT_DISPLAY); 12963 d.getRectSize(outRect); 12964 } 12965 12966 /** 12967 * Dispatch a notification about a resource configuration change down 12968 * the view hierarchy. 12969 * ViewGroups should override to route to their children. 12970 * 12971 * @param newConfig The new resource configuration. 12972 * 12973 * @see #onConfigurationChanged(android.content.res.Configuration) 12974 */ 12975 public void dispatchConfigurationChanged(Configuration newConfig) { 12976 onConfigurationChanged(newConfig); 12977 } 12978 12979 /** 12980 * Called when the current configuration of the resources being used 12981 * by the application have changed. You can use this to decide when 12982 * to reload resources that can changed based on orientation and other 12983 * configuration characteristics. You only need to use this if you are 12984 * not relying on the normal {@link android.app.Activity} mechanism of 12985 * recreating the activity instance upon a configuration change. 12986 * 12987 * @param newConfig The new resource configuration. 12988 */ 12989 protected void onConfigurationChanged(Configuration newConfig) { 12990 } 12991 12992 /** 12993 * Private function to aggregate all per-view attributes in to the view 12994 * root. 12995 */ 12996 void dispatchCollectViewAttributes(AttachInfo attachInfo, int visibility) { 12997 performCollectViewAttributes(attachInfo, visibility); 12998 } 12999 13000 void performCollectViewAttributes(AttachInfo attachInfo, int visibility) { 13001 if ((visibility & VISIBILITY_MASK) == VISIBLE) { 13002 if ((mViewFlags & KEEP_SCREEN_ON) == KEEP_SCREEN_ON) { 13003 attachInfo.mKeepScreenOn = true; 13004 } 13005 attachInfo.mSystemUiVisibility |= mSystemUiVisibility; 13006 ListenerInfo li = mListenerInfo; 13007 if (li != null && li.mOnSystemUiVisibilityChangeListener != null) { 13008 attachInfo.mHasSystemUiListeners = true; 13009 } 13010 } 13011 } 13012 13013 void needGlobalAttributesUpdate(boolean force) { 13014 final AttachInfo ai = mAttachInfo; 13015 if (ai != null && !ai.mRecomputeGlobalAttributes) { 13016 if (force || ai.mKeepScreenOn || (ai.mSystemUiVisibility != 0) 13017 || ai.mHasSystemUiListeners) { 13018 ai.mRecomputeGlobalAttributes = true; 13019 } 13020 } 13021 } 13022 13023 /** 13024 * Returns whether the device is currently in touch mode. Touch mode is entered 13025 * once the user begins interacting with the device by touch, and affects various 13026 * things like whether focus is always visible to the user. 13027 * 13028 * @return Whether the device is in touch mode. 13029 */ 13030 @ViewDebug.ExportedProperty 13031 public boolean isInTouchMode() { 13032 if (mAttachInfo != null) { 13033 return mAttachInfo.mInTouchMode; 13034 } else { 13035 return ViewRootImpl.isInTouchMode(); 13036 } 13037 } 13038 13039 /** 13040 * Returns the context the view is running in, through which it can 13041 * access the current theme, resources, etc. 13042 * 13043 * @return The view's Context. 13044 */ 13045 @ViewDebug.CapturedViewProperty 13046 public final Context getContext() { 13047 return mContext; 13048 } 13049 13050 /** 13051 * Handle a key event before it is processed by any input method 13052 * associated with the view hierarchy. This can be used to intercept 13053 * key events in special situations before the IME consumes them; a 13054 * typical example would be handling the BACK key to update the application's 13055 * UI instead of allowing the IME to see it and close itself. 13056 * 13057 * @param keyCode The value in event.getKeyCode(). 13058 * @param event Description of the key event. 13059 * @return If you handled the event, return true. If you want to allow the 13060 * event to be handled by the next receiver, return false. 13061 */ 13062 public boolean onKeyPreIme(int keyCode, KeyEvent event) { 13063 return false; 13064 } 13065 13066 /** 13067 * Default implementation of {@link KeyEvent.Callback#onKeyDown(int, KeyEvent) 13068 * KeyEvent.Callback.onKeyDown()}: perform press of the view 13069 * when {@link KeyEvent#KEYCODE_DPAD_CENTER} or {@link KeyEvent#KEYCODE_ENTER} 13070 * is released, if the view is enabled and clickable. 13071 * <p> 13072 * Key presses in software keyboards will generally NOT trigger this 13073 * listener, although some may elect to do so in some situations. Do not 13074 * rely on this to catch software key presses. 13075 * 13076 * @param keyCode a key code that represents the button pressed, from 13077 * {@link android.view.KeyEvent} 13078 * @param event the KeyEvent object that defines the button action 13079 */ 13080 public boolean onKeyDown(int keyCode, KeyEvent event) { 13081 if (KeyEvent.isConfirmKey(keyCode)) { 13082 if ((mViewFlags & ENABLED_MASK) == DISABLED) { 13083 return true; 13084 } 13085 13086 if (event.getRepeatCount() == 0) { 13087 // Long clickable items don't necessarily have to be clickable. 13088 final boolean clickable = (mViewFlags & CLICKABLE) == CLICKABLE 13089 || (mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE; 13090 if (clickable || (mViewFlags & TOOLTIP) == TOOLTIP) { 13091 // For the purposes of menu anchoring and drawable hotspots, 13092 // key events are considered to be at the center of the view. 13093 final float x = getWidth() / 2f; 13094 final float y = getHeight() / 2f; 13095 if (clickable) { 13096 setPressed(true, x, y); 13097 } 13098 checkForLongClick(0, x, y); 13099 return true; 13100 } 13101 } 13102 } 13103 13104 return false; 13105 } 13106 13107 /** 13108 * Default implementation of {@link KeyEvent.Callback#onKeyLongPress(int, KeyEvent) 13109 * KeyEvent.Callback.onKeyLongPress()}: always returns false (doesn't handle 13110 * the event). 13111 * <p>Key presses in software keyboards will generally NOT trigger this listener, 13112 * although some may elect to do so in some situations. Do not rely on this to 13113 * catch software key presses. 13114 */ 13115 public boolean onKeyLongPress(int keyCode, KeyEvent event) { 13116 return false; 13117 } 13118 13119 /** 13120 * Default implementation of {@link KeyEvent.Callback#onKeyUp(int, KeyEvent) 13121 * KeyEvent.Callback.onKeyUp()}: perform clicking of the view 13122 * when {@link KeyEvent#KEYCODE_DPAD_CENTER}, {@link KeyEvent#KEYCODE_ENTER} 13123 * or {@link KeyEvent#KEYCODE_SPACE} is released. 13124 * <p>Key presses in software keyboards will generally NOT trigger this listener, 13125 * although some may elect to do so in some situations. Do not rely on this to 13126 * catch software key presses. 13127 * 13128 * @param keyCode A key code that represents the button pressed, from 13129 * {@link android.view.KeyEvent}. 13130 * @param event The KeyEvent object that defines the button action. 13131 */ 13132 public boolean onKeyUp(int keyCode, KeyEvent event) { 13133 if (KeyEvent.isConfirmKey(keyCode)) { 13134 if ((mViewFlags & ENABLED_MASK) == DISABLED) { 13135 return true; 13136 } 13137 if ((mViewFlags & CLICKABLE) == CLICKABLE && isPressed()) { 13138 setPressed(false); 13139 13140 if (!mHasPerformedLongPress) { 13141 // This is a tap, so remove the longpress check 13142 removeLongPressCallback(); 13143 if (!event.isCanceled()) { 13144 return performClickInternal(); 13145 } 13146 } 13147 } 13148 } 13149 return false; 13150 } 13151 13152 /** 13153 * Default implementation of {@link KeyEvent.Callback#onKeyMultiple(int, int, KeyEvent) 13154 * KeyEvent.Callback.onKeyMultiple()}: always returns false (doesn't handle 13155 * the event). 13156 * <p>Key presses in software keyboards will generally NOT trigger this listener, 13157 * although some may elect to do so in some situations. Do not rely on this to 13158 * catch software key presses. 13159 * 13160 * @param keyCode A key code that represents the button pressed, from 13161 * {@link android.view.KeyEvent}. 13162 * @param repeatCount The number of times the action was made. 13163 * @param event The KeyEvent object that defines the button action. 13164 */ 13165 public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event) { 13166 return false; 13167 } 13168 13169 /** 13170 * Called on the focused view when a key shortcut event is not handled. 13171 * Override this method to implement local key shortcuts for the View. 13172 * Key shortcuts can also be implemented by setting the 13173 * {@link MenuItem#setShortcut(char, char) shortcut} property of menu items. 13174 * 13175 * @param keyCode The value in event.getKeyCode(). 13176 * @param event Description of the key event. 13177 * @return If you handled the event, return true. If you want to allow the 13178 * event to be handled by the next receiver, return false. 13179 */ 13180 public boolean onKeyShortcut(int keyCode, KeyEvent event) { 13181 return false; 13182 } 13183 13184 /** 13185 * Check whether the called view is a text editor, in which case it 13186 * would make sense to automatically display a soft input window for 13187 * it. Subclasses should override this if they implement 13188 * {@link #onCreateInputConnection(EditorInfo)} to return true if 13189 * a call on that method would return a non-null InputConnection, and 13190 * they are really a first-class editor that the user would normally 13191 * start typing on when the go into a window containing your view. 13192 * 13193 * <p>The default implementation always returns false. This does 13194 * <em>not</em> mean that its {@link #onCreateInputConnection(EditorInfo)} 13195 * will not be called or the user can not otherwise perform edits on your 13196 * view; it is just a hint to the system that this is not the primary 13197 * purpose of this view. 13198 * 13199 * @return Returns true if this view is a text editor, else false. 13200 */ 13201 public boolean onCheckIsTextEditor() { 13202 return false; 13203 } 13204 13205 /** 13206 * Create a new InputConnection for an InputMethod to interact 13207 * with the view. The default implementation returns null, since it doesn't 13208 * support input methods. You can override this to implement such support. 13209 * This is only needed for views that take focus and text input. 13210 * 13211 * <p>When implementing this, you probably also want to implement 13212 * {@link #onCheckIsTextEditor()} to indicate you will return a 13213 * non-null InputConnection.</p> 13214 * 13215 * <p>Also, take good care to fill in the {@link android.view.inputmethod.EditorInfo} 13216 * object correctly and in its entirety, so that the connected IME can rely 13217 * on its values. For example, {@link android.view.inputmethod.EditorInfo#initialSelStart} 13218 * and {@link android.view.inputmethod.EditorInfo#initialSelEnd} members 13219 * must be filled in with the correct cursor position for IMEs to work correctly 13220 * with your application.</p> 13221 * 13222 * @param outAttrs Fill in with attribute information about the connection. 13223 */ 13224 public InputConnection onCreateInputConnection(EditorInfo outAttrs) { 13225 return null; 13226 } 13227 13228 /** 13229 * Called by the {@link android.view.inputmethod.InputMethodManager} 13230 * when a view who is not the current 13231 * input connection target is trying to make a call on the manager. The 13232 * default implementation returns false; you can override this to return 13233 * true for certain views if you are performing InputConnection proxying 13234 * to them. 13235 * @param view The View that is making the InputMethodManager call. 13236 * @return Return true to allow the call, false to reject. 13237 */ 13238 public boolean checkInputConnectionProxy(View view) { 13239 return false; 13240 } 13241 13242 /** 13243 * Show the context menu for this view. It is not safe to hold on to the 13244 * menu after returning from this method. 13245 * 13246 * You should normally not overload this method. Overload 13247 * {@link #onCreateContextMenu(ContextMenu)} or define an 13248 * {@link OnCreateContextMenuListener} to add items to the context menu. 13249 * 13250 * @param menu The context menu to populate 13251 */ 13252 public void createContextMenu(ContextMenu menu) { 13253 ContextMenuInfo menuInfo = getContextMenuInfo(); 13254 13255 // Sets the current menu info so all items added to menu will have 13256 // my extra info set. 13257 ((MenuBuilder)menu).setCurrentMenuInfo(menuInfo); 13258 13259 onCreateContextMenu(menu); 13260 ListenerInfo li = mListenerInfo; 13261 if (li != null && li.mOnCreateContextMenuListener != null) { 13262 li.mOnCreateContextMenuListener.onCreateContextMenu(menu, this, menuInfo); 13263 } 13264 13265 // Clear the extra information so subsequent items that aren't mine don't 13266 // have my extra info. 13267 ((MenuBuilder)menu).setCurrentMenuInfo(null); 13268 13269 if (mParent != null) { 13270 mParent.createContextMenu(menu); 13271 } 13272 } 13273 13274 /** 13275 * Views should implement this if they have extra information to associate 13276 * with the context menu. The return result is supplied as a parameter to 13277 * the {@link OnCreateContextMenuListener#onCreateContextMenu(ContextMenu, View, ContextMenuInfo)} 13278 * callback. 13279 * 13280 * @return Extra information about the item for which the context menu 13281 * should be shown. This information will vary across different 13282 * subclasses of View. 13283 */ 13284 protected ContextMenuInfo getContextMenuInfo() { 13285 return null; 13286 } 13287 13288 /** 13289 * Views should implement this if the view itself is going to add items to 13290 * the context menu. 13291 * 13292 * @param menu the context menu to populate 13293 */ 13294 protected void onCreateContextMenu(ContextMenu menu) { 13295 } 13296 13297 /** 13298 * Implement this method to handle trackball motion events. The 13299 * <em>relative</em> movement of the trackball since the last event 13300 * can be retrieve with {@link MotionEvent#getX MotionEvent.getX()} and 13301 * {@link MotionEvent#getY MotionEvent.getY()}. These are normalized so 13302 * that a movement of 1 corresponds to the user pressing one DPAD key (so 13303 * they will often be fractional values, representing the more fine-grained 13304 * movement information available from a trackball). 13305 * 13306 * @param event The motion event. 13307 * @return True if the event was handled, false otherwise. 13308 */ 13309 public boolean onTrackballEvent(MotionEvent event) { 13310 return false; 13311 } 13312 13313 /** 13314 * Implement this method to handle generic motion events. 13315 * <p> 13316 * Generic motion events describe joystick movements, mouse hovers, track pad 13317 * touches, scroll wheel movements and other input events. The 13318 * {@link MotionEvent#getSource() source} of the motion event specifies 13319 * the class of input that was received. Implementations of this method 13320 * must examine the bits in the source before processing the event. 13321 * The following code example shows how this is done. 13322 * </p><p> 13323 * Generic motion events with source class {@link InputDevice#SOURCE_CLASS_POINTER} 13324 * are delivered to the view under the pointer. All other generic motion events are 13325 * delivered to the focused view. 13326 * </p> 13327 * <pre> public boolean onGenericMotionEvent(MotionEvent event) { 13328 * if (event.isFromSource(InputDevice.SOURCE_CLASS_JOYSTICK)) { 13329 * if (event.getAction() == MotionEvent.ACTION_MOVE) { 13330 * // process the joystick movement... 13331 * return true; 13332 * } 13333 * } 13334 * if (event.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) { 13335 * switch (event.getAction()) { 13336 * case MotionEvent.ACTION_HOVER_MOVE: 13337 * // process the mouse hover movement... 13338 * return true; 13339 * case MotionEvent.ACTION_SCROLL: 13340 * // process the scroll wheel movement... 13341 * return true; 13342 * } 13343 * } 13344 * return super.onGenericMotionEvent(event); 13345 * }</pre> 13346 * 13347 * @param event The generic motion event being processed. 13348 * @return True if the event was handled, false otherwise. 13349 */ 13350 public boolean onGenericMotionEvent(MotionEvent event) { 13351 return false; 13352 } 13353 13354 /** 13355 * Implement this method to handle hover events. 13356 * <p> 13357 * This method is called whenever a pointer is hovering into, over, or out of the 13358 * bounds of a view and the view is not currently being touched. 13359 * Hover events are represented as pointer events with action 13360 * {@link MotionEvent#ACTION_HOVER_ENTER}, {@link MotionEvent#ACTION_HOVER_MOVE}, 13361 * or {@link MotionEvent#ACTION_HOVER_EXIT}. 13362 * </p> 13363 * <ul> 13364 * <li>The view receives a hover event with action {@link MotionEvent#ACTION_HOVER_ENTER} 13365 * when the pointer enters the bounds of the view.</li> 13366 * <li>The view receives a hover event with action {@link MotionEvent#ACTION_HOVER_MOVE} 13367 * when the pointer has already entered the bounds of the view and has moved.</li> 13368 * <li>The view receives a hover event with action {@link MotionEvent#ACTION_HOVER_EXIT} 13369 * when the pointer has exited the bounds of the view or when the pointer is 13370 * about to go down due to a button click, tap, or similar user action that 13371 * causes the view to be touched.</li> 13372 * </ul> 13373 * <p> 13374 * The view should implement this method to return true to indicate that it is 13375 * handling the hover event, such as by changing its drawable state. 13376 * </p><p> 13377 * The default implementation calls {@link #setHovered} to update the hovered state 13378 * of the view when a hover enter or hover exit event is received, if the view 13379 * is enabled and is clickable. The default implementation also sends hover 13380 * accessibility events. 13381 * </p> 13382 * 13383 * @param event The motion event that describes the hover. 13384 * @return True if the view handled the hover event. 13385 * 13386 * @see #isHovered 13387 * @see #setHovered 13388 * @see #onHoverChanged 13389 */ 13390 public boolean onHoverEvent(MotionEvent event) { 13391 // The root view may receive hover (or touch) events that are outside the bounds of 13392 // the window. This code ensures that we only send accessibility events for 13393 // hovers that are actually within the bounds of the root view. 13394 final int action = event.getActionMasked(); 13395 if (!mSendingHoverAccessibilityEvents) { 13396 if ((action == MotionEvent.ACTION_HOVER_ENTER 13397 || action == MotionEvent.ACTION_HOVER_MOVE) 13398 && !hasHoveredChild() 13399 && pointInView(event.getX(), event.getY())) { 13400 sendAccessibilityHoverEvent(AccessibilityEvent.TYPE_VIEW_HOVER_ENTER); 13401 mSendingHoverAccessibilityEvents = true; 13402 } 13403 } else { 13404 if (action == MotionEvent.ACTION_HOVER_EXIT 13405 || (action == MotionEvent.ACTION_MOVE 13406 && !pointInView(event.getX(), event.getY()))) { 13407 mSendingHoverAccessibilityEvents = false; 13408 sendAccessibilityHoverEvent(AccessibilityEvent.TYPE_VIEW_HOVER_EXIT); 13409 } 13410 } 13411 13412 if ((action == MotionEvent.ACTION_HOVER_ENTER || action == MotionEvent.ACTION_HOVER_MOVE) 13413 && event.isFromSource(InputDevice.SOURCE_MOUSE) 13414 && isOnScrollbar(event.getX(), event.getY())) { 13415 awakenScrollBars(); 13416 } 13417 13418 // If we consider ourself hoverable, or if we we're already hovered, 13419 // handle changing state in response to ENTER and EXIT events. 13420 if (isHoverable() || isHovered()) { 13421 switch (action) { 13422 case MotionEvent.ACTION_HOVER_ENTER: 13423 setHovered(true); 13424 break; 13425 case MotionEvent.ACTION_HOVER_EXIT: 13426 setHovered(false); 13427 break; 13428 } 13429 13430 // Dispatch the event to onGenericMotionEvent before returning true. 13431 // This is to provide compatibility with existing applications that 13432 // handled HOVER_MOVE events in onGenericMotionEvent and that would 13433 // break because of the new default handling for hoverable views 13434 // in onHoverEvent. 13435 // Note that onGenericMotionEvent will be called by default when 13436 // onHoverEvent returns false (refer to dispatchGenericMotionEvent). 13437 dispatchGenericMotionEventInternal(event); 13438 // The event was already handled by calling setHovered(), so always 13439 // return true. 13440 return true; 13441 } 13442 13443 return false; 13444 } 13445 13446 /** 13447 * Returns true if the view should handle {@link #onHoverEvent} 13448 * by calling {@link #setHovered} to change its hovered state. 13449 * 13450 * @return True if the view is hoverable. 13451 */ 13452 private boolean isHoverable() { 13453 final int viewFlags = mViewFlags; 13454 if ((viewFlags & ENABLED_MASK) == DISABLED) { 13455 return false; 13456 } 13457 13458 return (viewFlags & CLICKABLE) == CLICKABLE 13459 || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE 13460 || (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE; 13461 } 13462 13463 /** 13464 * Returns true if the view is currently hovered. 13465 * 13466 * @return True if the view is currently hovered. 13467 * 13468 * @see #setHovered 13469 * @see #onHoverChanged 13470 */ 13471 @ViewDebug.ExportedProperty 13472 public boolean isHovered() { 13473 return (mPrivateFlags & PFLAG_HOVERED) != 0; 13474 } 13475 13476 /** 13477 * Sets whether the view is currently hovered. 13478 * <p> 13479 * Calling this method also changes the drawable state of the view. This 13480 * enables the view to react to hover by using different drawable resources 13481 * to change its appearance. 13482 * </p><p> 13483 * The {@link #onHoverChanged} method is called when the hovered state changes. 13484 * </p> 13485 * 13486 * @param hovered True if the view is hovered. 13487 * 13488 * @see #isHovered 13489 * @see #onHoverChanged 13490 */ 13491 public void setHovered(boolean hovered) { 13492 if (hovered) { 13493 if ((mPrivateFlags & PFLAG_HOVERED) == 0) { 13494 mPrivateFlags |= PFLAG_HOVERED; 13495 refreshDrawableState(); 13496 onHoverChanged(true); 13497 } 13498 } else { 13499 if ((mPrivateFlags & PFLAG_HOVERED) != 0) { 13500 mPrivateFlags &= ~PFLAG_HOVERED; 13501 refreshDrawableState(); 13502 onHoverChanged(false); 13503 } 13504 } 13505 } 13506 13507 /** 13508 * Implement this method to handle hover state changes. 13509 * <p> 13510 * This method is called whenever the hover state changes as a result of a 13511 * call to {@link #setHovered}. 13512 * </p> 13513 * 13514 * @param hovered The current hover state, as returned by {@link #isHovered}. 13515 * 13516 * @see #isHovered 13517 * @see #setHovered 13518 */ 13519 public void onHoverChanged(boolean hovered) { 13520 } 13521 13522 /** 13523 * Handles scroll bar dragging by mouse input. 13524 * 13525 * @hide 13526 * @param event The motion event. 13527 * 13528 * @return true if the event was handled as a scroll bar dragging, false otherwise. 13529 */ 13530 protected boolean handleScrollBarDragging(MotionEvent event) { 13531 if (mScrollCache == null) { 13532 return false; 13533 } 13534 final float x = event.getX(); 13535 final float y = event.getY(); 13536 final int action = event.getAction(); 13537 if ((mScrollCache.mScrollBarDraggingState == ScrollabilityCache.NOT_DRAGGING 13538 && action != MotionEvent.ACTION_DOWN) 13539 || !event.isFromSource(InputDevice.SOURCE_MOUSE) 13540 || !event.isButtonPressed(MotionEvent.BUTTON_PRIMARY)) { 13541 mScrollCache.mScrollBarDraggingState = ScrollabilityCache.NOT_DRAGGING; 13542 return false; 13543 } 13544 13545 switch (action) { 13546 case MotionEvent.ACTION_MOVE: 13547 if (mScrollCache.mScrollBarDraggingState == ScrollabilityCache.NOT_DRAGGING) { 13548 return false; 13549 } 13550 if (mScrollCache.mScrollBarDraggingState 13551 == ScrollabilityCache.DRAGGING_VERTICAL_SCROLL_BAR) { 13552 final Rect bounds = mScrollCache.mScrollBarBounds; 13553 getVerticalScrollBarBounds(bounds, null); 13554 final int range = computeVerticalScrollRange(); 13555 final int offset = computeVerticalScrollOffset(); 13556 final int extent = computeVerticalScrollExtent(); 13557 13558 final int thumbLength = ScrollBarUtils.getThumbLength( 13559 bounds.height(), bounds.width(), extent, range); 13560 final int thumbOffset = ScrollBarUtils.getThumbOffset( 13561 bounds.height(), thumbLength, extent, range, offset); 13562 13563 final float diff = y - mScrollCache.mScrollBarDraggingPos; 13564 final float maxThumbOffset = bounds.height() - thumbLength; 13565 final float newThumbOffset = 13566 Math.min(Math.max(thumbOffset + diff, 0.0f), maxThumbOffset); 13567 final int height = getHeight(); 13568 if (Math.round(newThumbOffset) != thumbOffset && maxThumbOffset > 0 13569 && height > 0 && extent > 0) { 13570 final int newY = Math.round((range - extent) 13571 / ((float)extent / height) * (newThumbOffset / maxThumbOffset)); 13572 if (newY != getScrollY()) { 13573 mScrollCache.mScrollBarDraggingPos = y; 13574 setScrollY(newY); 13575 } 13576 } 13577 return true; 13578 } 13579 if (mScrollCache.mScrollBarDraggingState 13580 == ScrollabilityCache.DRAGGING_HORIZONTAL_SCROLL_BAR) { 13581 final Rect bounds = mScrollCache.mScrollBarBounds; 13582 getHorizontalScrollBarBounds(bounds, null); 13583 final int range = computeHorizontalScrollRange(); 13584 final int offset = computeHorizontalScrollOffset(); 13585 final int extent = computeHorizontalScrollExtent(); 13586 13587 final int thumbLength = ScrollBarUtils.getThumbLength( 13588 bounds.width(), bounds.height(), extent, range); 13589 final int thumbOffset = ScrollBarUtils.getThumbOffset( 13590 bounds.width(), thumbLength, extent, range, offset); 13591 13592 final float diff = x - mScrollCache.mScrollBarDraggingPos; 13593 final float maxThumbOffset = bounds.width() - thumbLength; 13594 final float newThumbOffset = 13595 Math.min(Math.max(thumbOffset + diff, 0.0f), maxThumbOffset); 13596 final int width = getWidth(); 13597 if (Math.round(newThumbOffset) != thumbOffset && maxThumbOffset > 0 13598 && width > 0 && extent > 0) { 13599 final int newX = Math.round((range - extent) 13600 / ((float)extent / width) * (newThumbOffset / maxThumbOffset)); 13601 if (newX != getScrollX()) { 13602 mScrollCache.mScrollBarDraggingPos = x; 13603 setScrollX(newX); 13604 } 13605 } 13606 return true; 13607 } 13608 case MotionEvent.ACTION_DOWN: 13609 if (mScrollCache.state == ScrollabilityCache.OFF) { 13610 return false; 13611 } 13612 if (isOnVerticalScrollbarThumb(x, y)) { 13613 mScrollCache.mScrollBarDraggingState = 13614 ScrollabilityCache.DRAGGING_VERTICAL_SCROLL_BAR; 13615 mScrollCache.mScrollBarDraggingPos = y; 13616 return true; 13617 } 13618 if (isOnHorizontalScrollbarThumb(x, y)) { 13619 mScrollCache.mScrollBarDraggingState = 13620 ScrollabilityCache.DRAGGING_HORIZONTAL_SCROLL_BAR; 13621 mScrollCache.mScrollBarDraggingPos = x; 13622 return true; 13623 } 13624 } 13625 mScrollCache.mScrollBarDraggingState = ScrollabilityCache.NOT_DRAGGING; 13626 return false; 13627 } 13628 13629 /** 13630 * Implement this method to handle touch screen motion events. 13631 * <p> 13632 * If this method is used to detect click actions, it is recommended that 13633 * the actions be performed by implementing and calling 13634 * {@link #performClick()}. This will ensure consistent system behavior, 13635 * including: 13636 * <ul> 13637 * <li>obeying click sound preferences 13638 * <li>dispatching OnClickListener calls 13639 * <li>handling {@link AccessibilityNodeInfo#ACTION_CLICK ACTION_CLICK} when 13640 * accessibility features are enabled 13641 * </ul> 13642 * 13643 * @param event The motion event. 13644 * @return True if the event was handled, false otherwise. 13645 */ 13646 public boolean onTouchEvent(MotionEvent event) { 13647 final float x = event.getX(); 13648 final float y = event.getY(); 13649 final int viewFlags = mViewFlags; 13650 final int action = event.getAction(); 13651 13652 final boolean clickable = ((viewFlags & CLICKABLE) == CLICKABLE 13653 || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE) 13654 || (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE; 13655 13656 if ((viewFlags & ENABLED_MASK) == DISABLED) { 13657 if (action == MotionEvent.ACTION_UP && (mPrivateFlags & PFLAG_PRESSED) != 0) { 13658 setPressed(false); 13659 } 13660 mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN; 13661 // A disabled view that is clickable still consumes the touch 13662 // events, it just doesn't respond to them. 13663 return clickable; 13664 } 13665 if (mTouchDelegate != null) { 13666 if (mTouchDelegate.onTouchEvent(event)) { 13667 return true; 13668 } 13669 } 13670 13671 if (clickable || (viewFlags & TOOLTIP) == TOOLTIP) { 13672 switch (action) { 13673 case MotionEvent.ACTION_UP: 13674 mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN; 13675 if ((viewFlags & TOOLTIP) == TOOLTIP) { 13676 handleTooltipUp(); 13677 } 13678 if (!clickable) { 13679 removeTapCallback(); 13680 removeLongPressCallback(); 13681 mInContextButtonPress = false; 13682 mHasPerformedLongPress = false; 13683 mIgnoreNextUpEvent = false; 13684 break; 13685 } 13686 boolean prepressed = (mPrivateFlags & PFLAG_PREPRESSED) != 0; 13687 if ((mPrivateFlags & PFLAG_PRESSED) != 0 || prepressed) { 13688 // take focus if we don't have it already and we should in 13689 // touch mode. 13690 boolean focusTaken = false; 13691 if (isFocusable() && isFocusableInTouchMode() && !isFocused()) { 13692 focusTaken = requestFocus(); 13693 } 13694 13695 if (prepressed) { 13696 // The button is being released before we actually 13697 // showed it as pressed. Make it show the pressed 13698 // state now (before scheduling the click) to ensure 13699 // the user sees it. 13700 setPressed(true, x, y); 13701 } 13702 13703 if (!mHasPerformedLongPress && !mIgnoreNextUpEvent) { 13704 // This is a tap, so remove the longpress check 13705 removeLongPressCallback(); 13706 13707 // Only perform take click actions if we were in the pressed state 13708 if (!focusTaken) { 13709 // Use a Runnable and post this rather than calling 13710 // performClick directly. This lets other visual state 13711 // of the view update before click actions start. 13712 if (mPerformClick == null) { 13713 mPerformClick = new PerformClick(); 13714 } 13715 if (!post(mPerformClick)) { 13716 performClickInternal(); 13717 } 13718 } 13719 } 13720 13721 if (mUnsetPressedState == null) { 13722 mUnsetPressedState = new UnsetPressedState(); 13723 } 13724 13725 if (prepressed) { 13726 postDelayed(mUnsetPressedState, 13727 ViewConfiguration.getPressedStateDuration()); 13728 } else if (!post(mUnsetPressedState)) { 13729 // If the post failed, unpress right now 13730 mUnsetPressedState.run(); 13731 } 13732 13733 removeTapCallback(); 13734 } 13735 mIgnoreNextUpEvent = false; 13736 break; 13737 13738 case MotionEvent.ACTION_DOWN: 13739 if (event.getSource() == InputDevice.SOURCE_TOUCHSCREEN) { 13740 mPrivateFlags3 |= PFLAG3_FINGER_DOWN; 13741 } 13742 mHasPerformedLongPress = false; 13743 13744 if (!clickable) { 13745 checkForLongClick(0, x, y); 13746 break; 13747 } 13748 13749 if (performButtonActionOnTouchDown(event)) { 13750 break; 13751 } 13752 13753 // Walk up the hierarchy to determine if we're inside a scrolling container. 13754 boolean isInScrollingContainer = isInScrollingContainer(); 13755 13756 // For views inside a scrolling container, delay the pressed feedback for 13757 // a short period in case this is a scroll. 13758 if (isInScrollingContainer) { 13759 mPrivateFlags |= PFLAG_PREPRESSED; 13760 if (mPendingCheckForTap == null) { 13761 mPendingCheckForTap = new CheckForTap(); 13762 } 13763 mPendingCheckForTap.x = event.getX(); 13764 mPendingCheckForTap.y = event.getY(); 13765 postDelayed(mPendingCheckForTap, ViewConfiguration.getTapTimeout()); 13766 } else { 13767 // Not inside a scrolling container, so show the feedback right away 13768 setPressed(true, x, y); 13769 checkForLongClick(0, x, y); 13770 } 13771 break; 13772 13773 case MotionEvent.ACTION_CANCEL: 13774 if (clickable) { 13775 setPressed(false); 13776 } 13777 removeTapCallback(); 13778 removeLongPressCallback(); 13779 mInContextButtonPress = false; 13780 mHasPerformedLongPress = false; 13781 mIgnoreNextUpEvent = false; 13782 mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN; 13783 break; 13784 13785 case MotionEvent.ACTION_MOVE: 13786 if (clickable) { 13787 drawableHotspotChanged(x, y); 13788 } 13789 13790 // Be lenient about moving outside of buttons 13791 if (!pointInView(x, y, mTouchSlop)) { 13792 // Outside button 13793 // Remove any future long press/tap checks 13794 removeTapCallback(); 13795 removeLongPressCallback(); 13796 if ((mPrivateFlags & PFLAG_PRESSED) != 0) { 13797 setPressed(false); 13798 } 13799 mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN; 13800 } 13801 break; 13802 } 13803 13804 return true; 13805 } 13806 13807 return false; 13808 } 13809 13810 /** 13811 * @hide 13812 */ 13813 public boolean isInScrollingContainer() { 13814 ViewParent p = getParent(); 13815 while (p != null && p instanceof ViewGroup) { 13816 if (((ViewGroup) p).shouldDelayChildPressedState()) { 13817 return true; 13818 } 13819 p = p.getParent(); 13820 } 13821 return false; 13822 } 13823 13824 /** 13825 * Remove the longpress detection timer. 13826 */ 13827 private void removeLongPressCallback() { 13828 if (mPendingCheckForLongPress != null) { 13829 removeCallbacks(mPendingCheckForLongPress); 13830 } 13831 } 13832 13833 /** 13834 * Remove the pending click action 13835 */ 13836 private void removePerformClickCallback() { 13837 if (mPerformClick != null) { 13838 removeCallbacks(mPerformClick); 13839 } 13840 } 13841 13842 /** 13843 * Remove the prepress detection timer. 13844 */ 13845 private void removeUnsetPressCallback() { 13846 if ((mPrivateFlags & PFLAG_PRESSED) != 0 && mUnsetPressedState != null) { 13847 setPressed(false); 13848 removeCallbacks(mUnsetPressedState); 13849 } 13850 } 13851 13852 /** 13853 * Remove the tap detection timer. 13854 */ 13855 private void removeTapCallback() { 13856 if (mPendingCheckForTap != null) { 13857 mPrivateFlags &= ~PFLAG_PREPRESSED; 13858 removeCallbacks(mPendingCheckForTap); 13859 } 13860 } 13861 13862 /** 13863 * Cancels a pending long press. Your subclass can use this if you 13864 * want the context menu to come up if the user presses and holds 13865 * at the same place, but you don't want it to come up if they press 13866 * and then move around enough to cause scrolling. 13867 */ 13868 public void cancelLongPress() { 13869 removeLongPressCallback(); 13870 13871 /* 13872 * The prepressed state handled by the tap callback is a display 13873 * construct, but the tap callback will post a long press callback 13874 * less its own timeout. Remove it here. 13875 */ 13876 removeTapCallback(); 13877 } 13878 13879 /** 13880 * Sets the TouchDelegate for this View. 13881 */ 13882 public void setTouchDelegate(TouchDelegate delegate) { 13883 mTouchDelegate = delegate; 13884 } 13885 13886 /** 13887 * Gets the TouchDelegate for this View. 13888 */ 13889 public TouchDelegate getTouchDelegate() { 13890 return mTouchDelegate; 13891 } 13892 13893 /** 13894 * Request unbuffered dispatch of the given stream of MotionEvents to this View. 13895 * 13896 * Until this View receives a corresponding {@link MotionEvent#ACTION_UP}, ask that the input 13897 * system not batch {@link MotionEvent}s but instead deliver them as soon as they're 13898 * available. This method should only be called for touch events. 13899 * 13900 * <p class="note">This api is not intended for most applications. Buffered dispatch 13901 * provides many of benefits, and just requesting unbuffered dispatch on most MotionEvent 13902 * streams will not improve your input latency. Side effects include: increased latency, 13903 * jittery scrolls and inability to take advantage of system resampling. Talk to your input 13904 * professional to see if {@link #requestUnbufferedDispatch(MotionEvent)} is right for 13905 * you.</p> 13906 */ 13907 public final void requestUnbufferedDispatch(MotionEvent event) { 13908 final int action = event.getAction(); 13909 if (mAttachInfo == null 13910 || action != MotionEvent.ACTION_DOWN && action != MotionEvent.ACTION_MOVE 13911 || !event.isTouchEvent()) { 13912 return; 13913 } 13914 mAttachInfo.mUnbufferedDispatchRequested = true; 13915 } 13916 13917 private boolean canTakeFocus() { 13918 return ((mViewFlags & VISIBILITY_MASK) == VISIBLE) 13919 && ((mViewFlags & FOCUSABLE) == FOCUSABLE) 13920 && ((mViewFlags & ENABLED_MASK) == ENABLED) 13921 && (sCanFocusZeroSized || !isLayoutValid() || (mBottom > mTop) && (mRight > mLeft)); 13922 } 13923 13924 /** 13925 * Set flags controlling behavior of this view. 13926 * 13927 * @param flags Constant indicating the value which should be set 13928 * @param mask Constant indicating the bit range that should be changed 13929 */ 13930 void setFlags(int flags, int mask) { 13931 final boolean accessibilityEnabled = 13932 AccessibilityManager.getInstance(mContext).isEnabled(); 13933 final boolean oldIncludeForAccessibility = accessibilityEnabled && includeForAccessibility(); 13934 13935 int old = mViewFlags; 13936 mViewFlags = (mViewFlags & ~mask) | (flags & mask); 13937 13938 int changed = mViewFlags ^ old; 13939 if (changed == 0) { 13940 return; 13941 } 13942 int privateFlags = mPrivateFlags; 13943 boolean shouldNotifyFocusableAvailable = false; 13944 13945 // If focusable is auto, update the FOCUSABLE bit. 13946 int focusableChangedByAuto = 0; 13947 if (((mViewFlags & FOCUSABLE_AUTO) != 0) 13948 && (changed & (FOCUSABLE_MASK | CLICKABLE)) != 0) { 13949 // Heuristic only takes into account whether view is clickable. 13950 final int newFocus; 13951 if ((mViewFlags & CLICKABLE) != 0) { 13952 newFocus = FOCUSABLE; 13953 } else { 13954 newFocus = NOT_FOCUSABLE; 13955 } 13956 mViewFlags = (mViewFlags & ~FOCUSABLE) | newFocus; 13957 focusableChangedByAuto = (old & FOCUSABLE) ^ (newFocus & FOCUSABLE); 13958 changed = (changed & ~FOCUSABLE) | focusableChangedByAuto; 13959 } 13960 13961 /* Check if the FOCUSABLE bit has changed */ 13962 if (((changed & FOCUSABLE) != 0) && ((privateFlags & PFLAG_HAS_BOUNDS) != 0)) { 13963 if (((old & FOCUSABLE) == FOCUSABLE) 13964 && ((privateFlags & PFLAG_FOCUSED) != 0)) { 13965 /* Give up focus if we are no longer focusable */ 13966 clearFocus(); 13967 if (mParent instanceof ViewGroup) { 13968 ((ViewGroup) mParent).clearFocusedInCluster(); 13969 } 13970 } else if (((old & FOCUSABLE) == NOT_FOCUSABLE) 13971 && ((privateFlags & PFLAG_FOCUSED) == 0)) { 13972 /* 13973 * Tell the view system that we are now available to take focus 13974 * if no one else already has it. 13975 */ 13976 if (mParent != null) { 13977 ViewRootImpl viewRootImpl = getViewRootImpl(); 13978 if (!sAutoFocusableOffUIThreadWontNotifyParents 13979 || focusableChangedByAuto == 0 13980 || viewRootImpl == null 13981 || viewRootImpl.mThread == Thread.currentThread()) { 13982 shouldNotifyFocusableAvailable = true; 13983 } 13984 } 13985 } 13986 } 13987 13988 final int newVisibility = flags & VISIBILITY_MASK; 13989 if (newVisibility == VISIBLE) { 13990 if ((changed & VISIBILITY_MASK) != 0) { 13991 /* 13992 * If this view is becoming visible, invalidate it in case it changed while 13993 * it was not visible. Marking it drawn ensures that the invalidation will 13994 * go through. 13995 */ 13996 mPrivateFlags |= PFLAG_DRAWN; 13997 invalidate(true); 13998 13999 needGlobalAttributesUpdate(true); 14000 14001 // a view becoming visible is worth notifying the parent 14002 // about in case nothing has focus. even if this specific view 14003 // isn't focusable, it may contain something that is, so let 14004 // the root view try to give this focus if nothing else does. 14005 shouldNotifyFocusableAvailable = true; 14006 } 14007 } 14008 14009 if ((changed & ENABLED_MASK) != 0) { 14010 if ((mViewFlags & ENABLED_MASK) == ENABLED) { 14011 // a view becoming enabled should notify the parent as long as the view is also 14012 // visible and the parent wasn't already notified by becoming visible during this 14013 // setFlags invocation. 14014 shouldNotifyFocusableAvailable = true; 14015 } else { 14016 if (isFocused()) clearFocus(); 14017 } 14018 } 14019 14020 if (shouldNotifyFocusableAvailable) { 14021 if (mParent != null && canTakeFocus()) { 14022 mParent.focusableViewAvailable(this); 14023 } 14024 } 14025 14026 /* Check if the GONE bit has changed */ 14027 if ((changed & GONE) != 0) { 14028 needGlobalAttributesUpdate(false); 14029 requestLayout(); 14030 14031 if (((mViewFlags & VISIBILITY_MASK) == GONE)) { 14032 if (hasFocus()) { 14033 clearFocus(); 14034 if (mParent instanceof ViewGroup) { 14035 ((ViewGroup) mParent).clearFocusedInCluster(); 14036 } 14037 } 14038 clearAccessibilityFocus(); 14039 destroyDrawingCache(); 14040 if (mParent instanceof View) { 14041 // GONE views noop invalidation, so invalidate the parent 14042 ((View) mParent).invalidate(true); 14043 } 14044 // Mark the view drawn to ensure that it gets invalidated properly the next 14045 // time it is visible and gets invalidated 14046 mPrivateFlags |= PFLAG_DRAWN; 14047 } 14048 if (mAttachInfo != null) { 14049 mAttachInfo.mViewVisibilityChanged = true; 14050 } 14051 } 14052 14053 /* Check if the VISIBLE bit has changed */ 14054 if ((changed & INVISIBLE) != 0) { 14055 needGlobalAttributesUpdate(false); 14056 /* 14057 * If this view is becoming invisible, set the DRAWN flag so that 14058 * the next invalidate() will not be skipped. 14059 */ 14060 mPrivateFlags |= PFLAG_DRAWN; 14061 14062 if (((mViewFlags & VISIBILITY_MASK) == INVISIBLE)) { 14063 // root view becoming invisible shouldn't clear focus and accessibility focus 14064 if (getRootView() != this) { 14065 if (hasFocus()) { 14066 clearFocus(); 14067 if (mParent instanceof ViewGroup) { 14068 ((ViewGroup) mParent).clearFocusedInCluster(); 14069 } 14070 } 14071 clearAccessibilityFocus(); 14072 } 14073 } 14074 if (mAttachInfo != null) { 14075 mAttachInfo.mViewVisibilityChanged = true; 14076 } 14077 } 14078 14079 if ((changed & VISIBILITY_MASK) != 0) { 14080 // If the view is invisible, cleanup its display list to free up resources 14081 if (newVisibility != VISIBLE && mAttachInfo != null) { 14082 cleanupDraw(); 14083 } 14084 14085 if (mParent instanceof ViewGroup) { 14086 ((ViewGroup) mParent).onChildVisibilityChanged(this, 14087 (changed & VISIBILITY_MASK), newVisibility); 14088 ((View) mParent).invalidate(true); 14089 } else if (mParent != null) { 14090 mParent.invalidateChild(this, null); 14091 } 14092 14093 if (mAttachInfo != null) { 14094 dispatchVisibilityChanged(this, newVisibility); 14095 14096 // Aggregated visibility changes are dispatched to attached views 14097 // in visible windows where the parent is currently shown/drawn 14098 // or the parent is not a ViewGroup (and therefore assumed to be a ViewRoot), 14099 // discounting clipping or overlapping. This makes it a good place 14100 // to change animation states. 14101 if (mParent != null && getWindowVisibility() == VISIBLE && 14102 ((!(mParent instanceof ViewGroup)) || ((ViewGroup) mParent).isShown())) { 14103 dispatchVisibilityAggregated(newVisibility == VISIBLE); 14104 } 14105 notifySubtreeAccessibilityStateChangedIfNeeded(); 14106 } 14107 } 14108 14109 if ((changed & WILL_NOT_CACHE_DRAWING) != 0) { 14110 destroyDrawingCache(); 14111 } 14112 14113 if ((changed & DRAWING_CACHE_ENABLED) != 0) { 14114 destroyDrawingCache(); 14115 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; 14116 invalidateParentCaches(); 14117 } 14118 14119 if ((changed & DRAWING_CACHE_QUALITY_MASK) != 0) { 14120 destroyDrawingCache(); 14121 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; 14122 } 14123 14124 if ((changed & DRAW_MASK) != 0) { 14125 if ((mViewFlags & WILL_NOT_DRAW) != 0) { 14126 if (mBackground != null 14127 || mDefaultFocusHighlight != null 14128 || (mForegroundInfo != null && mForegroundInfo.mDrawable != null)) { 14129 mPrivateFlags &= ~PFLAG_SKIP_DRAW; 14130 } else { 14131 mPrivateFlags |= PFLAG_SKIP_DRAW; 14132 } 14133 } else { 14134 mPrivateFlags &= ~PFLAG_SKIP_DRAW; 14135 } 14136 requestLayout(); 14137 invalidate(true); 14138 } 14139 14140 if ((changed & KEEP_SCREEN_ON) != 0) { 14141 if (mParent != null && mAttachInfo != null && !mAttachInfo.mRecomputeGlobalAttributes) { 14142 mParent.recomputeViewAttributes(this); 14143 } 14144 } 14145 14146 if (accessibilityEnabled) { 14147 // If we're an accessibility pane and the visibility changed, we already have sent 14148 // a state change, so we really don't need to report other changes. 14149 if (isAccessibilityPane()) { 14150 changed &= ~VISIBILITY_MASK; 14151 } 14152 if ((changed & FOCUSABLE) != 0 || (changed & VISIBILITY_MASK) != 0 14153 || (changed & CLICKABLE) != 0 || (changed & LONG_CLICKABLE) != 0 14154 || (changed & CONTEXT_CLICKABLE) != 0) { 14155 if (oldIncludeForAccessibility != includeForAccessibility()) { 14156 notifySubtreeAccessibilityStateChangedIfNeeded(); 14157 } else { 14158 notifyViewAccessibilityStateChangedIfNeeded( 14159 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 14160 } 14161 } else if ((changed & ENABLED_MASK) != 0) { 14162 notifyViewAccessibilityStateChangedIfNeeded( 14163 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 14164 } 14165 } 14166 } 14167 14168 /** 14169 * Change the view's z order in the tree, so it's on top of other sibling 14170 * views. This ordering change may affect layout, if the parent container 14171 * uses an order-dependent layout scheme (e.g., LinearLayout). Prior 14172 * to {@link android.os.Build.VERSION_CODES#KITKAT} this 14173 * method should be followed by calls to {@link #requestLayout()} and 14174 * {@link View#invalidate()} on the view's parent to force the parent to redraw 14175 * with the new child ordering. 14176 * 14177 * @see ViewGroup#bringChildToFront(View) 14178 */ 14179 public void bringToFront() { 14180 if (mParent != null) { 14181 mParent.bringChildToFront(this); 14182 } 14183 } 14184 14185 /** 14186 * This is called in response to an internal scroll in this view (i.e., the 14187 * view scrolled its own contents). This is typically as a result of 14188 * {@link #scrollBy(int, int)} or {@link #scrollTo(int, int)} having been 14189 * called. 14190 * 14191 * @param l Current horizontal scroll origin. 14192 * @param t Current vertical scroll origin. 14193 * @param oldl Previous horizontal scroll origin. 14194 * @param oldt Previous vertical scroll origin. 14195 */ 14196 protected void onScrollChanged(int l, int t, int oldl, int oldt) { 14197 notifySubtreeAccessibilityStateChangedIfNeeded(); 14198 14199 if (AccessibilityManager.getInstance(mContext).isEnabled()) { 14200 postSendViewScrolledAccessibilityEventCallback(l - oldl, t - oldt); 14201 } 14202 14203 mBackgroundSizeChanged = true; 14204 mDefaultFocusHighlightSizeChanged = true; 14205 if (mForegroundInfo != null) { 14206 mForegroundInfo.mBoundsChanged = true; 14207 } 14208 14209 final AttachInfo ai = mAttachInfo; 14210 if (ai != null) { 14211 ai.mViewScrollChanged = true; 14212 } 14213 14214 if (mListenerInfo != null && mListenerInfo.mOnScrollChangeListener != null) { 14215 mListenerInfo.mOnScrollChangeListener.onScrollChange(this, l, t, oldl, oldt); 14216 } 14217 } 14218 14219 /** 14220 * Interface definition for a callback to be invoked when the scroll 14221 * X or Y positions of a view change. 14222 * <p> 14223 * <b>Note:</b> Some views handle scrolling independently from View and may 14224 * have their own separate listeners for scroll-type events. For example, 14225 * {@link android.widget.ListView ListView} allows clients to register an 14226 * {@link android.widget.ListView#setOnScrollListener(android.widget.AbsListView.OnScrollListener) AbsListView.OnScrollListener} 14227 * to listen for changes in list scroll position. 14228 * 14229 * @see #setOnScrollChangeListener(View.OnScrollChangeListener) 14230 */ 14231 public interface OnScrollChangeListener { 14232 /** 14233 * Called when the scroll position of a view changes. 14234 * 14235 * @param v The view whose scroll position has changed. 14236 * @param scrollX Current horizontal scroll origin. 14237 * @param scrollY Current vertical scroll origin. 14238 * @param oldScrollX Previous horizontal scroll origin. 14239 * @param oldScrollY Previous vertical scroll origin. 14240 */ 14241 void onScrollChange(View v, int scrollX, int scrollY, int oldScrollX, int oldScrollY); 14242 } 14243 14244 /** 14245 * Interface definition for a callback to be invoked when the layout bounds of a view 14246 * changes due to layout processing. 14247 */ 14248 public interface OnLayoutChangeListener { 14249 /** 14250 * Called when the layout bounds of a view changes due to layout processing. 14251 * 14252 * @param v The view whose bounds have changed. 14253 * @param left The new value of the view's left property. 14254 * @param top The new value of the view's top property. 14255 * @param right The new value of the view's right property. 14256 * @param bottom The new value of the view's bottom property. 14257 * @param oldLeft The previous value of the view's left property. 14258 * @param oldTop The previous value of the view's top property. 14259 * @param oldRight The previous value of the view's right property. 14260 * @param oldBottom The previous value of the view's bottom property. 14261 */ 14262 void onLayoutChange(View v, int left, int top, int right, int bottom, 14263 int oldLeft, int oldTop, int oldRight, int oldBottom); 14264 } 14265 14266 /** 14267 * This is called during layout when the size of this view has changed. If 14268 * you were just added to the view hierarchy, you're called with the old 14269 * values of 0. 14270 * 14271 * @param w Current width of this view. 14272 * @param h Current height of this view. 14273 * @param oldw Old width of this view. 14274 * @param oldh Old height of this view. 14275 */ 14276 protected void onSizeChanged(int w, int h, int oldw, int oldh) { 14277 } 14278 14279 /** 14280 * Called by draw to draw the child views. This may be overridden 14281 * by derived classes to gain control just before its children are drawn 14282 * (but after its own view has been drawn). 14283 * @param canvas the canvas on which to draw the view 14284 */ 14285 protected void dispatchDraw(Canvas canvas) { 14286 14287 } 14288 14289 /** 14290 * Gets the parent of this view. Note that the parent is a 14291 * ViewParent and not necessarily a View. 14292 * 14293 * @return Parent of this view. 14294 */ 14295 public final ViewParent getParent() { 14296 return mParent; 14297 } 14298 14299 /** 14300 * Set the horizontal scrolled position of your view. This will cause a call to 14301 * {@link #onScrollChanged(int, int, int, int)} and the view will be 14302 * invalidated. 14303 * @param value the x position to scroll to 14304 */ 14305 public void setScrollX(int value) { 14306 scrollTo(value, mScrollY); 14307 } 14308 14309 /** 14310 * Set the vertical scrolled position of your view. This will cause a call to 14311 * {@link #onScrollChanged(int, int, int, int)} and the view will be 14312 * invalidated. 14313 * @param value the y position to scroll to 14314 */ 14315 public void setScrollY(int value) { 14316 scrollTo(mScrollX, value); 14317 } 14318 14319 /** 14320 * Return the scrolled left position of this view. This is the left edge of 14321 * the displayed part of your view. You do not need to draw any pixels 14322 * farther left, since those are outside of the frame of your view on 14323 * screen. 14324 * 14325 * @return The left edge of the displayed part of your view, in pixels. 14326 */ 14327 public final int getScrollX() { 14328 return mScrollX; 14329 } 14330 14331 /** 14332 * Return the scrolled top position of this view. This is the top edge of 14333 * the displayed part of your view. You do not need to draw any pixels above 14334 * it, since those are outside of the frame of your view on screen. 14335 * 14336 * @return The top edge of the displayed part of your view, in pixels. 14337 */ 14338 public final int getScrollY() { 14339 return mScrollY; 14340 } 14341 14342 /** 14343 * Return the width of the your view. 14344 * 14345 * @return The width of your view, in pixels. 14346 */ 14347 @ViewDebug.ExportedProperty(category = "layout") 14348 public final int getWidth() { 14349 return mRight - mLeft; 14350 } 14351 14352 /** 14353 * Return the height of your view. 14354 * 14355 * @return The height of your view, in pixels. 14356 */ 14357 @ViewDebug.ExportedProperty(category = "layout") 14358 public final int getHeight() { 14359 return mBottom - mTop; 14360 } 14361 14362 /** 14363 * Return the visible drawing bounds of your view. Fills in the output 14364 * rectangle with the values from getScrollX(), getScrollY(), 14365 * getWidth(), and getHeight(). These bounds do not account for any 14366 * transformation properties currently set on the view, such as 14367 * {@link #setScaleX(float)} or {@link #setRotation(float)}. 14368 * 14369 * @param outRect The (scrolled) drawing bounds of the view. 14370 */ 14371 public void getDrawingRect(Rect outRect) { 14372 outRect.left = mScrollX; 14373 outRect.top = mScrollY; 14374 outRect.right = mScrollX + (mRight - mLeft); 14375 outRect.bottom = mScrollY + (mBottom - mTop); 14376 } 14377 14378 /** 14379 * Like {@link #getMeasuredWidthAndState()}, but only returns the 14380 * raw width component (that is the result is masked by 14381 * {@link #MEASURED_SIZE_MASK}). 14382 * 14383 * @return The raw measured width of this view. 14384 */ 14385 public final int getMeasuredWidth() { 14386 return mMeasuredWidth & MEASURED_SIZE_MASK; 14387 } 14388 14389 /** 14390 * Return the full width measurement information for this view as computed 14391 * by the most recent call to {@link #measure(int, int)}. This result is a bit mask 14392 * as defined by {@link #MEASURED_SIZE_MASK} and {@link #MEASURED_STATE_TOO_SMALL}. 14393 * This should be used during measurement and layout calculations only. Use 14394 * {@link #getWidth()} to see how wide a view is after layout. 14395 * 14396 * @return The measured width of this view as a bit mask. 14397 */ 14398 @ViewDebug.ExportedProperty(category = "measurement", flagMapping = { 14399 @ViewDebug.FlagToString(mask = MEASURED_STATE_MASK, equals = MEASURED_STATE_TOO_SMALL, 14400 name = "MEASURED_STATE_TOO_SMALL"), 14401 }) 14402 public final int getMeasuredWidthAndState() { 14403 return mMeasuredWidth; 14404 } 14405 14406 /** 14407 * Like {@link #getMeasuredHeightAndState()}, but only returns the 14408 * raw height component (that is the result is masked by 14409 * {@link #MEASURED_SIZE_MASK}). 14410 * 14411 * @return The raw measured height of this view. 14412 */ 14413 public final int getMeasuredHeight() { 14414 return mMeasuredHeight & MEASURED_SIZE_MASK; 14415 } 14416 14417 /** 14418 * Return the full height measurement information for this view as computed 14419 * by the most recent call to {@link #measure(int, int)}. This result is a bit mask 14420 * as defined by {@link #MEASURED_SIZE_MASK} and {@link #MEASURED_STATE_TOO_SMALL}. 14421 * This should be used during measurement and layout calculations only. Use 14422 * {@link #getHeight()} to see how wide a view is after layout. 14423 * 14424 * @return The measured height of this view as a bit mask. 14425 */ 14426 @ViewDebug.ExportedProperty(category = "measurement", flagMapping = { 14427 @ViewDebug.FlagToString(mask = MEASURED_STATE_MASK, equals = MEASURED_STATE_TOO_SMALL, 14428 name = "MEASURED_STATE_TOO_SMALL"), 14429 }) 14430 public final int getMeasuredHeightAndState() { 14431 return mMeasuredHeight; 14432 } 14433 14434 /** 14435 * Return only the state bits of {@link #getMeasuredWidthAndState()} 14436 * and {@link #getMeasuredHeightAndState()}, combined into one integer. 14437 * The width component is in the regular bits {@link #MEASURED_STATE_MASK} 14438 * and the height component is at the shifted bits 14439 * {@link #MEASURED_HEIGHT_STATE_SHIFT}>>{@link #MEASURED_STATE_MASK}. 14440 */ 14441 public final int getMeasuredState() { 14442 return (mMeasuredWidth&MEASURED_STATE_MASK) 14443 | ((mMeasuredHeight>>MEASURED_HEIGHT_STATE_SHIFT) 14444 & (MEASURED_STATE_MASK>>MEASURED_HEIGHT_STATE_SHIFT)); 14445 } 14446 14447 /** 14448 * The transform matrix of this view, which is calculated based on the current 14449 * rotation, scale, and pivot properties. 14450 * 14451 * @see #getRotation() 14452 * @see #getScaleX() 14453 * @see #getScaleY() 14454 * @see #getPivotX() 14455 * @see #getPivotY() 14456 * @return The current transform matrix for the view 14457 */ 14458 public Matrix getMatrix() { 14459 ensureTransformationInfo(); 14460 final Matrix matrix = mTransformationInfo.mMatrix; 14461 mRenderNode.getMatrix(matrix); 14462 return matrix; 14463 } 14464 14465 /** 14466 * Returns true if the transform matrix is the identity matrix. 14467 * Recomputes the matrix if necessary. 14468 * 14469 * @return True if the transform matrix is the identity matrix, false otherwise. 14470 */ 14471 final boolean hasIdentityMatrix() { 14472 return mRenderNode.hasIdentityMatrix(); 14473 } 14474 14475 void ensureTransformationInfo() { 14476 if (mTransformationInfo == null) { 14477 mTransformationInfo = new TransformationInfo(); 14478 } 14479 } 14480 14481 /** 14482 * Utility method to retrieve the inverse of the current mMatrix property. 14483 * We cache the matrix to avoid recalculating it when transform properties 14484 * have not changed. 14485 * 14486 * @return The inverse of the current matrix of this view. 14487 * @hide 14488 */ 14489 public final Matrix getInverseMatrix() { 14490 ensureTransformationInfo(); 14491 if (mTransformationInfo.mInverseMatrix == null) { 14492 mTransformationInfo.mInverseMatrix = new Matrix(); 14493 } 14494 final Matrix matrix = mTransformationInfo.mInverseMatrix; 14495 mRenderNode.getInverseMatrix(matrix); 14496 return matrix; 14497 } 14498 14499 /** 14500 * Gets the distance along the Z axis from the camera to this view. 14501 * 14502 * @see #setCameraDistance(float) 14503 * 14504 * @return The distance along the Z axis. 14505 */ 14506 public float getCameraDistance() { 14507 final float dpi = mResources.getDisplayMetrics().densityDpi; 14508 return -(mRenderNode.getCameraDistance() * dpi); 14509 } 14510 14511 /** 14512 * <p>Sets the distance along the Z axis (orthogonal to the X/Y plane on which 14513 * views are drawn) from the camera to this view. The camera's distance 14514 * affects 3D transformations, for instance rotations around the X and Y 14515 * axis. If the rotationX or rotationY properties are changed and this view is 14516 * large (more than half the size of the screen), it is recommended to always 14517 * use a camera distance that's greater than the height (X axis rotation) or 14518 * the width (Y axis rotation) of this view.</p> 14519 * 14520 * <p>The distance of the camera from the view plane can have an affect on the 14521 * perspective distortion of the view when it is rotated around the x or y axis. 14522 * For example, a large distance will result in a large viewing angle, and there 14523 * will not be much perspective distortion of the view as it rotates. A short 14524 * distance may cause much more perspective distortion upon rotation, and can 14525 * also result in some drawing artifacts if the rotated view ends up partially 14526 * behind the camera (which is why the recommendation is to use a distance at 14527 * least as far as the size of the view, if the view is to be rotated.)</p> 14528 * 14529 * <p>The distance is expressed in "depth pixels." The default distance depends 14530 * on the screen density. For instance, on a medium density display, the 14531 * default distance is 1280. On a high density display, the default distance 14532 * is 1920.</p> 14533 * 14534 * <p>If you want to specify a distance that leads to visually consistent 14535 * results across various densities, use the following formula:</p> 14536 * <pre> 14537 * float scale = context.getResources().getDisplayMetrics().density; 14538 * view.setCameraDistance(distance * scale); 14539 * </pre> 14540 * 14541 * <p>The density scale factor of a high density display is 1.5, 14542 * and 1920 = 1280 * 1.5.</p> 14543 * 14544 * @param distance The distance in "depth pixels", if negative the opposite 14545 * value is used 14546 * 14547 * @see #setRotationX(float) 14548 * @see #setRotationY(float) 14549 */ 14550 public void setCameraDistance(float distance) { 14551 final float dpi = mResources.getDisplayMetrics().densityDpi; 14552 14553 invalidateViewProperty(true, false); 14554 mRenderNode.setCameraDistance(-Math.abs(distance) / dpi); 14555 invalidateViewProperty(false, false); 14556 14557 invalidateParentIfNeededAndWasQuickRejected(); 14558 } 14559 14560 /** 14561 * The degrees that the view is rotated around the pivot point. 14562 * 14563 * @see #setRotation(float) 14564 * @see #getPivotX() 14565 * @see #getPivotY() 14566 * 14567 * @return The degrees of rotation. 14568 */ 14569 @ViewDebug.ExportedProperty(category = "drawing") 14570 public float getRotation() { 14571 return mRenderNode.getRotation(); 14572 } 14573 14574 /** 14575 * Sets the degrees that the view is rotated around the pivot point. Increasing values 14576 * result in clockwise rotation. 14577 * 14578 * @param rotation The degrees of rotation. 14579 * 14580 * @see #getRotation() 14581 * @see #getPivotX() 14582 * @see #getPivotY() 14583 * @see #setRotationX(float) 14584 * @see #setRotationY(float) 14585 * 14586 * @attr ref android.R.styleable#View_rotation 14587 */ 14588 public void setRotation(float rotation) { 14589 if (rotation != getRotation()) { 14590 // Double-invalidation is necessary to capture view's old and new areas 14591 invalidateViewProperty(true, false); 14592 mRenderNode.setRotation(rotation); 14593 invalidateViewProperty(false, true); 14594 14595 invalidateParentIfNeededAndWasQuickRejected(); 14596 notifySubtreeAccessibilityStateChangedIfNeeded(); 14597 } 14598 } 14599 14600 /** 14601 * The degrees that the view is rotated around the vertical axis through the pivot point. 14602 * 14603 * @see #getPivotX() 14604 * @see #getPivotY() 14605 * @see #setRotationY(float) 14606 * 14607 * @return The degrees of Y rotation. 14608 */ 14609 @ViewDebug.ExportedProperty(category = "drawing") 14610 public float getRotationY() { 14611 return mRenderNode.getRotationY(); 14612 } 14613 14614 /** 14615 * Sets the degrees that the view is rotated around the vertical axis through the pivot point. 14616 * Increasing values result in counter-clockwise rotation from the viewpoint of looking 14617 * down the y axis. 14618 * 14619 * When rotating large views, it is recommended to adjust the camera distance 14620 * accordingly. Refer to {@link #setCameraDistance(float)} for more information. 14621 * 14622 * @param rotationY The degrees of Y rotation. 14623 * 14624 * @see #getRotationY() 14625 * @see #getPivotX() 14626 * @see #getPivotY() 14627 * @see #setRotation(float) 14628 * @see #setRotationX(float) 14629 * @see #setCameraDistance(float) 14630 * 14631 * @attr ref android.R.styleable#View_rotationY 14632 */ 14633 public void setRotationY(float rotationY) { 14634 if (rotationY != getRotationY()) { 14635 invalidateViewProperty(true, false); 14636 mRenderNode.setRotationY(rotationY); 14637 invalidateViewProperty(false, true); 14638 14639 invalidateParentIfNeededAndWasQuickRejected(); 14640 notifySubtreeAccessibilityStateChangedIfNeeded(); 14641 } 14642 } 14643 14644 /** 14645 * The degrees that the view is rotated around the horizontal axis through the pivot point. 14646 * 14647 * @see #getPivotX() 14648 * @see #getPivotY() 14649 * @see #setRotationX(float) 14650 * 14651 * @return The degrees of X rotation. 14652 */ 14653 @ViewDebug.ExportedProperty(category = "drawing") 14654 public float getRotationX() { 14655 return mRenderNode.getRotationX(); 14656 } 14657 14658 /** 14659 * Sets the degrees that the view is rotated around the horizontal axis through the pivot point. 14660 * Increasing values result in clockwise rotation from the viewpoint of looking down the 14661 * x axis. 14662 * 14663 * When rotating large views, it is recommended to adjust the camera distance 14664 * accordingly. Refer to {@link #setCameraDistance(float)} for more information. 14665 * 14666 * @param rotationX The degrees of X rotation. 14667 * 14668 * @see #getRotationX() 14669 * @see #getPivotX() 14670 * @see #getPivotY() 14671 * @see #setRotation(float) 14672 * @see #setRotationY(float) 14673 * @see #setCameraDistance(float) 14674 * 14675 * @attr ref android.R.styleable#View_rotationX 14676 */ 14677 public void setRotationX(float rotationX) { 14678 if (rotationX != getRotationX()) { 14679 invalidateViewProperty(true, false); 14680 mRenderNode.setRotationX(rotationX); 14681 invalidateViewProperty(false, true); 14682 14683 invalidateParentIfNeededAndWasQuickRejected(); 14684 notifySubtreeAccessibilityStateChangedIfNeeded(); 14685 } 14686 } 14687 14688 /** 14689 * The amount that the view is scaled in x around the pivot point, as a proportion of 14690 * the view's unscaled width. A value of 1, the default, means that no scaling is applied. 14691 * 14692 * <p>By default, this is 1.0f. 14693 * 14694 * @see #getPivotX() 14695 * @see #getPivotY() 14696 * @return The scaling factor. 14697 */ 14698 @ViewDebug.ExportedProperty(category = "drawing") 14699 public float getScaleX() { 14700 return mRenderNode.getScaleX(); 14701 } 14702 14703 /** 14704 * Sets the amount that the view is scaled in x around the pivot point, as a proportion of 14705 * the view's unscaled width. A value of 1 means that no scaling is applied. 14706 * 14707 * @param scaleX The scaling factor. 14708 * @see #getPivotX() 14709 * @see #getPivotY() 14710 * 14711 * @attr ref android.R.styleable#View_scaleX 14712 */ 14713 public void setScaleX(float scaleX) { 14714 if (scaleX != getScaleX()) { 14715 scaleX = sanitizeFloatPropertyValue(scaleX, "scaleX"); 14716 invalidateViewProperty(true, false); 14717 mRenderNode.setScaleX(scaleX); 14718 invalidateViewProperty(false, true); 14719 14720 invalidateParentIfNeededAndWasQuickRejected(); 14721 notifySubtreeAccessibilityStateChangedIfNeeded(); 14722 } 14723 } 14724 14725 /** 14726 * The amount that the view is scaled in y around the pivot point, as a proportion of 14727 * the view's unscaled height. A value of 1, the default, means that no scaling is applied. 14728 * 14729 * <p>By default, this is 1.0f. 14730 * 14731 * @see #getPivotX() 14732 * @see #getPivotY() 14733 * @return The scaling factor. 14734 */ 14735 @ViewDebug.ExportedProperty(category = "drawing") 14736 public float getScaleY() { 14737 return mRenderNode.getScaleY(); 14738 } 14739 14740 /** 14741 * Sets the amount that the view is scaled in Y around the pivot point, as a proportion of 14742 * the view's unscaled width. A value of 1 means that no scaling is applied. 14743 * 14744 * @param scaleY The scaling factor. 14745 * @see #getPivotX() 14746 * @see #getPivotY() 14747 * 14748 * @attr ref android.R.styleable#View_scaleY 14749 */ 14750 public void setScaleY(float scaleY) { 14751 if (scaleY != getScaleY()) { 14752 scaleY = sanitizeFloatPropertyValue(scaleY, "scaleY"); 14753 invalidateViewProperty(true, false); 14754 mRenderNode.setScaleY(scaleY); 14755 invalidateViewProperty(false, true); 14756 14757 invalidateParentIfNeededAndWasQuickRejected(); 14758 notifySubtreeAccessibilityStateChangedIfNeeded(); 14759 } 14760 } 14761 14762 /** 14763 * The x location of the point around which the view is {@link #setRotation(float) rotated} 14764 * and {@link #setScaleX(float) scaled}. 14765 * 14766 * @see #getRotation() 14767 * @see #getScaleX() 14768 * @see #getScaleY() 14769 * @see #getPivotY() 14770 * @return The x location of the pivot point. 14771 * 14772 * @attr ref android.R.styleable#View_transformPivotX 14773 */ 14774 @ViewDebug.ExportedProperty(category = "drawing") 14775 public float getPivotX() { 14776 return mRenderNode.getPivotX(); 14777 } 14778 14779 /** 14780 * Sets the x location of the point around which the view is 14781 * {@link #setRotation(float) rotated} and {@link #setScaleX(float) scaled}. 14782 * By default, the pivot point is centered on the object. 14783 * Setting this property disables this behavior and causes the view to use only the 14784 * explicitly set pivotX and pivotY values. 14785 * 14786 * @param pivotX The x location of the pivot point. 14787 * @see #getRotation() 14788 * @see #getScaleX() 14789 * @see #getScaleY() 14790 * @see #getPivotY() 14791 * 14792 * @attr ref android.R.styleable#View_transformPivotX 14793 */ 14794 public void setPivotX(float pivotX) { 14795 if (!mRenderNode.isPivotExplicitlySet() || pivotX != getPivotX()) { 14796 invalidateViewProperty(true, false); 14797 mRenderNode.setPivotX(pivotX); 14798 invalidateViewProperty(false, true); 14799 14800 invalidateParentIfNeededAndWasQuickRejected(); 14801 } 14802 } 14803 14804 /** 14805 * The y location of the point around which the view is {@link #setRotation(float) rotated} 14806 * and {@link #setScaleY(float) scaled}. 14807 * 14808 * @see #getRotation() 14809 * @see #getScaleX() 14810 * @see #getScaleY() 14811 * @see #getPivotY() 14812 * @return The y location of the pivot point. 14813 * 14814 * @attr ref android.R.styleable#View_transformPivotY 14815 */ 14816 @ViewDebug.ExportedProperty(category = "drawing") 14817 public float getPivotY() { 14818 return mRenderNode.getPivotY(); 14819 } 14820 14821 /** 14822 * Sets the y location of the point around which the view is {@link #setRotation(float) rotated} 14823 * and {@link #setScaleY(float) scaled}. By default, the pivot point is centered on the object. 14824 * Setting this property disables this behavior and causes the view to use only the 14825 * explicitly set pivotX and pivotY values. 14826 * 14827 * @param pivotY The y location of the pivot point. 14828 * @see #getRotation() 14829 * @see #getScaleX() 14830 * @see #getScaleY() 14831 * @see #getPivotY() 14832 * 14833 * @attr ref android.R.styleable#View_transformPivotY 14834 */ 14835 public void setPivotY(float pivotY) { 14836 if (!mRenderNode.isPivotExplicitlySet() || pivotY != getPivotY()) { 14837 invalidateViewProperty(true, false); 14838 mRenderNode.setPivotY(pivotY); 14839 invalidateViewProperty(false, true); 14840 14841 invalidateParentIfNeededAndWasQuickRejected(); 14842 } 14843 } 14844 14845 /** 14846 * Returns whether or not a pivot has been set by a call to {@link #setPivotX(float)} or 14847 * {@link #setPivotY(float)}. If no pivot has been set then the pivot will be the center 14848 * of the view. 14849 * 14850 * @return True if a pivot has been set, false if the default pivot is being used 14851 */ 14852 public boolean isPivotSet() { 14853 return mRenderNode.isPivotExplicitlySet(); 14854 } 14855 14856 /** 14857 * Clears any pivot previously set by a call to {@link #setPivotX(float)} or 14858 * {@link #setPivotY(float)}. After calling this {@link #isPivotSet()} will be false 14859 * and the pivot used for rotation will return to default of being centered on the view. 14860 */ 14861 public void resetPivot() { 14862 if (mRenderNode.resetPivot()) { 14863 invalidateViewProperty(false, false); 14864 } 14865 } 14866 14867 /** 14868 * The opacity of the view. This is a value from 0 to 1, where 0 means the view is 14869 * completely transparent and 1 means the view is completely opaque. 14870 * 14871 * <p>By default this is 1.0f. 14872 * @return The opacity of the view. 14873 */ 14874 @ViewDebug.ExportedProperty(category = "drawing") 14875 public float getAlpha() { 14876 return mTransformationInfo != null ? mTransformationInfo.mAlpha : 1; 14877 } 14878 14879 /** 14880 * Sets the behavior for overlapping rendering for this view (see {@link 14881 * #hasOverlappingRendering()} for more details on this behavior). Calling this method 14882 * is an alternative to overriding {@link #hasOverlappingRendering()} in a subclass, 14883 * providing the value which is then used internally. That is, when {@link 14884 * #forceHasOverlappingRendering(boolean)} is called, the value of {@link 14885 * #hasOverlappingRendering()} is ignored and the value passed into this method is used 14886 * instead. 14887 * 14888 * @param hasOverlappingRendering The value for overlapping rendering to be used internally 14889 * instead of that returned by {@link #hasOverlappingRendering()}. 14890 * 14891 * @attr ref android.R.styleable#View_forceHasOverlappingRendering 14892 */ 14893 public void forceHasOverlappingRendering(boolean hasOverlappingRendering) { 14894 mPrivateFlags3 |= PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED; 14895 if (hasOverlappingRendering) { 14896 mPrivateFlags3 |= PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE; 14897 } else { 14898 mPrivateFlags3 &= ~PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE; 14899 } 14900 } 14901 14902 /** 14903 * Returns the value for overlapping rendering that is used internally. This is either 14904 * the value passed into {@link #forceHasOverlappingRendering(boolean)}, if called, or 14905 * the return value of {@link #hasOverlappingRendering()}, otherwise. 14906 * 14907 * @return The value for overlapping rendering being used internally. 14908 */ 14909 public final boolean getHasOverlappingRendering() { 14910 return (mPrivateFlags3 & PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED) != 0 ? 14911 (mPrivateFlags3 & PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE) != 0 : 14912 hasOverlappingRendering(); 14913 } 14914 14915 /** 14916 * Returns whether this View has content which overlaps. 14917 * 14918 * <p>This function, intended to be overridden by specific View types, is an optimization when 14919 * alpha is set on a view. If rendering overlaps in a view with alpha < 1, that view is drawn to 14920 * an offscreen buffer and then composited into place, which can be expensive. If the view has 14921 * no overlapping rendering, the view can draw each primitive with the appropriate alpha value 14922 * directly. An example of overlapping rendering is a TextView with a background image, such as 14923 * a Button. An example of non-overlapping rendering is a TextView with no background, or an 14924 * ImageView with only the foreground image. The default implementation returns true; subclasses 14925 * should override if they have cases which can be optimized.</p> 14926 * 14927 * <p>The current implementation of the saveLayer and saveLayerAlpha methods in {@link Canvas} 14928 * necessitates that a View return true if it uses the methods internally without passing the 14929 * {@link Canvas#CLIP_TO_LAYER_SAVE_FLAG}.</p> 14930 * 14931 * <p><strong>Note:</strong> The return value of this method is ignored if {@link 14932 * #forceHasOverlappingRendering(boolean)} has been called on this view.</p> 14933 * 14934 * @return true if the content in this view might overlap, false otherwise. 14935 */ 14936 @ViewDebug.ExportedProperty(category = "drawing") 14937 public boolean hasOverlappingRendering() { 14938 return true; 14939 } 14940 14941 /** 14942 * Sets the opacity of the view to a value from 0 to 1, where 0 means the view is 14943 * completely transparent and 1 means the view is completely opaque. 14944 * 14945 * <p class="note"><strong>Note:</strong> setting alpha to a translucent value (0 < alpha < 1) 14946 * can have significant performance implications, especially for large views. It is best to use 14947 * the alpha property sparingly and transiently, as in the case of fading animations.</p> 14948 * 14949 * <p>For a view with a frequently changing alpha, such as during a fading animation, it is 14950 * strongly recommended for performance reasons to either override 14951 * {@link #hasOverlappingRendering()} to return <code>false</code> if appropriate, or setting a 14952 * {@link #setLayerType(int, android.graphics.Paint) layer type} on the view for the duration 14953 * of the animation. On versions {@link android.os.Build.VERSION_CODES#M} and below, 14954 * the default path for rendering an unlayered View with alpha could add multiple milliseconds 14955 * of rendering cost, even for simple or small views. Starting with 14956 * {@link android.os.Build.VERSION_CODES#M}, {@link #LAYER_TYPE_HARDWARE} is automatically 14957 * applied to the view at the rendering level.</p> 14958 * 14959 * <p>If this view overrides {@link #onSetAlpha(int)} to return true, then this view is 14960 * responsible for applying the opacity itself.</p> 14961 * 14962 * <p>On versions {@link android.os.Build.VERSION_CODES#LOLLIPOP_MR1} and below, note that if 14963 * the view is backed by a {@link #setLayerType(int, android.graphics.Paint) layer} and is 14964 * associated with a {@link #setLayerPaint(android.graphics.Paint) layer paint}, setting an 14965 * alpha value less than 1.0 will supersede the alpha of the layer paint.</p> 14966 * 14967 * <p>Starting with {@link android.os.Build.VERSION_CODES#M}, setting a translucent alpha 14968 * value will clip a View to its bounds, unless the View returns <code>false</code> from 14969 * {@link #hasOverlappingRendering}.</p> 14970 * 14971 * @param alpha The opacity of the view. 14972 * 14973 * @see #hasOverlappingRendering() 14974 * @see #setLayerType(int, android.graphics.Paint) 14975 * 14976 * @attr ref android.R.styleable#View_alpha 14977 */ 14978 public void setAlpha(@FloatRange(from=0.0, to=1.0) float alpha) { 14979 ensureTransformationInfo(); 14980 if (mTransformationInfo.mAlpha != alpha) { 14981 // Report visibility changes, which can affect children, to accessibility 14982 if ((alpha == 0) ^ (mTransformationInfo.mAlpha == 0)) { 14983 notifySubtreeAccessibilityStateChangedIfNeeded(); 14984 } 14985 mTransformationInfo.mAlpha = alpha; 14986 if (onSetAlpha((int) (alpha * 255))) { 14987 mPrivateFlags |= PFLAG_ALPHA_SET; 14988 // subclass is handling alpha - don't optimize rendering cache invalidation 14989 invalidateParentCaches(); 14990 invalidate(true); 14991 } else { 14992 mPrivateFlags &= ~PFLAG_ALPHA_SET; 14993 invalidateViewProperty(true, false); 14994 mRenderNode.setAlpha(getFinalAlpha()); 14995 } 14996 } 14997 } 14998 14999 /** 15000 * Faster version of setAlpha() which performs the same steps except there are 15001 * no calls to invalidate(). The caller of this function should perform proper invalidation 15002 * on the parent and this object. The return value indicates whether the subclass handles 15003 * alpha (the return value for onSetAlpha()). 15004 * 15005 * @param alpha The new value for the alpha property 15006 * @return true if the View subclass handles alpha (the return value for onSetAlpha()) and 15007 * the new value for the alpha property is different from the old value 15008 */ 15009 boolean setAlphaNoInvalidation(float alpha) { 15010 ensureTransformationInfo(); 15011 if (mTransformationInfo.mAlpha != alpha) { 15012 mTransformationInfo.mAlpha = alpha; 15013 boolean subclassHandlesAlpha = onSetAlpha((int) (alpha * 255)); 15014 if (subclassHandlesAlpha) { 15015 mPrivateFlags |= PFLAG_ALPHA_SET; 15016 return true; 15017 } else { 15018 mPrivateFlags &= ~PFLAG_ALPHA_SET; 15019 mRenderNode.setAlpha(getFinalAlpha()); 15020 } 15021 } 15022 return false; 15023 } 15024 15025 /** 15026 * This property is hidden and intended only for use by the Fade transition, which 15027 * animates it to produce a visual translucency that does not side-effect (or get 15028 * affected by) the real alpha property. This value is composited with the other 15029 * alpha value (and the AlphaAnimation value, when that is present) to produce 15030 * a final visual translucency result, which is what is passed into the DisplayList. 15031 * 15032 * @hide 15033 */ 15034 public void setTransitionAlpha(float alpha) { 15035 ensureTransformationInfo(); 15036 if (mTransformationInfo.mTransitionAlpha != alpha) { 15037 mTransformationInfo.mTransitionAlpha = alpha; 15038 mPrivateFlags &= ~PFLAG_ALPHA_SET; 15039 invalidateViewProperty(true, false); 15040 mRenderNode.setAlpha(getFinalAlpha()); 15041 } 15042 } 15043 15044 /** 15045 * Calculates the visual alpha of this view, which is a combination of the actual 15046 * alpha value and the transitionAlpha value (if set). 15047 */ 15048 private float getFinalAlpha() { 15049 if (mTransformationInfo != null) { 15050 return mTransformationInfo.mAlpha * mTransformationInfo.mTransitionAlpha; 15051 } 15052 return 1; 15053 } 15054 15055 /** 15056 * This property is hidden and intended only for use by the Fade transition, which 15057 * animates it to produce a visual translucency that does not side-effect (or get 15058 * affected by) the real alpha property. This value is composited with the other 15059 * alpha value (and the AlphaAnimation value, when that is present) to produce 15060 * a final visual translucency result, which is what is passed into the DisplayList. 15061 * 15062 * @hide 15063 */ 15064 @ViewDebug.ExportedProperty(category = "drawing") 15065 public float getTransitionAlpha() { 15066 return mTransformationInfo != null ? mTransformationInfo.mTransitionAlpha : 1; 15067 } 15068 15069 /** 15070 * Top position of this view relative to its parent. 15071 * 15072 * @return The top of this view, in pixels. 15073 */ 15074 @ViewDebug.CapturedViewProperty 15075 public final int getTop() { 15076 return mTop; 15077 } 15078 15079 /** 15080 * Sets the top position of this view relative to its parent. This method is meant to be called 15081 * by the layout system and should not generally be called otherwise, because the property 15082 * may be changed at any time by the layout. 15083 * 15084 * @param top The top of this view, in pixels. 15085 */ 15086 public final void setTop(int top) { 15087 if (top != mTop) { 15088 final boolean matrixIsIdentity = hasIdentityMatrix(); 15089 if (matrixIsIdentity) { 15090 if (mAttachInfo != null) { 15091 int minTop; 15092 int yLoc; 15093 if (top < mTop) { 15094 minTop = top; 15095 yLoc = top - mTop; 15096 } else { 15097 minTop = mTop; 15098 yLoc = 0; 15099 } 15100 invalidate(0, yLoc, mRight - mLeft, mBottom - minTop); 15101 } 15102 } else { 15103 // Double-invalidation is necessary to capture view's old and new areas 15104 invalidate(true); 15105 } 15106 15107 int width = mRight - mLeft; 15108 int oldHeight = mBottom - mTop; 15109 15110 mTop = top; 15111 mRenderNode.setTop(mTop); 15112 15113 sizeChange(width, mBottom - mTop, width, oldHeight); 15114 15115 if (!matrixIsIdentity) { 15116 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 15117 invalidate(true); 15118 } 15119 mBackgroundSizeChanged = true; 15120 mDefaultFocusHighlightSizeChanged = true; 15121 if (mForegroundInfo != null) { 15122 mForegroundInfo.mBoundsChanged = true; 15123 } 15124 invalidateParentIfNeeded(); 15125 if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) { 15126 // View was rejected last time it was drawn by its parent; this may have changed 15127 invalidateParentIfNeeded(); 15128 } 15129 } 15130 } 15131 15132 /** 15133 * Bottom position of this view relative to its parent. 15134 * 15135 * @return The bottom of this view, in pixels. 15136 */ 15137 @ViewDebug.CapturedViewProperty 15138 public final int getBottom() { 15139 return mBottom; 15140 } 15141 15142 /** 15143 * True if this view has changed since the last time being drawn. 15144 * 15145 * @return The dirty state of this view. 15146 */ 15147 public boolean isDirty() { 15148 return (mPrivateFlags & PFLAG_DIRTY_MASK) != 0; 15149 } 15150 15151 /** 15152 * Sets the bottom position of this view relative to its parent. This method is meant to be 15153 * called by the layout system and should not generally be called otherwise, because the 15154 * property may be changed at any time by the layout. 15155 * 15156 * @param bottom The bottom of this view, in pixels. 15157 */ 15158 public final void setBottom(int bottom) { 15159 if (bottom != mBottom) { 15160 final boolean matrixIsIdentity = hasIdentityMatrix(); 15161 if (matrixIsIdentity) { 15162 if (mAttachInfo != null) { 15163 int maxBottom; 15164 if (bottom < mBottom) { 15165 maxBottom = mBottom; 15166 } else { 15167 maxBottom = bottom; 15168 } 15169 invalidate(0, 0, mRight - mLeft, maxBottom - mTop); 15170 } 15171 } else { 15172 // Double-invalidation is necessary to capture view's old and new areas 15173 invalidate(true); 15174 } 15175 15176 int width = mRight - mLeft; 15177 int oldHeight = mBottom - mTop; 15178 15179 mBottom = bottom; 15180 mRenderNode.setBottom(mBottom); 15181 15182 sizeChange(width, mBottom - mTop, width, oldHeight); 15183 15184 if (!matrixIsIdentity) { 15185 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 15186 invalidate(true); 15187 } 15188 mBackgroundSizeChanged = true; 15189 mDefaultFocusHighlightSizeChanged = true; 15190 if (mForegroundInfo != null) { 15191 mForegroundInfo.mBoundsChanged = true; 15192 } 15193 invalidateParentIfNeeded(); 15194 if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) { 15195 // View was rejected last time it was drawn by its parent; this may have changed 15196 invalidateParentIfNeeded(); 15197 } 15198 } 15199 } 15200 15201 /** 15202 * Left position of this view relative to its parent. 15203 * 15204 * @return The left edge of this view, in pixels. 15205 */ 15206 @ViewDebug.CapturedViewProperty 15207 public final int getLeft() { 15208 return mLeft; 15209 } 15210 15211 /** 15212 * Sets the left position of this view relative to its parent. This method is meant to be called 15213 * by the layout system and should not generally be called otherwise, because the property 15214 * may be changed at any time by the layout. 15215 * 15216 * @param left The left of this view, in pixels. 15217 */ 15218 public final void setLeft(int left) { 15219 if (left != mLeft) { 15220 final boolean matrixIsIdentity = hasIdentityMatrix(); 15221 if (matrixIsIdentity) { 15222 if (mAttachInfo != null) { 15223 int minLeft; 15224 int xLoc; 15225 if (left < mLeft) { 15226 minLeft = left; 15227 xLoc = left - mLeft; 15228 } else { 15229 minLeft = mLeft; 15230 xLoc = 0; 15231 } 15232 invalidate(xLoc, 0, mRight - minLeft, mBottom - mTop); 15233 } 15234 } else { 15235 // Double-invalidation is necessary to capture view's old and new areas 15236 invalidate(true); 15237 } 15238 15239 int oldWidth = mRight - mLeft; 15240 int height = mBottom - mTop; 15241 15242 mLeft = left; 15243 mRenderNode.setLeft(left); 15244 15245 sizeChange(mRight - mLeft, height, oldWidth, height); 15246 15247 if (!matrixIsIdentity) { 15248 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 15249 invalidate(true); 15250 } 15251 mBackgroundSizeChanged = true; 15252 mDefaultFocusHighlightSizeChanged = true; 15253 if (mForegroundInfo != null) { 15254 mForegroundInfo.mBoundsChanged = true; 15255 } 15256 invalidateParentIfNeeded(); 15257 if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) { 15258 // View was rejected last time it was drawn by its parent; this may have changed 15259 invalidateParentIfNeeded(); 15260 } 15261 } 15262 } 15263 15264 /** 15265 * Right position of this view relative to its parent. 15266 * 15267 * @return The right edge of this view, in pixels. 15268 */ 15269 @ViewDebug.CapturedViewProperty 15270 public final int getRight() { 15271 return mRight; 15272 } 15273 15274 /** 15275 * Sets the right position of this view relative to its parent. This method is meant to be called 15276 * by the layout system and should not generally be called otherwise, because the property 15277 * may be changed at any time by the layout. 15278 * 15279 * @param right The right of this view, in pixels. 15280 */ 15281 public final void setRight(int right) { 15282 if (right != mRight) { 15283 final boolean matrixIsIdentity = hasIdentityMatrix(); 15284 if (matrixIsIdentity) { 15285 if (mAttachInfo != null) { 15286 int maxRight; 15287 if (right < mRight) { 15288 maxRight = mRight; 15289 } else { 15290 maxRight = right; 15291 } 15292 invalidate(0, 0, maxRight - mLeft, mBottom - mTop); 15293 } 15294 } else { 15295 // Double-invalidation is necessary to capture view's old and new areas 15296 invalidate(true); 15297 } 15298 15299 int oldWidth = mRight - mLeft; 15300 int height = mBottom - mTop; 15301 15302 mRight = right; 15303 mRenderNode.setRight(mRight); 15304 15305 sizeChange(mRight - mLeft, height, oldWidth, height); 15306 15307 if (!matrixIsIdentity) { 15308 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 15309 invalidate(true); 15310 } 15311 mBackgroundSizeChanged = true; 15312 mDefaultFocusHighlightSizeChanged = true; 15313 if (mForegroundInfo != null) { 15314 mForegroundInfo.mBoundsChanged = true; 15315 } 15316 invalidateParentIfNeeded(); 15317 if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) { 15318 // View was rejected last time it was drawn by its parent; this may have changed 15319 invalidateParentIfNeeded(); 15320 } 15321 } 15322 } 15323 15324 private static float sanitizeFloatPropertyValue(float value, String propertyName) { 15325 return sanitizeFloatPropertyValue(value, propertyName, -Float.MAX_VALUE, Float.MAX_VALUE); 15326 } 15327 15328 private static float sanitizeFloatPropertyValue(float value, String propertyName, 15329 float min, float max) { 15330 // The expected "nothing bad happened" path 15331 if (value >= min && value <= max) return value; 15332 15333 if (value < min || value == Float.NEGATIVE_INFINITY) { 15334 if (sThrowOnInvalidFloatProperties) { 15335 throw new IllegalArgumentException("Cannot set '" + propertyName + "' to " 15336 + value + ", the value must be >= " + min); 15337 } 15338 return min; 15339 } 15340 15341 if (value > max || value == Float.POSITIVE_INFINITY) { 15342 if (sThrowOnInvalidFloatProperties) { 15343 throw new IllegalArgumentException("Cannot set '" + propertyName + "' to " 15344 + value + ", the value must be <= " + max); 15345 } 15346 return max; 15347 } 15348 15349 if (Float.isNaN(value)) { 15350 if (sThrowOnInvalidFloatProperties) { 15351 throw new IllegalArgumentException( 15352 "Cannot set '" + propertyName + "' to Float.NaN"); 15353 } 15354 return 0; // Unclear which direction this NaN went so... 0? 15355 } 15356 15357 // Shouldn't be possible to reach this. 15358 throw new IllegalStateException("How do you get here?? " + value); 15359 } 15360 15361 /** 15362 * The visual x position of this view, in pixels. This is equivalent to the 15363 * {@link #setTranslationX(float) translationX} property plus the current 15364 * {@link #getLeft() left} property. 15365 * 15366 * @return The visual x position of this view, in pixels. 15367 */ 15368 @ViewDebug.ExportedProperty(category = "drawing") 15369 public float getX() { 15370 return mLeft + getTranslationX(); 15371 } 15372 15373 /** 15374 * Sets the visual x position of this view, in pixels. This is equivalent to setting the 15375 * {@link #setTranslationX(float) translationX} property to be the difference between 15376 * the x value passed in and the current {@link #getLeft() left} property. 15377 * 15378 * @param x The visual x position of this view, in pixels. 15379 */ 15380 public void setX(float x) { 15381 setTranslationX(x - mLeft); 15382 } 15383 15384 /** 15385 * The visual y position of this view, in pixels. This is equivalent to the 15386 * {@link #setTranslationY(float) translationY} property plus the current 15387 * {@link #getTop() top} property. 15388 * 15389 * @return The visual y position of this view, in pixels. 15390 */ 15391 @ViewDebug.ExportedProperty(category = "drawing") 15392 public float getY() { 15393 return mTop + getTranslationY(); 15394 } 15395 15396 /** 15397 * Sets the visual y position of this view, in pixels. This is equivalent to setting the 15398 * {@link #setTranslationY(float) translationY} property to be the difference between 15399 * the y value passed in and the current {@link #getTop() top} property. 15400 * 15401 * @param y The visual y position of this view, in pixels. 15402 */ 15403 public void setY(float y) { 15404 setTranslationY(y - mTop); 15405 } 15406 15407 /** 15408 * The visual z position of this view, in pixels. This is equivalent to the 15409 * {@link #setTranslationZ(float) translationZ} property plus the current 15410 * {@link #getElevation() elevation} property. 15411 * 15412 * @return The visual z position of this view, in pixels. 15413 */ 15414 @ViewDebug.ExportedProperty(category = "drawing") 15415 public float getZ() { 15416 return getElevation() + getTranslationZ(); 15417 } 15418 15419 /** 15420 * Sets the visual z position of this view, in pixels. This is equivalent to setting the 15421 * {@link #setTranslationZ(float) translationZ} property to be the difference between 15422 * the x value passed in and the current {@link #getElevation() elevation} property. 15423 * 15424 * @param z The visual z position of this view, in pixels. 15425 */ 15426 public void setZ(float z) { 15427 setTranslationZ(z - getElevation()); 15428 } 15429 15430 /** 15431 * The base elevation of this view relative to its parent, in pixels. 15432 * 15433 * @return The base depth position of the view, in pixels. 15434 */ 15435 @ViewDebug.ExportedProperty(category = "drawing") 15436 public float getElevation() { 15437 return mRenderNode.getElevation(); 15438 } 15439 15440 /** 15441 * Sets the base elevation of this view, in pixels. 15442 * 15443 * @attr ref android.R.styleable#View_elevation 15444 */ 15445 public void setElevation(float elevation) { 15446 if (elevation != getElevation()) { 15447 elevation = sanitizeFloatPropertyValue(elevation, "elevation"); 15448 invalidateViewProperty(true, false); 15449 mRenderNode.setElevation(elevation); 15450 invalidateViewProperty(false, true); 15451 15452 invalidateParentIfNeededAndWasQuickRejected(); 15453 } 15454 } 15455 15456 /** 15457 * The horizontal location of this view relative to its {@link #getLeft() left} position. 15458 * This position is post-layout, in addition to wherever the object's 15459 * layout placed it. 15460 * 15461 * @return The horizontal position of this view relative to its left position, in pixels. 15462 */ 15463 @ViewDebug.ExportedProperty(category = "drawing") 15464 public float getTranslationX() { 15465 return mRenderNode.getTranslationX(); 15466 } 15467 15468 /** 15469 * Sets the horizontal location of this view relative to its {@link #getLeft() left} position. 15470 * This effectively positions the object post-layout, in addition to wherever the object's 15471 * layout placed it. 15472 * 15473 * @param translationX The horizontal position of this view relative to its left position, 15474 * in pixels. 15475 * 15476 * @attr ref android.R.styleable#View_translationX 15477 */ 15478 public void setTranslationX(float translationX) { 15479 if (translationX != getTranslationX()) { 15480 invalidateViewProperty(true, false); 15481 mRenderNode.setTranslationX(translationX); 15482 invalidateViewProperty(false, true); 15483 15484 invalidateParentIfNeededAndWasQuickRejected(); 15485 notifySubtreeAccessibilityStateChangedIfNeeded(); 15486 } 15487 } 15488 15489 /** 15490 * The vertical location of this view relative to its {@link #getTop() top} position. 15491 * This position is post-layout, in addition to wherever the object's 15492 * layout placed it. 15493 * 15494 * @return The vertical position of this view relative to its top position, 15495 * in pixels. 15496 */ 15497 @ViewDebug.ExportedProperty(category = "drawing") 15498 public float getTranslationY() { 15499 return mRenderNode.getTranslationY(); 15500 } 15501 15502 /** 15503 * Sets the vertical location of this view relative to its {@link #getTop() top} position. 15504 * This effectively positions the object post-layout, in addition to wherever the object's 15505 * layout placed it. 15506 * 15507 * @param translationY The vertical position of this view relative to its top position, 15508 * in pixels. 15509 * 15510 * @attr ref android.R.styleable#View_translationY 15511 */ 15512 public void setTranslationY(float translationY) { 15513 if (translationY != getTranslationY()) { 15514 invalidateViewProperty(true, false); 15515 mRenderNode.setTranslationY(translationY); 15516 invalidateViewProperty(false, true); 15517 15518 invalidateParentIfNeededAndWasQuickRejected(); 15519 notifySubtreeAccessibilityStateChangedIfNeeded(); 15520 } 15521 } 15522 15523 /** 15524 * The depth location of this view relative to its {@link #getElevation() elevation}. 15525 * 15526 * @return The depth of this view relative to its elevation. 15527 */ 15528 @ViewDebug.ExportedProperty(category = "drawing") 15529 public float getTranslationZ() { 15530 return mRenderNode.getTranslationZ(); 15531 } 15532 15533 /** 15534 * Sets the depth location of this view relative to its {@link #getElevation() elevation}. 15535 * 15536 * @attr ref android.R.styleable#View_translationZ 15537 */ 15538 public void setTranslationZ(float translationZ) { 15539 if (translationZ != getTranslationZ()) { 15540 translationZ = sanitizeFloatPropertyValue(translationZ, "translationZ"); 15541 invalidateViewProperty(true, false); 15542 mRenderNode.setTranslationZ(translationZ); 15543 invalidateViewProperty(false, true); 15544 15545 invalidateParentIfNeededAndWasQuickRejected(); 15546 } 15547 } 15548 15549 /** @hide */ 15550 public void setAnimationMatrix(Matrix matrix) { 15551 invalidateViewProperty(true, false); 15552 mRenderNode.setAnimationMatrix(matrix); 15553 invalidateViewProperty(false, true); 15554 15555 invalidateParentIfNeededAndWasQuickRejected(); 15556 } 15557 15558 /** 15559 * Returns the current StateListAnimator if exists. 15560 * 15561 * @return StateListAnimator or null if it does not exists 15562 * @see #setStateListAnimator(android.animation.StateListAnimator) 15563 */ 15564 public StateListAnimator getStateListAnimator() { 15565 return mStateListAnimator; 15566 } 15567 15568 /** 15569 * Attaches the provided StateListAnimator to this View. 15570 * <p> 15571 * Any previously attached StateListAnimator will be detached. 15572 * 15573 * @param stateListAnimator The StateListAnimator to update the view 15574 * @see android.animation.StateListAnimator 15575 */ 15576 public void setStateListAnimator(StateListAnimator stateListAnimator) { 15577 if (mStateListAnimator == stateListAnimator) { 15578 return; 15579 } 15580 if (mStateListAnimator != null) { 15581 mStateListAnimator.setTarget(null); 15582 } 15583 mStateListAnimator = stateListAnimator; 15584 if (stateListAnimator != null) { 15585 stateListAnimator.setTarget(this); 15586 if (isAttachedToWindow()) { 15587 stateListAnimator.setState(getDrawableState()); 15588 } 15589 } 15590 } 15591 15592 /** 15593 * Returns whether the Outline should be used to clip the contents of the View. 15594 * <p> 15595 * Note that this flag will only be respected if the View's Outline returns true from 15596 * {@link Outline#canClip()}. 15597 * 15598 * @see #setOutlineProvider(ViewOutlineProvider) 15599 * @see #setClipToOutline(boolean) 15600 */ 15601 public final boolean getClipToOutline() { 15602 return mRenderNode.getClipToOutline(); 15603 } 15604 15605 /** 15606 * Sets whether the View's Outline should be used to clip the contents of the View. 15607 * <p> 15608 * Only a single non-rectangular clip can be applied on a View at any time. 15609 * Circular clips from a {@link ViewAnimationUtils#createCircularReveal(View, int, int, float, float) 15610 * circular reveal} animation take priority over Outline clipping, and 15611 * child Outline clipping takes priority over Outline clipping done by a 15612 * parent. 15613 * <p> 15614 * Note that this flag will only be respected if the View's Outline returns true from 15615 * {@link Outline#canClip()}. 15616 * 15617 * @see #setOutlineProvider(ViewOutlineProvider) 15618 * @see #getClipToOutline() 15619 */ 15620 public void setClipToOutline(boolean clipToOutline) { 15621 damageInParent(); 15622 if (getClipToOutline() != clipToOutline) { 15623 mRenderNode.setClipToOutline(clipToOutline); 15624 } 15625 } 15626 15627 // correspond to the enum values of View_outlineProvider 15628 private static final int PROVIDER_BACKGROUND = 0; 15629 private static final int PROVIDER_NONE = 1; 15630 private static final int PROVIDER_BOUNDS = 2; 15631 private static final int PROVIDER_PADDED_BOUNDS = 3; 15632 private void setOutlineProviderFromAttribute(int providerInt) { 15633 switch (providerInt) { 15634 case PROVIDER_BACKGROUND: 15635 setOutlineProvider(ViewOutlineProvider.BACKGROUND); 15636 break; 15637 case PROVIDER_NONE: 15638 setOutlineProvider(null); 15639 break; 15640 case PROVIDER_BOUNDS: 15641 setOutlineProvider(ViewOutlineProvider.BOUNDS); 15642 break; 15643 case PROVIDER_PADDED_BOUNDS: 15644 setOutlineProvider(ViewOutlineProvider.PADDED_BOUNDS); 15645 break; 15646 } 15647 } 15648 15649 /** 15650 * Sets the {@link ViewOutlineProvider} of the view, which generates the Outline that defines 15651 * the shape of the shadow it casts, and enables outline clipping. 15652 * <p> 15653 * The default ViewOutlineProvider, {@link ViewOutlineProvider#BACKGROUND}, queries the Outline 15654 * from the View's background drawable, via {@link Drawable#getOutline(Outline)}. Changing the 15655 * outline provider with this method allows this behavior to be overridden. 15656 * <p> 15657 * If the ViewOutlineProvider is null, if querying it for an outline returns false, 15658 * or if the produced Outline is {@link Outline#isEmpty()}, shadows will not be cast. 15659 * <p> 15660 * Only outlines that return true from {@link Outline#canClip()} may be used for clipping. 15661 * 15662 * @see #setClipToOutline(boolean) 15663 * @see #getClipToOutline() 15664 * @see #getOutlineProvider() 15665 */ 15666 public void setOutlineProvider(ViewOutlineProvider provider) { 15667 mOutlineProvider = provider; 15668 invalidateOutline(); 15669 } 15670 15671 /** 15672 * Returns the current {@link ViewOutlineProvider} of the view, which generates the Outline 15673 * that defines the shape of the shadow it casts, and enables outline clipping. 15674 * 15675 * @see #setOutlineProvider(ViewOutlineProvider) 15676 */ 15677 public ViewOutlineProvider getOutlineProvider() { 15678 return mOutlineProvider; 15679 } 15680 15681 /** 15682 * Called to rebuild this View's Outline from its {@link ViewOutlineProvider outline provider} 15683 * 15684 * @see #setOutlineProvider(ViewOutlineProvider) 15685 */ 15686 public void invalidateOutline() { 15687 rebuildOutline(); 15688 15689 notifySubtreeAccessibilityStateChangedIfNeeded(); 15690 invalidateViewProperty(false, false); 15691 } 15692 15693 /** 15694 * Internal version of {@link #invalidateOutline()} which invalidates the 15695 * outline without invalidating the view itself. This is intended to be called from 15696 * within methods in the View class itself which are the result of the view being 15697 * invalidated already. For example, when we are drawing the background of a View, 15698 * we invalidate the outline in case it changed in the meantime, but we do not 15699 * need to invalidate the view because we're already drawing the background as part 15700 * of drawing the view in response to an earlier invalidation of the view. 15701 */ 15702 private void rebuildOutline() { 15703 // Unattached views ignore this signal, and outline is recomputed in onAttachedToWindow() 15704 if (mAttachInfo == null) return; 15705 15706 if (mOutlineProvider == null) { 15707 // no provider, remove outline 15708 mRenderNode.setOutline(null); 15709 } else { 15710 final Outline outline = mAttachInfo.mTmpOutline; 15711 outline.setEmpty(); 15712 outline.setAlpha(1.0f); 15713 15714 mOutlineProvider.getOutline(this, outline); 15715 mRenderNode.setOutline(outline); 15716 } 15717 } 15718 15719 /** 15720 * HierarchyViewer only 15721 * 15722 * @hide 15723 */ 15724 @ViewDebug.ExportedProperty(category = "drawing") 15725 public boolean hasShadow() { 15726 return mRenderNode.hasShadow(); 15727 } 15728 15729 /** 15730 * Sets the color of the spot shadow that is drawn when the view has a positive Z or 15731 * elevation value. 15732 * <p> 15733 * By default the shadow color is black. Generally, this color will be opaque so the intensity 15734 * of the shadow is consistent between different views with different colors. 15735 * <p> 15736 * The opacity of the final spot shadow is a function of the shadow caster height, the 15737 * alpha channel of the outlineSpotShadowColor (typically opaque), and the 15738 * {@link android.R.attr#spotShadowAlpha} theme attribute. 15739 * 15740 * @attr ref android.R.styleable#View_outlineSpotShadowColor 15741 * @param color The color this View will cast for its elevation spot shadow. 15742 */ 15743 public void setOutlineSpotShadowColor(@ColorInt int color) { 15744 if (mRenderNode.setSpotShadowColor(color)) { 15745 invalidateViewProperty(true, true); 15746 } 15747 } 15748 15749 /** 15750 * @return The shadow color set by {@link #setOutlineSpotShadowColor(int)}, or black if nothing 15751 * was set 15752 */ 15753 public @ColorInt int getOutlineSpotShadowColor() { 15754 return mRenderNode.getSpotShadowColor(); 15755 } 15756 15757 /** 15758 * Sets the color of the ambient shadow that is drawn when the view has a positive Z or 15759 * elevation value. 15760 * <p> 15761 * By default the shadow color is black. Generally, this color will be opaque so the intensity 15762 * of the shadow is consistent between different views with different colors. 15763 * <p> 15764 * The opacity of the final ambient shadow is a function of the shadow caster height, the 15765 * alpha channel of the outlineAmbientShadowColor (typically opaque), and the 15766 * {@link android.R.attr#ambientShadowAlpha} theme attribute. 15767 * 15768 * @attr ref android.R.styleable#View_outlineAmbientShadowColor 15769 * @param color The color this View will cast for its elevation shadow. 15770 */ 15771 public void setOutlineAmbientShadowColor(@ColorInt int color) { 15772 if (mRenderNode.setAmbientShadowColor(color)) { 15773 invalidateViewProperty(true, true); 15774 } 15775 } 15776 15777 /** 15778 * @return The shadow color set by {@link #setOutlineAmbientShadowColor(int)}, or black if 15779 * nothing was set 15780 */ 15781 public @ColorInt int getOutlineAmbientShadowColor() { 15782 return mRenderNode.getAmbientShadowColor(); 15783 } 15784 15785 15786 /** @hide */ 15787 public void setRevealClip(boolean shouldClip, float x, float y, float radius) { 15788 mRenderNode.setRevealClip(shouldClip, x, y, radius); 15789 invalidateViewProperty(false, false); 15790 } 15791 15792 /** 15793 * Hit rectangle in parent's coordinates 15794 * 15795 * @param outRect The hit rectangle of the view. 15796 */ 15797 public void getHitRect(Rect outRect) { 15798 if (hasIdentityMatrix() || mAttachInfo == null) { 15799 outRect.set(mLeft, mTop, mRight, mBottom); 15800 } else { 15801 final RectF tmpRect = mAttachInfo.mTmpTransformRect; 15802 tmpRect.set(0, 0, getWidth(), getHeight()); 15803 getMatrix().mapRect(tmpRect); // TODO: mRenderNode.mapRect(tmpRect) 15804 outRect.set((int) tmpRect.left + mLeft, (int) tmpRect.top + mTop, 15805 (int) tmpRect.right + mLeft, (int) tmpRect.bottom + mTop); 15806 } 15807 } 15808 15809 /** 15810 * Determines whether the given point, in local coordinates is inside the view. 15811 */ 15812 /*package*/ final boolean pointInView(float localX, float localY) { 15813 return pointInView(localX, localY, 0); 15814 } 15815 15816 /** 15817 * Utility method to determine whether the given point, in local coordinates, 15818 * is inside the view, where the area of the view is expanded by the slop factor. 15819 * This method is called while processing touch-move events to determine if the event 15820 * is still within the view. 15821 * 15822 * @hide 15823 */ 15824 public boolean pointInView(float localX, float localY, float slop) { 15825 return localX >= -slop && localY >= -slop && localX < ((mRight - mLeft) + slop) && 15826 localY < ((mBottom - mTop) + slop); 15827 } 15828 15829 /** 15830 * When a view has focus and the user navigates away from it, the next view is searched for 15831 * starting from the rectangle filled in by this method. 15832 * 15833 * By default, the rectangle is the {@link #getDrawingRect(android.graphics.Rect)}) 15834 * of the view. However, if your view maintains some idea of internal selection, 15835 * such as a cursor, or a selected row or column, you should override this method and 15836 * fill in a more specific rectangle. 15837 * 15838 * @param r The rectangle to fill in, in this view's coordinates. 15839 */ 15840 public void getFocusedRect(Rect r) { 15841 getDrawingRect(r); 15842 } 15843 15844 /** 15845 * If some part of this view is not clipped by any of its parents, then 15846 * return that area in r in global (root) coordinates. To convert r to local 15847 * coordinates (without taking possible View rotations into account), offset 15848 * it by -globalOffset (e.g. r.offset(-globalOffset.x, -globalOffset.y)). 15849 * If the view is completely clipped or translated out, return false. 15850 * 15851 * @param r If true is returned, r holds the global coordinates of the 15852 * visible portion of this view. 15853 * @param globalOffset If true is returned, globalOffset holds the dx,dy 15854 * between this view and its root. globalOffet may be null. 15855 * @return true if r is non-empty (i.e. part of the view is visible at the 15856 * root level. 15857 */ 15858 public boolean getGlobalVisibleRect(Rect r, Point globalOffset) { 15859 int width = mRight - mLeft; 15860 int height = mBottom - mTop; 15861 if (width > 0 && height > 0) { 15862 r.set(0, 0, width, height); 15863 if (globalOffset != null) { 15864 globalOffset.set(-mScrollX, -mScrollY); 15865 } 15866 return mParent == null || mParent.getChildVisibleRect(this, r, globalOffset); 15867 } 15868 return false; 15869 } 15870 15871 public final boolean getGlobalVisibleRect(Rect r) { 15872 return getGlobalVisibleRect(r, null); 15873 } 15874 15875 public final boolean getLocalVisibleRect(Rect r) { 15876 final Point offset = mAttachInfo != null ? mAttachInfo.mPoint : new Point(); 15877 if (getGlobalVisibleRect(r, offset)) { 15878 r.offset(-offset.x, -offset.y); // make r local 15879 return true; 15880 } 15881 return false; 15882 } 15883 15884 /** 15885 * Offset this view's vertical location by the specified number of pixels. 15886 * 15887 * @param offset the number of pixels to offset the view by 15888 */ 15889 public void offsetTopAndBottom(int offset) { 15890 if (offset != 0) { 15891 final boolean matrixIsIdentity = hasIdentityMatrix(); 15892 if (matrixIsIdentity) { 15893 if (isHardwareAccelerated()) { 15894 invalidateViewProperty(false, false); 15895 } else { 15896 final ViewParent p = mParent; 15897 if (p != null && mAttachInfo != null) { 15898 final Rect r = mAttachInfo.mTmpInvalRect; 15899 int minTop; 15900 int maxBottom; 15901 int yLoc; 15902 if (offset < 0) { 15903 minTop = mTop + offset; 15904 maxBottom = mBottom; 15905 yLoc = offset; 15906 } else { 15907 minTop = mTop; 15908 maxBottom = mBottom + offset; 15909 yLoc = 0; 15910 } 15911 r.set(0, yLoc, mRight - mLeft, maxBottom - minTop); 15912 p.invalidateChild(this, r); 15913 } 15914 } 15915 } else { 15916 invalidateViewProperty(false, false); 15917 } 15918 15919 mTop += offset; 15920 mBottom += offset; 15921 mRenderNode.offsetTopAndBottom(offset); 15922 if (isHardwareAccelerated()) { 15923 invalidateViewProperty(false, false); 15924 invalidateParentIfNeededAndWasQuickRejected(); 15925 } else { 15926 if (!matrixIsIdentity) { 15927 invalidateViewProperty(false, true); 15928 } 15929 invalidateParentIfNeeded(); 15930 } 15931 notifySubtreeAccessibilityStateChangedIfNeeded(); 15932 } 15933 } 15934 15935 /** 15936 * Offset this view's horizontal location by the specified amount of pixels. 15937 * 15938 * @param offset the number of pixels to offset the view by 15939 */ 15940 public void offsetLeftAndRight(int offset) { 15941 if (offset != 0) { 15942 final boolean matrixIsIdentity = hasIdentityMatrix(); 15943 if (matrixIsIdentity) { 15944 if (isHardwareAccelerated()) { 15945 invalidateViewProperty(false, false); 15946 } else { 15947 final ViewParent p = mParent; 15948 if (p != null && mAttachInfo != null) { 15949 final Rect r = mAttachInfo.mTmpInvalRect; 15950 int minLeft; 15951 int maxRight; 15952 if (offset < 0) { 15953 minLeft = mLeft + offset; 15954 maxRight = mRight; 15955 } else { 15956 minLeft = mLeft; 15957 maxRight = mRight + offset; 15958 } 15959 r.set(0, 0, maxRight - minLeft, mBottom - mTop); 15960 p.invalidateChild(this, r); 15961 } 15962 } 15963 } else { 15964 invalidateViewProperty(false, false); 15965 } 15966 15967 mLeft += offset; 15968 mRight += offset; 15969 mRenderNode.offsetLeftAndRight(offset); 15970 if (isHardwareAccelerated()) { 15971 invalidateViewProperty(false, false); 15972 invalidateParentIfNeededAndWasQuickRejected(); 15973 } else { 15974 if (!matrixIsIdentity) { 15975 invalidateViewProperty(false, true); 15976 } 15977 invalidateParentIfNeeded(); 15978 } 15979 notifySubtreeAccessibilityStateChangedIfNeeded(); 15980 } 15981 } 15982 15983 /** 15984 * Get the LayoutParams associated with this view. All views should have 15985 * layout parameters. These supply parameters to the <i>parent</i> of this 15986 * view specifying how it should be arranged. There are many subclasses of 15987 * ViewGroup.LayoutParams, and these correspond to the different subclasses 15988 * of ViewGroup that are responsible for arranging their children. 15989 * 15990 * This method may return null if this View is not attached to a parent 15991 * ViewGroup or {@link #setLayoutParams(android.view.ViewGroup.LayoutParams)} 15992 * was not invoked successfully. When a View is attached to a parent 15993 * ViewGroup, this method must not return null. 15994 * 15995 * @return The LayoutParams associated with this view, or null if no 15996 * parameters have been set yet 15997 */ 15998 @ViewDebug.ExportedProperty(deepExport = true, prefix = "layout_") 15999 public ViewGroup.LayoutParams getLayoutParams() { 16000 return mLayoutParams; 16001 } 16002 16003 /** 16004 * Set the layout parameters associated with this view. These supply 16005 * parameters to the <i>parent</i> of this view specifying how it should be 16006 * arranged. There are many subclasses of ViewGroup.LayoutParams, and these 16007 * correspond to the different subclasses of ViewGroup that are responsible 16008 * for arranging their children. 16009 * 16010 * @param params The layout parameters for this view, cannot be null 16011 */ 16012 public void setLayoutParams(ViewGroup.LayoutParams params) { 16013 if (params == null) { 16014 throw new NullPointerException("Layout parameters cannot be null"); 16015 } 16016 mLayoutParams = params; 16017 resolveLayoutParams(); 16018 if (mParent instanceof ViewGroup) { 16019 ((ViewGroup) mParent).onSetLayoutParams(this, params); 16020 } 16021 requestLayout(); 16022 } 16023 16024 /** 16025 * Resolve the layout parameters depending on the resolved layout direction 16026 * 16027 * @hide 16028 */ 16029 public void resolveLayoutParams() { 16030 if (mLayoutParams != null) { 16031 mLayoutParams.resolveLayoutDirection(getLayoutDirection()); 16032 } 16033 } 16034 16035 /** 16036 * Set the scrolled position of your view. This will cause a call to 16037 * {@link #onScrollChanged(int, int, int, int)} and the view will be 16038 * invalidated. 16039 * @param x the x position to scroll to 16040 * @param y the y position to scroll to 16041 */ 16042 public void scrollTo(int x, int y) { 16043 if (mScrollX != x || mScrollY != y) { 16044 int oldX = mScrollX; 16045 int oldY = mScrollY; 16046 mScrollX = x; 16047 mScrollY = y; 16048 invalidateParentCaches(); 16049 onScrollChanged(mScrollX, mScrollY, oldX, oldY); 16050 if (!awakenScrollBars()) { 16051 postInvalidateOnAnimation(); 16052 } 16053 } 16054 } 16055 16056 /** 16057 * Move the scrolled position of your view. This will cause a call to 16058 * {@link #onScrollChanged(int, int, int, int)} and the view will be 16059 * invalidated. 16060 * @param x the amount of pixels to scroll by horizontally 16061 * @param y the amount of pixels to scroll by vertically 16062 */ 16063 public void scrollBy(int x, int y) { 16064 scrollTo(mScrollX + x, mScrollY + y); 16065 } 16066 16067 /** 16068 * <p>Trigger the scrollbars to draw. When invoked this method starts an 16069 * animation to fade the scrollbars out after a default delay. If a subclass 16070 * provides animated scrolling, the start delay should equal the duration 16071 * of the scrolling animation.</p> 16072 * 16073 * <p>The animation starts only if at least one of the scrollbars is 16074 * enabled, as specified by {@link #isHorizontalScrollBarEnabled()} and 16075 * {@link #isVerticalScrollBarEnabled()}. When the animation is started, 16076 * this method returns true, and false otherwise. If the animation is 16077 * started, this method calls {@link #invalidate()}; in that case the 16078 * caller should not call {@link #invalidate()}.</p> 16079 * 16080 * <p>This method should be invoked every time a subclass directly updates 16081 * the scroll parameters.</p> 16082 * 16083 * <p>This method is automatically invoked by {@link #scrollBy(int, int)} 16084 * and {@link #scrollTo(int, int)}.</p> 16085 * 16086 * @return true if the animation is played, false otherwise 16087 * 16088 * @see #awakenScrollBars(int) 16089 * @see #scrollBy(int, int) 16090 * @see #scrollTo(int, int) 16091 * @see #isHorizontalScrollBarEnabled() 16092 * @see #isVerticalScrollBarEnabled() 16093 * @see #setHorizontalScrollBarEnabled(boolean) 16094 * @see #setVerticalScrollBarEnabled(boolean) 16095 */ 16096 protected boolean awakenScrollBars() { 16097 return mScrollCache != null && 16098 awakenScrollBars(mScrollCache.scrollBarDefaultDelayBeforeFade, true); 16099 } 16100 16101 /** 16102 * Trigger the scrollbars to draw. 16103 * This method differs from awakenScrollBars() only in its default duration. 16104 * initialAwakenScrollBars() will show the scroll bars for longer than 16105 * usual to give the user more of a chance to notice them. 16106 * 16107 * @return true if the animation is played, false otherwise. 16108 */ 16109 private boolean initialAwakenScrollBars() { 16110 return mScrollCache != null && 16111 awakenScrollBars(mScrollCache.scrollBarDefaultDelayBeforeFade * 4, true); 16112 } 16113 16114 /** 16115 * <p> 16116 * Trigger the scrollbars to draw. When invoked this method starts an 16117 * animation to fade the scrollbars out after a fixed delay. If a subclass 16118 * provides animated scrolling, the start delay should equal the duration of 16119 * the scrolling animation. 16120 * </p> 16121 * 16122 * <p> 16123 * The animation starts only if at least one of the scrollbars is enabled, 16124 * as specified by {@link #isHorizontalScrollBarEnabled()} and 16125 * {@link #isVerticalScrollBarEnabled()}. When the animation is started, 16126 * this method returns true, and false otherwise. If the animation is 16127 * started, this method calls {@link #invalidate()}; in that case the caller 16128 * should not call {@link #invalidate()}. 16129 * </p> 16130 * 16131 * <p> 16132 * This method should be invoked every time a subclass directly updates the 16133 * scroll parameters. 16134 * </p> 16135 * 16136 * @param startDelay the delay, in milliseconds, after which the animation 16137 * should start; when the delay is 0, the animation starts 16138 * immediately 16139 * @return true if the animation is played, false otherwise 16140 * 16141 * @see #scrollBy(int, int) 16142 * @see #scrollTo(int, int) 16143 * @see #isHorizontalScrollBarEnabled() 16144 * @see #isVerticalScrollBarEnabled() 16145 * @see #setHorizontalScrollBarEnabled(boolean) 16146 * @see #setVerticalScrollBarEnabled(boolean) 16147 */ 16148 protected boolean awakenScrollBars(int startDelay) { 16149 return awakenScrollBars(startDelay, true); 16150 } 16151 16152 /** 16153 * <p> 16154 * Trigger the scrollbars to draw. When invoked this method starts an 16155 * animation to fade the scrollbars out after a fixed delay. If a subclass 16156 * provides animated scrolling, the start delay should equal the duration of 16157 * the scrolling animation. 16158 * </p> 16159 * 16160 * <p> 16161 * The animation starts only if at least one of the scrollbars is enabled, 16162 * as specified by {@link #isHorizontalScrollBarEnabled()} and 16163 * {@link #isVerticalScrollBarEnabled()}. When the animation is started, 16164 * this method returns true, and false otherwise. If the animation is 16165 * started, this method calls {@link #invalidate()} if the invalidate parameter 16166 * is set to true; in that case the caller 16167 * should not call {@link #invalidate()}. 16168 * </p> 16169 * 16170 * <p> 16171 * This method should be invoked every time a subclass directly updates the 16172 * scroll parameters. 16173 * </p> 16174 * 16175 * @param startDelay the delay, in milliseconds, after which the animation 16176 * should start; when the delay is 0, the animation starts 16177 * immediately 16178 * 16179 * @param invalidate Whether this method should call invalidate 16180 * 16181 * @return true if the animation is played, false otherwise 16182 * 16183 * @see #scrollBy(int, int) 16184 * @see #scrollTo(int, int) 16185 * @see #isHorizontalScrollBarEnabled() 16186 * @see #isVerticalScrollBarEnabled() 16187 * @see #setHorizontalScrollBarEnabled(boolean) 16188 * @see #setVerticalScrollBarEnabled(boolean) 16189 */ 16190 protected boolean awakenScrollBars(int startDelay, boolean invalidate) { 16191 final ScrollabilityCache scrollCache = mScrollCache; 16192 16193 if (scrollCache == null || !scrollCache.fadeScrollBars) { 16194 return false; 16195 } 16196 16197 if (scrollCache.scrollBar == null) { 16198 scrollCache.scrollBar = new ScrollBarDrawable(); 16199 scrollCache.scrollBar.setState(getDrawableState()); 16200 scrollCache.scrollBar.setCallback(this); 16201 } 16202 16203 if (isHorizontalScrollBarEnabled() || isVerticalScrollBarEnabled()) { 16204 16205 if (invalidate) { 16206 // Invalidate to show the scrollbars 16207 postInvalidateOnAnimation(); 16208 } 16209 16210 if (scrollCache.state == ScrollabilityCache.OFF) { 16211 // FIXME: this is copied from WindowManagerService. 16212 // We should get this value from the system when it 16213 // is possible to do so. 16214 final int KEY_REPEAT_FIRST_DELAY = 750; 16215 startDelay = Math.max(KEY_REPEAT_FIRST_DELAY, startDelay); 16216 } 16217 16218 // Tell mScrollCache when we should start fading. This may 16219 // extend the fade start time if one was already scheduled 16220 long fadeStartTime = AnimationUtils.currentAnimationTimeMillis() + startDelay; 16221 scrollCache.fadeStartTime = fadeStartTime; 16222 scrollCache.state = ScrollabilityCache.ON; 16223 16224 // Schedule our fader to run, unscheduling any old ones first 16225 if (mAttachInfo != null) { 16226 mAttachInfo.mHandler.removeCallbacks(scrollCache); 16227 mAttachInfo.mHandler.postAtTime(scrollCache, fadeStartTime); 16228 } 16229 16230 return true; 16231 } 16232 16233 return false; 16234 } 16235 16236 /** 16237 * Do not invalidate views which are not visible and which are not running an animation. They 16238 * will not get drawn and they should not set dirty flags as if they will be drawn 16239 */ 16240 private boolean skipInvalidate() { 16241 return (mViewFlags & VISIBILITY_MASK) != VISIBLE && mCurrentAnimation == null && 16242 (!(mParent instanceof ViewGroup) || 16243 !((ViewGroup) mParent).isViewTransitioning(this)); 16244 } 16245 16246 /** 16247 * Mark the area defined by dirty as needing to be drawn. If the view is 16248 * visible, {@link #onDraw(android.graphics.Canvas)} will be called at some 16249 * point in the future. 16250 * <p> 16251 * This must be called from a UI thread. To call from a non-UI thread, call 16252 * {@link #postInvalidate()}. 16253 * <p> 16254 * <b>WARNING:</b> In API 19 and below, this method may be destructive to 16255 * {@code dirty}. 16256 * 16257 * @param dirty the rectangle representing the bounds of the dirty region 16258 * 16259 * @deprecated The switch to hardware accelerated rendering in API 14 reduced 16260 * the importance of the dirty rectangle. In API 21 the given rectangle is 16261 * ignored entirely in favor of an internally-calculated area instead. 16262 * Because of this, clients are encouraged to just call {@link #invalidate()}. 16263 */ 16264 @Deprecated 16265 public void invalidate(Rect dirty) { 16266 final int scrollX = mScrollX; 16267 final int scrollY = mScrollY; 16268 invalidateInternal(dirty.left - scrollX, dirty.top - scrollY, 16269 dirty.right - scrollX, dirty.bottom - scrollY, true, false); 16270 } 16271 16272 /** 16273 * Mark the area defined by the rect (l,t,r,b) as needing to be drawn. The 16274 * coordinates of the dirty rect are relative to the view. If the view is 16275 * visible, {@link #onDraw(android.graphics.Canvas)} will be called at some 16276 * point in the future. 16277 * <p> 16278 * This must be called from a UI thread. To call from a non-UI thread, call 16279 * {@link #postInvalidate()}. 16280 * 16281 * @param l the left position of the dirty region 16282 * @param t the top position of the dirty region 16283 * @param r the right position of the dirty region 16284 * @param b the bottom position of the dirty region 16285 * 16286 * @deprecated The switch to hardware accelerated rendering in API 14 reduced 16287 * the importance of the dirty rectangle. In API 21 the given rectangle is 16288 * ignored entirely in favor of an internally-calculated area instead. 16289 * Because of this, clients are encouraged to just call {@link #invalidate()}. 16290 */ 16291 @Deprecated 16292 public void invalidate(int l, int t, int r, int b) { 16293 final int scrollX = mScrollX; 16294 final int scrollY = mScrollY; 16295 invalidateInternal(l - scrollX, t - scrollY, r - scrollX, b - scrollY, true, false); 16296 } 16297 16298 /** 16299 * Invalidate the whole view. If the view is visible, 16300 * {@link #onDraw(android.graphics.Canvas)} will be called at some point in 16301 * the future. 16302 * <p> 16303 * This must be called from a UI thread. To call from a non-UI thread, call 16304 * {@link #postInvalidate()}. 16305 */ 16306 public void invalidate() { 16307 invalidate(true); 16308 } 16309 16310 /** 16311 * This is where the invalidate() work actually happens. A full invalidate() 16312 * causes the drawing cache to be invalidated, but this function can be 16313 * called with invalidateCache set to false to skip that invalidation step 16314 * for cases that do not need it (for example, a component that remains at 16315 * the same dimensions with the same content). 16316 * 16317 * @param invalidateCache Whether the drawing cache for this view should be 16318 * invalidated as well. This is usually true for a full 16319 * invalidate, but may be set to false if the View's contents or 16320 * dimensions have not changed. 16321 * @hide 16322 */ 16323 public void invalidate(boolean invalidateCache) { 16324 invalidateInternal(0, 0, mRight - mLeft, mBottom - mTop, invalidateCache, true); 16325 } 16326 16327 void invalidateInternal(int l, int t, int r, int b, boolean invalidateCache, 16328 boolean fullInvalidate) { 16329 if (mGhostView != null) { 16330 mGhostView.invalidate(true); 16331 return; 16332 } 16333 16334 if (skipInvalidate()) { 16335 return; 16336 } 16337 16338 if ((mPrivateFlags & (PFLAG_DRAWN | PFLAG_HAS_BOUNDS)) == (PFLAG_DRAWN | PFLAG_HAS_BOUNDS) 16339 || (invalidateCache && (mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == PFLAG_DRAWING_CACHE_VALID) 16340 || (mPrivateFlags & PFLAG_INVALIDATED) != PFLAG_INVALIDATED 16341 || (fullInvalidate && isOpaque() != mLastIsOpaque)) { 16342 if (fullInvalidate) { 16343 mLastIsOpaque = isOpaque(); 16344 mPrivateFlags &= ~PFLAG_DRAWN; 16345 } 16346 16347 mPrivateFlags |= PFLAG_DIRTY; 16348 16349 if (invalidateCache) { 16350 mPrivateFlags |= PFLAG_INVALIDATED; 16351 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; 16352 } 16353 16354 // Propagate the damage rectangle to the parent view. 16355 final AttachInfo ai = mAttachInfo; 16356 final ViewParent p = mParent; 16357 if (p != null && ai != null && l < r && t < b) { 16358 final Rect damage = ai.mTmpInvalRect; 16359 damage.set(l, t, r, b); 16360 p.invalidateChild(this, damage); 16361 } 16362 16363 // Damage the entire projection receiver, if necessary. 16364 if (mBackground != null && mBackground.isProjected()) { 16365 final View receiver = getProjectionReceiver(); 16366 if (receiver != null) { 16367 receiver.damageInParent(); 16368 } 16369 } 16370 } 16371 } 16372 16373 /** 16374 * @return this view's projection receiver, or {@code null} if none exists 16375 */ 16376 private View getProjectionReceiver() { 16377 ViewParent p = getParent(); 16378 while (p != null && p instanceof View) { 16379 final View v = (View) p; 16380 if (v.isProjectionReceiver()) { 16381 return v; 16382 } 16383 p = p.getParent(); 16384 } 16385 16386 return null; 16387 } 16388 16389 /** 16390 * @return whether the view is a projection receiver 16391 */ 16392 private boolean isProjectionReceiver() { 16393 return mBackground != null; 16394 } 16395 16396 /** 16397 * Quick invalidation for View property changes (alpha, translationXY, etc.). We don't want to 16398 * set any flags or handle all of the cases handled by the default invalidation methods. 16399 * Instead, we just want to schedule a traversal in ViewRootImpl with the appropriate 16400 * dirty rect. This method calls into fast invalidation methods in ViewGroup that 16401 * walk up the hierarchy, transforming the dirty rect as necessary. 16402 * 16403 * The method also handles normal invalidation logic if display list properties are not 16404 * being used in this view. The invalidateParent and forceRedraw flags are used by that 16405 * backup approach, to handle these cases used in the various property-setting methods. 16406 * 16407 * @param invalidateParent Force a call to invalidateParentCaches() if display list properties 16408 * are not being used in this view 16409 * @param forceRedraw Mark the view as DRAWN to force the invalidation to propagate, if display 16410 * list properties are not being used in this view 16411 */ 16412 void invalidateViewProperty(boolean invalidateParent, boolean forceRedraw) { 16413 if (!isHardwareAccelerated() 16414 || !mRenderNode.isValid() 16415 || (mPrivateFlags & PFLAG_DRAW_ANIMATION) != 0) { 16416 if (invalidateParent) { 16417 invalidateParentCaches(); 16418 } 16419 if (forceRedraw) { 16420 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 16421 } 16422 invalidate(false); 16423 } else { 16424 damageInParent(); 16425 } 16426 } 16427 16428 /** 16429 * Tells the parent view to damage this view's bounds. 16430 * 16431 * @hide 16432 */ 16433 protected void damageInParent() { 16434 if (mParent != null && mAttachInfo != null) { 16435 mParent.onDescendantInvalidated(this, this); 16436 } 16437 } 16438 16439 /** 16440 * Utility method to transform a given Rect by the current matrix of this view. 16441 */ 16442 void transformRect(final Rect rect) { 16443 if (!getMatrix().isIdentity()) { 16444 RectF boundingRect = mAttachInfo.mTmpTransformRect; 16445 boundingRect.set(rect); 16446 getMatrix().mapRect(boundingRect); 16447 rect.set((int) Math.floor(boundingRect.left), 16448 (int) Math.floor(boundingRect.top), 16449 (int) Math.ceil(boundingRect.right), 16450 (int) Math.ceil(boundingRect.bottom)); 16451 } 16452 } 16453 16454 /** 16455 * Used to indicate that the parent of this view should clear its caches. This functionality 16456 * is used to force the parent to rebuild its display list (when hardware-accelerated), 16457 * which is necessary when various parent-managed properties of the view change, such as 16458 * alpha, translationX/Y, scrollX/Y, scaleX/Y, and rotation/X/Y. This method only 16459 * clears the parent caches and does not causes an invalidate event. 16460 * 16461 * @hide 16462 */ 16463 protected void invalidateParentCaches() { 16464 if (mParent instanceof View) { 16465 ((View) mParent).mPrivateFlags |= PFLAG_INVALIDATED; 16466 } 16467 } 16468 16469 /** 16470 * Used to indicate that the parent of this view should be invalidated. This functionality 16471 * is used to force the parent to rebuild its display list (when hardware-accelerated), 16472 * which is necessary when various parent-managed properties of the view change, such as 16473 * alpha, translationX/Y, scrollX/Y, scaleX/Y, and rotation/X/Y. This method will propagate 16474 * an invalidation event to the parent. 16475 * 16476 * @hide 16477 */ 16478 protected void invalidateParentIfNeeded() { 16479 if (isHardwareAccelerated() && mParent instanceof View) { 16480 ((View) mParent).invalidate(true); 16481 } 16482 } 16483 16484 /** 16485 * @hide 16486 */ 16487 protected void invalidateParentIfNeededAndWasQuickRejected() { 16488 if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) != 0) { 16489 // View was rejected last time it was drawn by its parent; this may have changed 16490 invalidateParentIfNeeded(); 16491 } 16492 } 16493 16494 /** 16495 * Indicates whether this View is opaque. An opaque View guarantees that it will 16496 * draw all the pixels overlapping its bounds using a fully opaque color. 16497 * 16498 * Subclasses of View should override this method whenever possible to indicate 16499 * whether an instance is opaque. Opaque Views are treated in a special way by 16500 * the View hierarchy, possibly allowing it to perform optimizations during 16501 * invalidate/draw passes. 16502 * 16503 * @return True if this View is guaranteed to be fully opaque, false otherwise. 16504 */ 16505 @ViewDebug.ExportedProperty(category = "drawing") 16506 public boolean isOpaque() { 16507 return (mPrivateFlags & PFLAG_OPAQUE_MASK) == PFLAG_OPAQUE_MASK && 16508 getFinalAlpha() >= 1.0f; 16509 } 16510 16511 /** 16512 * @hide 16513 */ 16514 protected void computeOpaqueFlags() { 16515 // Opaque if: 16516 // - Has a background 16517 // - Background is opaque 16518 // - Doesn't have scrollbars or scrollbars overlay 16519 16520 if (mBackground != null && mBackground.getOpacity() == PixelFormat.OPAQUE) { 16521 mPrivateFlags |= PFLAG_OPAQUE_BACKGROUND; 16522 } else { 16523 mPrivateFlags &= ~PFLAG_OPAQUE_BACKGROUND; 16524 } 16525 16526 final int flags = mViewFlags; 16527 if (((flags & SCROLLBARS_VERTICAL) == 0 && (flags & SCROLLBARS_HORIZONTAL) == 0) || 16528 (flags & SCROLLBARS_STYLE_MASK) == SCROLLBARS_INSIDE_OVERLAY || 16529 (flags & SCROLLBARS_STYLE_MASK) == SCROLLBARS_OUTSIDE_OVERLAY) { 16530 mPrivateFlags |= PFLAG_OPAQUE_SCROLLBARS; 16531 } else { 16532 mPrivateFlags &= ~PFLAG_OPAQUE_SCROLLBARS; 16533 } 16534 } 16535 16536 /** 16537 * @hide 16538 */ 16539 protected boolean hasOpaqueScrollbars() { 16540 return (mPrivateFlags & PFLAG_OPAQUE_SCROLLBARS) == PFLAG_OPAQUE_SCROLLBARS; 16541 } 16542 16543 /** 16544 * @return A handler associated with the thread running the View. This 16545 * handler can be used to pump events in the UI events queue. 16546 */ 16547 public Handler getHandler() { 16548 final AttachInfo attachInfo = mAttachInfo; 16549 if (attachInfo != null) { 16550 return attachInfo.mHandler; 16551 } 16552 return null; 16553 } 16554 16555 /** 16556 * Returns the queue of runnable for this view. 16557 * 16558 * @return the queue of runnables for this view 16559 */ 16560 private HandlerActionQueue getRunQueue() { 16561 if (mRunQueue == null) { 16562 mRunQueue = new HandlerActionQueue(); 16563 } 16564 return mRunQueue; 16565 } 16566 16567 /** 16568 * Gets the view root associated with the View. 16569 * @return The view root, or null if none. 16570 * @hide 16571 */ 16572 public ViewRootImpl getViewRootImpl() { 16573 if (mAttachInfo != null) { 16574 return mAttachInfo.mViewRootImpl; 16575 } 16576 return null; 16577 } 16578 16579 /** 16580 * @hide 16581 */ 16582 public ThreadedRenderer getThreadedRenderer() { 16583 return mAttachInfo != null ? mAttachInfo.mThreadedRenderer : null; 16584 } 16585 16586 /** 16587 * <p>Causes the Runnable to be added to the message queue. 16588 * The runnable will be run on the user interface thread.</p> 16589 * 16590 * @param action The Runnable that will be executed. 16591 * 16592 * @return Returns true if the Runnable was successfully placed in to the 16593 * message queue. Returns false on failure, usually because the 16594 * looper processing the message queue is exiting. 16595 * 16596 * @see #postDelayed 16597 * @see #removeCallbacks 16598 */ 16599 public boolean post(Runnable action) { 16600 final AttachInfo attachInfo = mAttachInfo; 16601 if (attachInfo != null) { 16602 return attachInfo.mHandler.post(action); 16603 } 16604 16605 // Postpone the runnable until we know on which thread it needs to run. 16606 // Assume that the runnable will be successfully placed after attach. 16607 getRunQueue().post(action); 16608 return true; 16609 } 16610 16611 /** 16612 * <p>Causes the Runnable to be added to the message queue, to be run 16613 * after the specified amount of time elapses. 16614 * The runnable will be run on the user interface thread.</p> 16615 * 16616 * @param action The Runnable that will be executed. 16617 * @param delayMillis The delay (in milliseconds) until the Runnable 16618 * will be executed. 16619 * 16620 * @return true if the Runnable was successfully placed in to the 16621 * message queue. Returns false on failure, usually because the 16622 * looper processing the message queue is exiting. Note that a 16623 * result of true does not mean the Runnable will be processed -- 16624 * if the looper is quit before the delivery time of the message 16625 * occurs then the message will be dropped. 16626 * 16627 * @see #post 16628 * @see #removeCallbacks 16629 */ 16630 public boolean postDelayed(Runnable action, long delayMillis) { 16631 final AttachInfo attachInfo = mAttachInfo; 16632 if (attachInfo != null) { 16633 return attachInfo.mHandler.postDelayed(action, delayMillis); 16634 } 16635 16636 // Postpone the runnable until we know on which thread it needs to run. 16637 // Assume that the runnable will be successfully placed after attach. 16638 getRunQueue().postDelayed(action, delayMillis); 16639 return true; 16640 } 16641 16642 /** 16643 * <p>Causes the Runnable to execute on the next animation time step. 16644 * The runnable will be run on the user interface thread.</p> 16645 * 16646 * @param action The Runnable that will be executed. 16647 * 16648 * @see #postOnAnimationDelayed 16649 * @see #removeCallbacks 16650 */ 16651 public void postOnAnimation(Runnable action) { 16652 final AttachInfo attachInfo = mAttachInfo; 16653 if (attachInfo != null) { 16654 attachInfo.mViewRootImpl.mChoreographer.postCallback( 16655 Choreographer.CALLBACK_ANIMATION, action, null); 16656 } else { 16657 // Postpone the runnable until we know 16658 // on which thread it needs to run. 16659 getRunQueue().post(action); 16660 } 16661 } 16662 16663 /** 16664 * <p>Causes the Runnable to execute on the next animation time step, 16665 * after the specified amount of time elapses. 16666 * The runnable will be run on the user interface thread.</p> 16667 * 16668 * @param action The Runnable that will be executed. 16669 * @param delayMillis The delay (in milliseconds) until the Runnable 16670 * will be executed. 16671 * 16672 * @see #postOnAnimation 16673 * @see #removeCallbacks 16674 */ 16675 public void postOnAnimationDelayed(Runnable action, long delayMillis) { 16676 final AttachInfo attachInfo = mAttachInfo; 16677 if (attachInfo != null) { 16678 attachInfo.mViewRootImpl.mChoreographer.postCallbackDelayed( 16679 Choreographer.CALLBACK_ANIMATION, action, null, delayMillis); 16680 } else { 16681 // Postpone the runnable until we know 16682 // on which thread it needs to run. 16683 getRunQueue().postDelayed(action, delayMillis); 16684 } 16685 } 16686 16687 /** 16688 * <p>Removes the specified Runnable from the message queue.</p> 16689 * 16690 * @param action The Runnable to remove from the message handling queue 16691 * 16692 * @return true if this view could ask the Handler to remove the Runnable, 16693 * false otherwise. When the returned value is true, the Runnable 16694 * may or may not have been actually removed from the message queue 16695 * (for instance, if the Runnable was not in the queue already.) 16696 * 16697 * @see #post 16698 * @see #postDelayed 16699 * @see #postOnAnimation 16700 * @see #postOnAnimationDelayed 16701 */ 16702 public boolean removeCallbacks(Runnable action) { 16703 if (action != null) { 16704 final AttachInfo attachInfo = mAttachInfo; 16705 if (attachInfo != null) { 16706 attachInfo.mHandler.removeCallbacks(action); 16707 attachInfo.mViewRootImpl.mChoreographer.removeCallbacks( 16708 Choreographer.CALLBACK_ANIMATION, action, null); 16709 } 16710 getRunQueue().removeCallbacks(action); 16711 } 16712 return true; 16713 } 16714 16715 /** 16716 * <p>Cause an invalidate to happen on a subsequent cycle through the event loop. 16717 * Use this to invalidate the View from a non-UI thread.</p> 16718 * 16719 * <p>This method can be invoked from outside of the UI thread 16720 * only when this View is attached to a window.</p> 16721 * 16722 * @see #invalidate() 16723 * @see #postInvalidateDelayed(long) 16724 */ 16725 public void postInvalidate() { 16726 postInvalidateDelayed(0); 16727 } 16728 16729 /** 16730 * <p>Cause an invalidate of the specified area to happen on a subsequent cycle 16731 * through the event loop. Use this to invalidate the View from a non-UI thread.</p> 16732 * 16733 * <p>This method can be invoked from outside of the UI thread 16734 * only when this View is attached to a window.</p> 16735 * 16736 * @param left The left coordinate of the rectangle to invalidate. 16737 * @param top The top coordinate of the rectangle to invalidate. 16738 * @param right The right coordinate of the rectangle to invalidate. 16739 * @param bottom The bottom coordinate of the rectangle to invalidate. 16740 * 16741 * @see #invalidate(int, int, int, int) 16742 * @see #invalidate(Rect) 16743 * @see #postInvalidateDelayed(long, int, int, int, int) 16744 */ 16745 public void postInvalidate(int left, int top, int right, int bottom) { 16746 postInvalidateDelayed(0, left, top, right, bottom); 16747 } 16748 16749 /** 16750 * <p>Cause an invalidate to happen on a subsequent cycle through the event 16751 * loop. Waits for the specified amount of time.</p> 16752 * 16753 * <p>This method can be invoked from outside of the UI thread 16754 * only when this View is attached to a window.</p> 16755 * 16756 * @param delayMilliseconds the duration in milliseconds to delay the 16757 * invalidation by 16758 * 16759 * @see #invalidate() 16760 * @see #postInvalidate() 16761 */ 16762 public void postInvalidateDelayed(long delayMilliseconds) { 16763 // We try only with the AttachInfo because there's no point in invalidating 16764 // if we are not attached to our window 16765 final AttachInfo attachInfo = mAttachInfo; 16766 if (attachInfo != null) { 16767 attachInfo.mViewRootImpl.dispatchInvalidateDelayed(this, delayMilliseconds); 16768 } 16769 } 16770 16771 /** 16772 * <p>Cause an invalidate of the specified area to happen on a subsequent cycle 16773 * through the event loop. Waits for the specified amount of time.</p> 16774 * 16775 * <p>This method can be invoked from outside of the UI thread 16776 * only when this View is attached to a window.</p> 16777 * 16778 * @param delayMilliseconds the duration in milliseconds to delay the 16779 * invalidation by 16780 * @param left The left coordinate of the rectangle to invalidate. 16781 * @param top The top coordinate of the rectangle to invalidate. 16782 * @param right The right coordinate of the rectangle to invalidate. 16783 * @param bottom The bottom coordinate of the rectangle to invalidate. 16784 * 16785 * @see #invalidate(int, int, int, int) 16786 * @see #invalidate(Rect) 16787 * @see #postInvalidate(int, int, int, int) 16788 */ 16789 public void postInvalidateDelayed(long delayMilliseconds, int left, int top, 16790 int right, int bottom) { 16791 16792 // We try only with the AttachInfo because there's no point in invalidating 16793 // if we are not attached to our window 16794 final AttachInfo attachInfo = mAttachInfo; 16795 if (attachInfo != null) { 16796 final AttachInfo.InvalidateInfo info = AttachInfo.InvalidateInfo.obtain(); 16797 info.target = this; 16798 info.left = left; 16799 info.top = top; 16800 info.right = right; 16801 info.bottom = bottom; 16802 16803 attachInfo.mViewRootImpl.dispatchInvalidateRectDelayed(info, delayMilliseconds); 16804 } 16805 } 16806 16807 /** 16808 * <p>Cause an invalidate to happen on the next animation time step, typically the 16809 * next display frame.</p> 16810 * 16811 * <p>This method can be invoked from outside of the UI thread 16812 * only when this View is attached to a window.</p> 16813 * 16814 * @see #invalidate() 16815 */ 16816 public void postInvalidateOnAnimation() { 16817 // We try only with the AttachInfo because there's no point in invalidating 16818 // if we are not attached to our window 16819 final AttachInfo attachInfo = mAttachInfo; 16820 if (attachInfo != null) { 16821 attachInfo.mViewRootImpl.dispatchInvalidateOnAnimation(this); 16822 } 16823 } 16824 16825 /** 16826 * <p>Cause an invalidate of the specified area to happen on the next animation 16827 * time step, typically the next display frame.</p> 16828 * 16829 * <p>This method can be invoked from outside of the UI thread 16830 * only when this View is attached to a window.</p> 16831 * 16832 * @param left The left coordinate of the rectangle to invalidate. 16833 * @param top The top coordinate of the rectangle to invalidate. 16834 * @param right The right coordinate of the rectangle to invalidate. 16835 * @param bottom The bottom coordinate of the rectangle to invalidate. 16836 * 16837 * @see #invalidate(int, int, int, int) 16838 * @see #invalidate(Rect) 16839 */ 16840 public void postInvalidateOnAnimation(int left, int top, int right, int bottom) { 16841 // We try only with the AttachInfo because there's no point in invalidating 16842 // if we are not attached to our window 16843 final AttachInfo attachInfo = mAttachInfo; 16844 if (attachInfo != null) { 16845 final AttachInfo.InvalidateInfo info = AttachInfo.InvalidateInfo.obtain(); 16846 info.target = this; 16847 info.left = left; 16848 info.top = top; 16849 info.right = right; 16850 info.bottom = bottom; 16851 16852 attachInfo.mViewRootImpl.dispatchInvalidateRectOnAnimation(info); 16853 } 16854 } 16855 16856 /** 16857 * Post a callback to send a {@link AccessibilityEvent#TYPE_VIEW_SCROLLED} event. 16858 * This event is sent at most once every 16859 * {@link ViewConfiguration#getSendRecurringAccessibilityEventsInterval()}. 16860 */ 16861 private void postSendViewScrolledAccessibilityEventCallback(int dx, int dy) { 16862 if (mSendViewScrolledAccessibilityEvent == null) { 16863 mSendViewScrolledAccessibilityEvent = new SendViewScrolledAccessibilityEvent(); 16864 } 16865 mSendViewScrolledAccessibilityEvent.post(dx, dy); 16866 } 16867 16868 /** 16869 * Called by a parent to request that a child update its values for mScrollX 16870 * and mScrollY if necessary. This will typically be done if the child is 16871 * animating a scroll using a {@link android.widget.Scroller Scroller} 16872 * object. 16873 */ 16874 public void computeScroll() { 16875 } 16876 16877 /** 16878 * <p>Indicate whether the horizontal edges are faded when the view is 16879 * scrolled horizontally.</p> 16880 * 16881 * @return true if the horizontal edges should are faded on scroll, false 16882 * otherwise 16883 * 16884 * @see #setHorizontalFadingEdgeEnabled(boolean) 16885 * 16886 * @attr ref android.R.styleable#View_requiresFadingEdge 16887 */ 16888 public boolean isHorizontalFadingEdgeEnabled() { 16889 return (mViewFlags & FADING_EDGE_HORIZONTAL) == FADING_EDGE_HORIZONTAL; 16890 } 16891 16892 /** 16893 * <p>Define whether the horizontal edges should be faded when this view 16894 * is scrolled horizontally.</p> 16895 * 16896 * @param horizontalFadingEdgeEnabled true if the horizontal edges should 16897 * be faded when the view is scrolled 16898 * horizontally 16899 * 16900 * @see #isHorizontalFadingEdgeEnabled() 16901 * 16902 * @attr ref android.R.styleable#View_requiresFadingEdge 16903 */ 16904 public void setHorizontalFadingEdgeEnabled(boolean horizontalFadingEdgeEnabled) { 16905 if (isHorizontalFadingEdgeEnabled() != horizontalFadingEdgeEnabled) { 16906 if (horizontalFadingEdgeEnabled) { 16907 initScrollCache(); 16908 } 16909 16910 mViewFlags ^= FADING_EDGE_HORIZONTAL; 16911 } 16912 } 16913 16914 /** 16915 * <p>Indicate whether the vertical edges are faded when the view is 16916 * scrolled horizontally.</p> 16917 * 16918 * @return true if the vertical edges should are faded on scroll, false 16919 * otherwise 16920 * 16921 * @see #setVerticalFadingEdgeEnabled(boolean) 16922 * 16923 * @attr ref android.R.styleable#View_requiresFadingEdge 16924 */ 16925 public boolean isVerticalFadingEdgeEnabled() { 16926 return (mViewFlags & FADING_EDGE_VERTICAL) == FADING_EDGE_VERTICAL; 16927 } 16928 16929 /** 16930 * <p>Define whether the vertical edges should be faded when this view 16931 * is scrolled vertically.</p> 16932 * 16933 * @param verticalFadingEdgeEnabled true if the vertical edges should 16934 * be faded when the view is scrolled 16935 * vertically 16936 * 16937 * @see #isVerticalFadingEdgeEnabled() 16938 * 16939 * @attr ref android.R.styleable#View_requiresFadingEdge 16940 */ 16941 public void setVerticalFadingEdgeEnabled(boolean verticalFadingEdgeEnabled) { 16942 if (isVerticalFadingEdgeEnabled() != verticalFadingEdgeEnabled) { 16943 if (verticalFadingEdgeEnabled) { 16944 initScrollCache(); 16945 } 16946 16947 mViewFlags ^= FADING_EDGE_VERTICAL; 16948 } 16949 } 16950 16951 /** 16952 * Returns the strength, or intensity, of the top faded edge. The strength is 16953 * a value between 0.0 (no fade) and 1.0 (full fade). The default implementation 16954 * returns 0.0 or 1.0 but no value in between. 16955 * 16956 * Subclasses should override this method to provide a smoother fade transition 16957 * when scrolling occurs. 16958 * 16959 * @return the intensity of the top fade as a float between 0.0f and 1.0f 16960 */ 16961 protected float getTopFadingEdgeStrength() { 16962 return computeVerticalScrollOffset() > 0 ? 1.0f : 0.0f; 16963 } 16964 16965 /** 16966 * Returns the strength, or intensity, of the bottom faded edge. The strength is 16967 * a value between 0.0 (no fade) and 1.0 (full fade). The default implementation 16968 * returns 0.0 or 1.0 but no value in between. 16969 * 16970 * Subclasses should override this method to provide a smoother fade transition 16971 * when scrolling occurs. 16972 * 16973 * @return the intensity of the bottom fade as a float between 0.0f and 1.0f 16974 */ 16975 protected float getBottomFadingEdgeStrength() { 16976 return computeVerticalScrollOffset() + computeVerticalScrollExtent() < 16977 computeVerticalScrollRange() ? 1.0f : 0.0f; 16978 } 16979 16980 /** 16981 * Returns the strength, or intensity, of the left faded edge. The strength is 16982 * a value between 0.0 (no fade) and 1.0 (full fade). The default implementation 16983 * returns 0.0 or 1.0 but no value in between. 16984 * 16985 * Subclasses should override this method to provide a smoother fade transition 16986 * when scrolling occurs. 16987 * 16988 * @return the intensity of the left fade as a float between 0.0f and 1.0f 16989 */ 16990 protected float getLeftFadingEdgeStrength() { 16991 return computeHorizontalScrollOffset() > 0 ? 1.0f : 0.0f; 16992 } 16993 16994 /** 16995 * Returns the strength, or intensity, of the right faded edge. The strength is 16996 * a value between 0.0 (no fade) and 1.0 (full fade). The default implementation 16997 * returns 0.0 or 1.0 but no value in between. 16998 * 16999 * Subclasses should override this method to provide a smoother fade transition 17000 * when scrolling occurs. 17001 * 17002 * @return the intensity of the right fade as a float between 0.0f and 1.0f 17003 */ 17004 protected float getRightFadingEdgeStrength() { 17005 return computeHorizontalScrollOffset() + computeHorizontalScrollExtent() < 17006 computeHorizontalScrollRange() ? 1.0f : 0.0f; 17007 } 17008 17009 /** 17010 * <p>Indicate whether the horizontal scrollbar should be drawn or not. The 17011 * scrollbar is not drawn by default.</p> 17012 * 17013 * @return true if the horizontal scrollbar should be painted, false 17014 * otherwise 17015 * 17016 * @see #setHorizontalScrollBarEnabled(boolean) 17017 */ 17018 public boolean isHorizontalScrollBarEnabled() { 17019 return (mViewFlags & SCROLLBARS_HORIZONTAL) == SCROLLBARS_HORIZONTAL; 17020 } 17021 17022 /** 17023 * <p>Define whether the horizontal scrollbar should be drawn or not. The 17024 * scrollbar is not drawn by default.</p> 17025 * 17026 * @param horizontalScrollBarEnabled true if the horizontal scrollbar should 17027 * be painted 17028 * 17029 * @see #isHorizontalScrollBarEnabled() 17030 */ 17031 public void setHorizontalScrollBarEnabled(boolean horizontalScrollBarEnabled) { 17032 if (isHorizontalScrollBarEnabled() != horizontalScrollBarEnabled) { 17033 mViewFlags ^= SCROLLBARS_HORIZONTAL; 17034 computeOpaqueFlags(); 17035 resolvePadding(); 17036 } 17037 } 17038 17039 /** 17040 * <p>Indicate whether the vertical scrollbar should be drawn or not. The 17041 * scrollbar is not drawn by default.</p> 17042 * 17043 * @return true if the vertical scrollbar should be painted, false 17044 * otherwise 17045 * 17046 * @see #setVerticalScrollBarEnabled(boolean) 17047 */ 17048 public boolean isVerticalScrollBarEnabled() { 17049 return (mViewFlags & SCROLLBARS_VERTICAL) == SCROLLBARS_VERTICAL; 17050 } 17051 17052 /** 17053 * <p>Define whether the vertical scrollbar should be drawn or not. The 17054 * scrollbar is not drawn by default.</p> 17055 * 17056 * @param verticalScrollBarEnabled true if the vertical scrollbar should 17057 * be painted 17058 * 17059 * @see #isVerticalScrollBarEnabled() 17060 */ 17061 public void setVerticalScrollBarEnabled(boolean verticalScrollBarEnabled) { 17062 if (isVerticalScrollBarEnabled() != verticalScrollBarEnabled) { 17063 mViewFlags ^= SCROLLBARS_VERTICAL; 17064 computeOpaqueFlags(); 17065 resolvePadding(); 17066 } 17067 } 17068 17069 /** 17070 * @hide 17071 */ 17072 protected void recomputePadding() { 17073 internalSetPadding(mUserPaddingLeft, mPaddingTop, mUserPaddingRight, mUserPaddingBottom); 17074 } 17075 17076 /** 17077 * Define whether scrollbars will fade when the view is not scrolling. 17078 * 17079 * @param fadeScrollbars whether to enable fading 17080 * 17081 * @attr ref android.R.styleable#View_fadeScrollbars 17082 */ 17083 public void setScrollbarFadingEnabled(boolean fadeScrollbars) { 17084 initScrollCache(); 17085 final ScrollabilityCache scrollabilityCache = mScrollCache; 17086 scrollabilityCache.fadeScrollBars = fadeScrollbars; 17087 if (fadeScrollbars) { 17088 scrollabilityCache.state = ScrollabilityCache.OFF; 17089 } else { 17090 scrollabilityCache.state = ScrollabilityCache.ON; 17091 } 17092 } 17093 17094 /** 17095 * 17096 * Returns true if scrollbars will fade when this view is not scrolling 17097 * 17098 * @return true if scrollbar fading is enabled 17099 * 17100 * @attr ref android.R.styleable#View_fadeScrollbars 17101 */ 17102 public boolean isScrollbarFadingEnabled() { 17103 return mScrollCache != null && mScrollCache.fadeScrollBars; 17104 } 17105 17106 /** 17107 * 17108 * Returns the delay before scrollbars fade. 17109 * 17110 * @return the delay before scrollbars fade 17111 * 17112 * @attr ref android.R.styleable#View_scrollbarDefaultDelayBeforeFade 17113 */ 17114 public int getScrollBarDefaultDelayBeforeFade() { 17115 return mScrollCache == null ? ViewConfiguration.getScrollDefaultDelay() : 17116 mScrollCache.scrollBarDefaultDelayBeforeFade; 17117 } 17118 17119 /** 17120 * Define the delay before scrollbars fade. 17121 * 17122 * @param scrollBarDefaultDelayBeforeFade - the delay before scrollbars fade 17123 * 17124 * @attr ref android.R.styleable#View_scrollbarDefaultDelayBeforeFade 17125 */ 17126 public void setScrollBarDefaultDelayBeforeFade(int scrollBarDefaultDelayBeforeFade) { 17127 getScrollCache().scrollBarDefaultDelayBeforeFade = scrollBarDefaultDelayBeforeFade; 17128 } 17129 17130 /** 17131 * 17132 * Returns the scrollbar fade duration. 17133 * 17134 * @return the scrollbar fade duration, in milliseconds 17135 * 17136 * @attr ref android.R.styleable#View_scrollbarFadeDuration 17137 */ 17138 public int getScrollBarFadeDuration() { 17139 return mScrollCache == null ? ViewConfiguration.getScrollBarFadeDuration() : 17140 mScrollCache.scrollBarFadeDuration; 17141 } 17142 17143 /** 17144 * Define the scrollbar fade duration. 17145 * 17146 * @param scrollBarFadeDuration - the scrollbar fade duration, in milliseconds 17147 * 17148 * @attr ref android.R.styleable#View_scrollbarFadeDuration 17149 */ 17150 public void setScrollBarFadeDuration(int scrollBarFadeDuration) { 17151 getScrollCache().scrollBarFadeDuration = scrollBarFadeDuration; 17152 } 17153 17154 /** 17155 * 17156 * Returns the scrollbar size. 17157 * 17158 * @return the scrollbar size 17159 * 17160 * @attr ref android.R.styleable#View_scrollbarSize 17161 */ 17162 public int getScrollBarSize() { 17163 return mScrollCache == null ? ViewConfiguration.get(mContext).getScaledScrollBarSize() : 17164 mScrollCache.scrollBarSize; 17165 } 17166 17167 /** 17168 * Define the scrollbar size. 17169 * 17170 * @param scrollBarSize - the scrollbar size 17171 * 17172 * @attr ref android.R.styleable#View_scrollbarSize 17173 */ 17174 public void setScrollBarSize(int scrollBarSize) { 17175 getScrollCache().scrollBarSize = scrollBarSize; 17176 } 17177 17178 /** 17179 * <p>Specify the style of the scrollbars. The scrollbars can be overlaid or 17180 * inset. When inset, they add to the padding of the view. And the scrollbars 17181 * can be drawn inside the padding area or on the edge of the view. For example, 17182 * if a view has a background drawable and you want to draw the scrollbars 17183 * inside the padding specified by the drawable, you can use 17184 * SCROLLBARS_INSIDE_OVERLAY or SCROLLBARS_INSIDE_INSET. If you want them to 17185 * appear at the edge of the view, ignoring the padding, then you can use 17186 * SCROLLBARS_OUTSIDE_OVERLAY or SCROLLBARS_OUTSIDE_INSET.</p> 17187 * @param style the style of the scrollbars. Should be one of 17188 * SCROLLBARS_INSIDE_OVERLAY, SCROLLBARS_INSIDE_INSET, 17189 * SCROLLBARS_OUTSIDE_OVERLAY or SCROLLBARS_OUTSIDE_INSET. 17190 * @see #SCROLLBARS_INSIDE_OVERLAY 17191 * @see #SCROLLBARS_INSIDE_INSET 17192 * @see #SCROLLBARS_OUTSIDE_OVERLAY 17193 * @see #SCROLLBARS_OUTSIDE_INSET 17194 * 17195 * @attr ref android.R.styleable#View_scrollbarStyle 17196 */ 17197 public void setScrollBarStyle(@ScrollBarStyle int style) { 17198 if (style != (mViewFlags & SCROLLBARS_STYLE_MASK)) { 17199 mViewFlags = (mViewFlags & ~SCROLLBARS_STYLE_MASK) | (style & SCROLLBARS_STYLE_MASK); 17200 computeOpaqueFlags(); 17201 resolvePadding(); 17202 } 17203 } 17204 17205 /** 17206 * <p>Returns the current scrollbar style.</p> 17207 * @return the current scrollbar style 17208 * @see #SCROLLBARS_INSIDE_OVERLAY 17209 * @see #SCROLLBARS_INSIDE_INSET 17210 * @see #SCROLLBARS_OUTSIDE_OVERLAY 17211 * @see #SCROLLBARS_OUTSIDE_INSET 17212 * 17213 * @attr ref android.R.styleable#View_scrollbarStyle 17214 */ 17215 @ViewDebug.ExportedProperty(mapping = { 17216 @ViewDebug.IntToString(from = SCROLLBARS_INSIDE_OVERLAY, to = "INSIDE_OVERLAY"), 17217 @ViewDebug.IntToString(from = SCROLLBARS_INSIDE_INSET, to = "INSIDE_INSET"), 17218 @ViewDebug.IntToString(from = SCROLLBARS_OUTSIDE_OVERLAY, to = "OUTSIDE_OVERLAY"), 17219 @ViewDebug.IntToString(from = SCROLLBARS_OUTSIDE_INSET, to = "OUTSIDE_INSET") 17220 }) 17221 @ScrollBarStyle 17222 public int getScrollBarStyle() { 17223 return mViewFlags & SCROLLBARS_STYLE_MASK; 17224 } 17225 17226 /** 17227 * <p>Compute the horizontal range that the horizontal scrollbar 17228 * represents.</p> 17229 * 17230 * <p>The range is expressed in arbitrary units that must be the same as the 17231 * units used by {@link #computeHorizontalScrollExtent()} and 17232 * {@link #computeHorizontalScrollOffset()}.</p> 17233 * 17234 * <p>The default range is the drawing width of this view.</p> 17235 * 17236 * @return the total horizontal range represented by the horizontal 17237 * scrollbar 17238 * 17239 * @see #computeHorizontalScrollExtent() 17240 * @see #computeHorizontalScrollOffset() 17241 * @see android.widget.ScrollBarDrawable 17242 */ 17243 protected int computeHorizontalScrollRange() { 17244 return getWidth(); 17245 } 17246 17247 /** 17248 * <p>Compute the horizontal offset of the horizontal scrollbar's thumb 17249 * within the horizontal range. This value is used to compute the position 17250 * of the thumb within the scrollbar's track.</p> 17251 * 17252 * <p>The range is expressed in arbitrary units that must be the same as the 17253 * units used by {@link #computeHorizontalScrollRange()} and 17254 * {@link #computeHorizontalScrollExtent()}.</p> 17255 * 17256 * <p>The default offset is the scroll offset of this view.</p> 17257 * 17258 * @return the horizontal offset of the scrollbar's thumb 17259 * 17260 * @see #computeHorizontalScrollRange() 17261 * @see #computeHorizontalScrollExtent() 17262 * @see android.widget.ScrollBarDrawable 17263 */ 17264 protected int computeHorizontalScrollOffset() { 17265 return mScrollX; 17266 } 17267 17268 /** 17269 * <p>Compute the horizontal extent of the horizontal scrollbar's thumb 17270 * within the horizontal range. This value is used to compute the length 17271 * of the thumb within the scrollbar's track.</p> 17272 * 17273 * <p>The range is expressed in arbitrary units that must be the same as the 17274 * units used by {@link #computeHorizontalScrollRange()} and 17275 * {@link #computeHorizontalScrollOffset()}.</p> 17276 * 17277 * <p>The default extent is the drawing width of this view.</p> 17278 * 17279 * @return the horizontal extent of the scrollbar's thumb 17280 * 17281 * @see #computeHorizontalScrollRange() 17282 * @see #computeHorizontalScrollOffset() 17283 * @see android.widget.ScrollBarDrawable 17284 */ 17285 protected int computeHorizontalScrollExtent() { 17286 return getWidth(); 17287 } 17288 17289 /** 17290 * <p>Compute the vertical range that the vertical scrollbar represents.</p> 17291 * 17292 * <p>The range is expressed in arbitrary units that must be the same as the 17293 * units used by {@link #computeVerticalScrollExtent()} and 17294 * {@link #computeVerticalScrollOffset()}.</p> 17295 * 17296 * @return the total vertical range represented by the vertical scrollbar 17297 * 17298 * <p>The default range is the drawing height of this view.</p> 17299 * 17300 * @see #computeVerticalScrollExtent() 17301 * @see #computeVerticalScrollOffset() 17302 * @see android.widget.ScrollBarDrawable 17303 */ 17304 protected int computeVerticalScrollRange() { 17305 return getHeight(); 17306 } 17307 17308 /** 17309 * <p>Compute the vertical offset of the vertical scrollbar's thumb 17310 * within the horizontal range. This value is used to compute the position 17311 * of the thumb within the scrollbar's track.</p> 17312 * 17313 * <p>The range is expressed in arbitrary units that must be the same as the 17314 * units used by {@link #computeVerticalScrollRange()} and 17315 * {@link #computeVerticalScrollExtent()}.</p> 17316 * 17317 * <p>The default offset is the scroll offset of this view.</p> 17318 * 17319 * @return the vertical offset of the scrollbar's thumb 17320 * 17321 * @see #computeVerticalScrollRange() 17322 * @see #computeVerticalScrollExtent() 17323 * @see android.widget.ScrollBarDrawable 17324 */ 17325 protected int computeVerticalScrollOffset() { 17326 return mScrollY; 17327 } 17328 17329 /** 17330 * <p>Compute the vertical extent of the vertical scrollbar's thumb 17331 * within the vertical range. This value is used to compute the length 17332 * of the thumb within the scrollbar's track.</p> 17333 * 17334 * <p>The range is expressed in arbitrary units that must be the same as the 17335 * units used by {@link #computeVerticalScrollRange()} and 17336 * {@link #computeVerticalScrollOffset()}.</p> 17337 * 17338 * <p>The default extent is the drawing height of this view.</p> 17339 * 17340 * @return the vertical extent of the scrollbar's thumb 17341 * 17342 * @see #computeVerticalScrollRange() 17343 * @see #computeVerticalScrollOffset() 17344 * @see android.widget.ScrollBarDrawable 17345 */ 17346 protected int computeVerticalScrollExtent() { 17347 return getHeight(); 17348 } 17349 17350 /** 17351 * Check if this view can be scrolled horizontally in a certain direction. 17352 * 17353 * @param direction Negative to check scrolling left, positive to check scrolling right. 17354 * @return true if this view can be scrolled in the specified direction, false otherwise. 17355 */ 17356 public boolean canScrollHorizontally(int direction) { 17357 final int offset = computeHorizontalScrollOffset(); 17358 final int range = computeHorizontalScrollRange() - computeHorizontalScrollExtent(); 17359 if (range == 0) return false; 17360 if (direction < 0) { 17361 return offset > 0; 17362 } else { 17363 return offset < range - 1; 17364 } 17365 } 17366 17367 /** 17368 * Check if this view can be scrolled vertically in a certain direction. 17369 * 17370 * @param direction Negative to check scrolling up, positive to check scrolling down. 17371 * @return true if this view can be scrolled in the specified direction, false otherwise. 17372 */ 17373 public boolean canScrollVertically(int direction) { 17374 final int offset = computeVerticalScrollOffset(); 17375 final int range = computeVerticalScrollRange() - computeVerticalScrollExtent(); 17376 if (range == 0) return false; 17377 if (direction < 0) { 17378 return offset > 0; 17379 } else { 17380 return offset < range - 1; 17381 } 17382 } 17383 17384 void getScrollIndicatorBounds(@NonNull Rect out) { 17385 out.left = mScrollX; 17386 out.right = mScrollX + mRight - mLeft; 17387 out.top = mScrollY; 17388 out.bottom = mScrollY + mBottom - mTop; 17389 } 17390 17391 private void onDrawScrollIndicators(Canvas c) { 17392 if ((mPrivateFlags3 & SCROLL_INDICATORS_PFLAG3_MASK) == 0) { 17393 // No scroll indicators enabled. 17394 return; 17395 } 17396 17397 final Drawable dr = mScrollIndicatorDrawable; 17398 if (dr == null) { 17399 // Scroll indicators aren't supported here. 17400 return; 17401 } 17402 17403 final int h = dr.getIntrinsicHeight(); 17404 final int w = dr.getIntrinsicWidth(); 17405 final Rect rect = mAttachInfo.mTmpInvalRect; 17406 getScrollIndicatorBounds(rect); 17407 17408 if ((mPrivateFlags3 & PFLAG3_SCROLL_INDICATOR_TOP) != 0) { 17409 final boolean canScrollUp = canScrollVertically(-1); 17410 if (canScrollUp) { 17411 dr.setBounds(rect.left, rect.top, rect.right, rect.top + h); 17412 dr.draw(c); 17413 } 17414 } 17415 17416 if ((mPrivateFlags3 & PFLAG3_SCROLL_INDICATOR_BOTTOM) != 0) { 17417 final boolean canScrollDown = canScrollVertically(1); 17418 if (canScrollDown) { 17419 dr.setBounds(rect.left, rect.bottom - h, rect.right, rect.bottom); 17420 dr.draw(c); 17421 } 17422 } 17423 17424 final int leftRtl; 17425 final int rightRtl; 17426 if (getLayoutDirection() == LAYOUT_DIRECTION_RTL) { 17427 leftRtl = PFLAG3_SCROLL_INDICATOR_END; 17428 rightRtl = PFLAG3_SCROLL_INDICATOR_START; 17429 } else { 17430 leftRtl = PFLAG3_SCROLL_INDICATOR_START; 17431 rightRtl = PFLAG3_SCROLL_INDICATOR_END; 17432 } 17433 17434 final int leftMask = PFLAG3_SCROLL_INDICATOR_LEFT | leftRtl; 17435 if ((mPrivateFlags3 & leftMask) != 0) { 17436 final boolean canScrollLeft = canScrollHorizontally(-1); 17437 if (canScrollLeft) { 17438 dr.setBounds(rect.left, rect.top, rect.left + w, rect.bottom); 17439 dr.draw(c); 17440 } 17441 } 17442 17443 final int rightMask = PFLAG3_SCROLL_INDICATOR_RIGHT | rightRtl; 17444 if ((mPrivateFlags3 & rightMask) != 0) { 17445 final boolean canScrollRight = canScrollHorizontally(1); 17446 if (canScrollRight) { 17447 dr.setBounds(rect.right - w, rect.top, rect.right, rect.bottom); 17448 dr.draw(c); 17449 } 17450 } 17451 } 17452 17453 private void getHorizontalScrollBarBounds(@Nullable Rect drawBounds, 17454 @Nullable Rect touchBounds) { 17455 final Rect bounds = drawBounds != null ? drawBounds : touchBounds; 17456 if (bounds == null) { 17457 return; 17458 } 17459 final int inside = (mViewFlags & SCROLLBARS_OUTSIDE_MASK) == 0 ? ~0 : 0; 17460 final boolean drawVerticalScrollBar = isVerticalScrollBarEnabled() 17461 && !isVerticalScrollBarHidden(); 17462 final int size = getHorizontalScrollbarHeight(); 17463 final int verticalScrollBarGap = drawVerticalScrollBar ? 17464 getVerticalScrollbarWidth() : 0; 17465 final int width = mRight - mLeft; 17466 final int height = mBottom - mTop; 17467 bounds.top = mScrollY + height - size - (mUserPaddingBottom & inside); 17468 bounds.left = mScrollX + (mPaddingLeft & inside); 17469 bounds.right = mScrollX + width - (mUserPaddingRight & inside) - verticalScrollBarGap; 17470 bounds.bottom = bounds.top + size; 17471 17472 if (touchBounds == null) { 17473 return; 17474 } 17475 if (touchBounds != bounds) { 17476 touchBounds.set(bounds); 17477 } 17478 final int minTouchTarget = mScrollCache.scrollBarMinTouchTarget; 17479 if (touchBounds.height() < minTouchTarget) { 17480 final int adjust = (minTouchTarget - touchBounds.height()) / 2; 17481 touchBounds.bottom = Math.min(touchBounds.bottom + adjust, mScrollY + height); 17482 touchBounds.top = touchBounds.bottom - minTouchTarget; 17483 } 17484 if (touchBounds.width() < minTouchTarget) { 17485 final int adjust = (minTouchTarget - touchBounds.width()) / 2; 17486 touchBounds.left -= adjust; 17487 touchBounds.right = touchBounds.left + minTouchTarget; 17488 } 17489 } 17490 17491 private void getVerticalScrollBarBounds(@Nullable Rect bounds, @Nullable Rect touchBounds) { 17492 if (mRoundScrollbarRenderer == null) { 17493 getStraightVerticalScrollBarBounds(bounds, touchBounds); 17494 } else { 17495 getRoundVerticalScrollBarBounds(bounds != null ? bounds : touchBounds); 17496 } 17497 } 17498 17499 private void getRoundVerticalScrollBarBounds(Rect bounds) { 17500 final int width = mRight - mLeft; 17501 final int height = mBottom - mTop; 17502 // Do not take padding into account as we always want the scrollbars 17503 // to hug the screen for round wearable devices. 17504 bounds.left = mScrollX; 17505 bounds.top = mScrollY; 17506 bounds.right = bounds.left + width; 17507 bounds.bottom = mScrollY + height; 17508 } 17509 17510 private void getStraightVerticalScrollBarBounds(@Nullable Rect drawBounds, 17511 @Nullable Rect touchBounds) { 17512 final Rect bounds = drawBounds != null ? drawBounds : touchBounds; 17513 if (bounds == null) { 17514 return; 17515 } 17516 final int inside = (mViewFlags & SCROLLBARS_OUTSIDE_MASK) == 0 ? ~0 : 0; 17517 final int size = getVerticalScrollbarWidth(); 17518 int verticalScrollbarPosition = mVerticalScrollbarPosition; 17519 if (verticalScrollbarPosition == SCROLLBAR_POSITION_DEFAULT) { 17520 verticalScrollbarPosition = isLayoutRtl() ? 17521 SCROLLBAR_POSITION_LEFT : SCROLLBAR_POSITION_RIGHT; 17522 } 17523 final int width = mRight - mLeft; 17524 final int height = mBottom - mTop; 17525 switch (verticalScrollbarPosition) { 17526 default: 17527 case SCROLLBAR_POSITION_RIGHT: 17528 bounds.left = mScrollX + width - size - (mUserPaddingRight & inside); 17529 break; 17530 case SCROLLBAR_POSITION_LEFT: 17531 bounds.left = mScrollX + (mUserPaddingLeft & inside); 17532 break; 17533 } 17534 bounds.top = mScrollY + (mPaddingTop & inside); 17535 bounds.right = bounds.left + size; 17536 bounds.bottom = mScrollY + height - (mUserPaddingBottom & inside); 17537 17538 if (touchBounds == null) { 17539 return; 17540 } 17541 if (touchBounds != bounds) { 17542 touchBounds.set(bounds); 17543 } 17544 final int minTouchTarget = mScrollCache.scrollBarMinTouchTarget; 17545 if (touchBounds.width() < minTouchTarget) { 17546 final int adjust = (minTouchTarget - touchBounds.width()) / 2; 17547 if (verticalScrollbarPosition == SCROLLBAR_POSITION_RIGHT) { 17548 touchBounds.right = Math.min(touchBounds.right + adjust, mScrollX + width); 17549 touchBounds.left = touchBounds.right - minTouchTarget; 17550 } else { 17551 touchBounds.left = Math.max(touchBounds.left + adjust, mScrollX); 17552 touchBounds.right = touchBounds.left + minTouchTarget; 17553 } 17554 } 17555 if (touchBounds.height() < minTouchTarget) { 17556 final int adjust = (minTouchTarget - touchBounds.height()) / 2; 17557 touchBounds.top -= adjust; 17558 touchBounds.bottom = touchBounds.top + minTouchTarget; 17559 } 17560 } 17561 17562 /** 17563 * <p>Request the drawing of the horizontal and the vertical scrollbar. The 17564 * scrollbars are painted only if they have been awakened first.</p> 17565 * 17566 * @param canvas the canvas on which to draw the scrollbars 17567 * 17568 * @see #awakenScrollBars(int) 17569 */ 17570 protected final void onDrawScrollBars(Canvas canvas) { 17571 // scrollbars are drawn only when the animation is running 17572 final ScrollabilityCache cache = mScrollCache; 17573 17574 if (cache != null) { 17575 17576 int state = cache.state; 17577 17578 if (state == ScrollabilityCache.OFF) { 17579 return; 17580 } 17581 17582 boolean invalidate = false; 17583 17584 if (state == ScrollabilityCache.FADING) { 17585 // We're fading -- get our fade interpolation 17586 if (cache.interpolatorValues == null) { 17587 cache.interpolatorValues = new float[1]; 17588 } 17589 17590 float[] values = cache.interpolatorValues; 17591 17592 // Stops the animation if we're done 17593 if (cache.scrollBarInterpolator.timeToValues(values) == 17594 Interpolator.Result.FREEZE_END) { 17595 cache.state = ScrollabilityCache.OFF; 17596 } else { 17597 cache.scrollBar.mutate().setAlpha(Math.round(values[0])); 17598 } 17599 17600 // This will make the scroll bars inval themselves after 17601 // drawing. We only want this when we're fading so that 17602 // we prevent excessive redraws 17603 invalidate = true; 17604 } else { 17605 // We're just on -- but we may have been fading before so 17606 // reset alpha 17607 cache.scrollBar.mutate().setAlpha(255); 17608 } 17609 17610 final boolean drawHorizontalScrollBar = isHorizontalScrollBarEnabled(); 17611 final boolean drawVerticalScrollBar = isVerticalScrollBarEnabled() 17612 && !isVerticalScrollBarHidden(); 17613 17614 // Fork out the scroll bar drawing for round wearable devices. 17615 if (mRoundScrollbarRenderer != null) { 17616 if (drawVerticalScrollBar) { 17617 final Rect bounds = cache.mScrollBarBounds; 17618 getVerticalScrollBarBounds(bounds, null); 17619 mRoundScrollbarRenderer.drawRoundScrollbars( 17620 canvas, (float) cache.scrollBar.getAlpha() / 255f, bounds); 17621 if (invalidate) { 17622 invalidate(); 17623 } 17624 } 17625 // Do not draw horizontal scroll bars for round wearable devices. 17626 } else if (drawVerticalScrollBar || drawHorizontalScrollBar) { 17627 final ScrollBarDrawable scrollBar = cache.scrollBar; 17628 17629 if (drawHorizontalScrollBar) { 17630 scrollBar.setParameters(computeHorizontalScrollRange(), 17631 computeHorizontalScrollOffset(), 17632 computeHorizontalScrollExtent(), false); 17633 final Rect bounds = cache.mScrollBarBounds; 17634 getHorizontalScrollBarBounds(bounds, null); 17635 onDrawHorizontalScrollBar(canvas, scrollBar, bounds.left, bounds.top, 17636 bounds.right, bounds.bottom); 17637 if (invalidate) { 17638 invalidate(bounds); 17639 } 17640 } 17641 17642 if (drawVerticalScrollBar) { 17643 scrollBar.setParameters(computeVerticalScrollRange(), 17644 computeVerticalScrollOffset(), 17645 computeVerticalScrollExtent(), true); 17646 final Rect bounds = cache.mScrollBarBounds; 17647 getVerticalScrollBarBounds(bounds, null); 17648 onDrawVerticalScrollBar(canvas, scrollBar, bounds.left, bounds.top, 17649 bounds.right, bounds.bottom); 17650 if (invalidate) { 17651 invalidate(bounds); 17652 } 17653 } 17654 } 17655 } 17656 } 17657 17658 /** 17659 * Override this if the vertical scrollbar needs to be hidden in a subclass, like when 17660 * FastScroller is visible. 17661 * @return whether to temporarily hide the vertical scrollbar 17662 * @hide 17663 */ 17664 protected boolean isVerticalScrollBarHidden() { 17665 return false; 17666 } 17667 17668 /** 17669 * <p>Draw the horizontal scrollbar if 17670 * {@link #isHorizontalScrollBarEnabled()} returns true.</p> 17671 * 17672 * @param canvas the canvas on which to draw the scrollbar 17673 * @param scrollBar the scrollbar's drawable 17674 * 17675 * @see #isHorizontalScrollBarEnabled() 17676 * @see #computeHorizontalScrollRange() 17677 * @see #computeHorizontalScrollExtent() 17678 * @see #computeHorizontalScrollOffset() 17679 * @see android.widget.ScrollBarDrawable 17680 * @hide 17681 */ 17682 protected void onDrawHorizontalScrollBar(Canvas canvas, Drawable scrollBar, 17683 int l, int t, int r, int b) { 17684 scrollBar.setBounds(l, t, r, b); 17685 scrollBar.draw(canvas); 17686 } 17687 17688 /** 17689 * <p>Draw the vertical scrollbar if {@link #isVerticalScrollBarEnabled()} 17690 * returns true.</p> 17691 * 17692 * @param canvas the canvas on which to draw the scrollbar 17693 * @param scrollBar the scrollbar's drawable 17694 * 17695 * @see #isVerticalScrollBarEnabled() 17696 * @see #computeVerticalScrollRange() 17697 * @see #computeVerticalScrollExtent() 17698 * @see #computeVerticalScrollOffset() 17699 * @see android.widget.ScrollBarDrawable 17700 * @hide 17701 */ 17702 protected void onDrawVerticalScrollBar(Canvas canvas, Drawable scrollBar, 17703 int l, int t, int r, int b) { 17704 scrollBar.setBounds(l, t, r, b); 17705 scrollBar.draw(canvas); 17706 } 17707 17708 /** 17709 * Implement this to do your drawing. 17710 * 17711 * @param canvas the canvas on which the background will be drawn 17712 */ 17713 protected void onDraw(Canvas canvas) { 17714 } 17715 17716 /* 17717 * Caller is responsible for calling requestLayout if necessary. 17718 * (This allows addViewInLayout to not request a new layout.) 17719 */ 17720 void assignParent(ViewParent parent) { 17721 if (mParent == null) { 17722 mParent = parent; 17723 } else if (parent == null) { 17724 mParent = null; 17725 } else { 17726 throw new RuntimeException("view " + this + " being added, but" 17727 + " it already has a parent"); 17728 } 17729 } 17730 17731 /** 17732 * This is called when the view is attached to a window. At this point it 17733 * has a Surface and will start drawing. Note that this function is 17734 * guaranteed to be called before {@link #onDraw(android.graphics.Canvas)}, 17735 * however it may be called any time before the first onDraw -- including 17736 * before or after {@link #onMeasure(int, int)}. 17737 * 17738 * @see #onDetachedFromWindow() 17739 */ 17740 @CallSuper 17741 protected void onAttachedToWindow() { 17742 if ((mPrivateFlags & PFLAG_REQUEST_TRANSPARENT_REGIONS) != 0) { 17743 mParent.requestTransparentRegion(this); 17744 } 17745 17746 mPrivateFlags3 &= ~PFLAG3_IS_LAID_OUT; 17747 17748 jumpDrawablesToCurrentState(); 17749 17750 resetSubtreeAccessibilityStateChanged(); 17751 17752 // rebuild, since Outline not maintained while View is detached 17753 rebuildOutline(); 17754 17755 if (isFocused()) { 17756 InputMethodManager imm = InputMethodManager.peekInstance(); 17757 if (imm != null) { 17758 imm.focusIn(this); 17759 } 17760 } 17761 } 17762 17763 /** 17764 * Resolve all RTL related properties. 17765 * 17766 * @return true if resolution of RTL properties has been done 17767 * 17768 * @hide 17769 */ 17770 public boolean resolveRtlPropertiesIfNeeded() { 17771 if (!needRtlPropertiesResolution()) return false; 17772 17773 // Order is important here: LayoutDirection MUST be resolved first 17774 if (!isLayoutDirectionResolved()) { 17775 resolveLayoutDirection(); 17776 resolveLayoutParams(); 17777 } 17778 // ... then we can resolve the others properties depending on the resolved LayoutDirection. 17779 if (!isTextDirectionResolved()) { 17780 resolveTextDirection(); 17781 } 17782 if (!isTextAlignmentResolved()) { 17783 resolveTextAlignment(); 17784 } 17785 // Should resolve Drawables before Padding because we need the layout direction of the 17786 // Drawable to correctly resolve Padding. 17787 if (!areDrawablesResolved()) { 17788 resolveDrawables(); 17789 } 17790 if (!isPaddingResolved()) { 17791 resolvePadding(); 17792 } 17793 onRtlPropertiesChanged(getLayoutDirection()); 17794 return true; 17795 } 17796 17797 /** 17798 * Reset resolution of all RTL related properties. 17799 * 17800 * @hide 17801 */ 17802 public void resetRtlProperties() { 17803 resetResolvedLayoutDirection(); 17804 resetResolvedTextDirection(); 17805 resetResolvedTextAlignment(); 17806 resetResolvedPadding(); 17807 resetResolvedDrawables(); 17808 } 17809 17810 /** 17811 * @see #onScreenStateChanged(int) 17812 */ 17813 void dispatchScreenStateChanged(int screenState) { 17814 onScreenStateChanged(screenState); 17815 } 17816 17817 /** 17818 * This method is called whenever the state of the screen this view is 17819 * attached to changes. A state change will usually occurs when the screen 17820 * turns on or off (whether it happens automatically or the user does it 17821 * manually.) 17822 * 17823 * @param screenState The new state of the screen. Can be either 17824 * {@link #SCREEN_STATE_ON} or {@link #SCREEN_STATE_OFF} 17825 */ 17826 public void onScreenStateChanged(int screenState) { 17827 } 17828 17829 /** 17830 * @see #onMovedToDisplay(int, Configuration) 17831 */ 17832 void dispatchMovedToDisplay(Display display, Configuration config) { 17833 mAttachInfo.mDisplay = display; 17834 mAttachInfo.mDisplayState = display.getState(); 17835 onMovedToDisplay(display.getDisplayId(), config); 17836 } 17837 17838 /** 17839 * Called by the system when the hosting activity is moved from one display to another without 17840 * recreation. This means that the activity is declared to handle all changes to configuration 17841 * that happened when it was switched to another display, so it wasn't destroyed and created 17842 * again. 17843 * 17844 * <p>This call will be followed by {@link #onConfigurationChanged(Configuration)} if the 17845 * applied configuration actually changed. It is up to app developer to choose whether to handle 17846 * the change in this method or in the following {@link #onConfigurationChanged(Configuration)} 17847 * call. 17848 * 17849 * <p>Use this callback to track changes to the displays if some functionality relies on an 17850 * association with some display properties. 17851 * 17852 * @param displayId The id of the display to which the view was moved. 17853 * @param config Configuration of the resources on new display after move. 17854 * 17855 * @see #onConfigurationChanged(Configuration) 17856 * @hide 17857 */ 17858 public void onMovedToDisplay(int displayId, Configuration config) { 17859 } 17860 17861 /** 17862 * Return true if the application tag in the AndroidManifest has set "supportRtl" to true 17863 */ 17864 private boolean hasRtlSupport() { 17865 return mContext.getApplicationInfo().hasRtlSupport(); 17866 } 17867 17868 /** 17869 * Return true if we are in RTL compatibility mode (either before Jelly Bean MR1 or 17870 * RTL not supported) 17871 */ 17872 private boolean isRtlCompatibilityMode() { 17873 final int targetSdkVersion = getContext().getApplicationInfo().targetSdkVersion; 17874 return targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR1 || !hasRtlSupport(); 17875 } 17876 17877 /** 17878 * @return true if RTL properties need resolution. 17879 * 17880 */ 17881 private boolean needRtlPropertiesResolution() { 17882 return (mPrivateFlags2 & ALL_RTL_PROPERTIES_RESOLVED) != ALL_RTL_PROPERTIES_RESOLVED; 17883 } 17884 17885 /** 17886 * Called when any RTL property (layout direction or text direction or text alignment) has 17887 * been changed. 17888 * 17889 * Subclasses need to override this method to take care of cached information that depends on the 17890 * resolved layout direction, or to inform child views that inherit their layout direction. 17891 * 17892 * The default implementation does nothing. 17893 * 17894 * @param layoutDirection the direction of the layout 17895 * 17896 * @see #LAYOUT_DIRECTION_LTR 17897 * @see #LAYOUT_DIRECTION_RTL 17898 */ 17899 public void onRtlPropertiesChanged(@ResolvedLayoutDir int layoutDirection) { 17900 } 17901 17902 /** 17903 * Resolve and cache the layout direction. LTR is set initially. This is implicitly supposing 17904 * that the parent directionality can and will be resolved before its children. 17905 * 17906 * @return true if resolution has been done, false otherwise. 17907 * 17908 * @hide 17909 */ 17910 public boolean resolveLayoutDirection() { 17911 // Clear any previous layout direction resolution 17912 mPrivateFlags2 &= ~PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK; 17913 17914 if (hasRtlSupport()) { 17915 // Set resolved depending on layout direction 17916 switch ((mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_MASK) >> 17917 PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT) { 17918 case LAYOUT_DIRECTION_INHERIT: 17919 // We cannot resolve yet. LTR is by default and let the resolution happen again 17920 // later to get the correct resolved value 17921 if (!canResolveLayoutDirection()) return false; 17922 17923 // Parent has not yet resolved, LTR is still the default 17924 try { 17925 if (!mParent.isLayoutDirectionResolved()) return false; 17926 17927 if (mParent.getLayoutDirection() == LAYOUT_DIRECTION_RTL) { 17928 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL; 17929 } 17930 } catch (AbstractMethodError e) { 17931 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 17932 " does not fully implement ViewParent", e); 17933 } 17934 break; 17935 case LAYOUT_DIRECTION_RTL: 17936 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL; 17937 break; 17938 case LAYOUT_DIRECTION_LOCALE: 17939 if((LAYOUT_DIRECTION_RTL == 17940 TextUtils.getLayoutDirectionFromLocale(Locale.getDefault()))) { 17941 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL; 17942 } 17943 break; 17944 default: 17945 // Nothing to do, LTR by default 17946 } 17947 } 17948 17949 // Set to resolved 17950 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED; 17951 return true; 17952 } 17953 17954 /** 17955 * Check if layout direction resolution can be done. 17956 * 17957 * @return true if layout direction resolution can be done otherwise return false. 17958 */ 17959 public boolean canResolveLayoutDirection() { 17960 switch (getRawLayoutDirection()) { 17961 case LAYOUT_DIRECTION_INHERIT: 17962 if (mParent != null) { 17963 try { 17964 return mParent.canResolveLayoutDirection(); 17965 } catch (AbstractMethodError e) { 17966 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 17967 " does not fully implement ViewParent", e); 17968 } 17969 } 17970 return false; 17971 17972 default: 17973 return true; 17974 } 17975 } 17976 17977 /** 17978 * Reset the resolved layout direction. Layout direction will be resolved during a call to 17979 * {@link #onMeasure(int, int)}. 17980 * 17981 * @hide 17982 */ 17983 public void resetResolvedLayoutDirection() { 17984 // Reset the current resolved bits 17985 mPrivateFlags2 &= ~PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK; 17986 } 17987 17988 /** 17989 * @return true if the layout direction is inherited. 17990 * 17991 * @hide 17992 */ 17993 public boolean isLayoutDirectionInherited() { 17994 return (getRawLayoutDirection() == LAYOUT_DIRECTION_INHERIT); 17995 } 17996 17997 /** 17998 * @return true if layout direction has been resolved. 17999 */ 18000 public boolean isLayoutDirectionResolved() { 18001 return (mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_RESOLVED) == PFLAG2_LAYOUT_DIRECTION_RESOLVED; 18002 } 18003 18004 /** 18005 * Return if padding has been resolved 18006 * 18007 * @hide 18008 */ 18009 boolean isPaddingResolved() { 18010 return (mPrivateFlags2 & PFLAG2_PADDING_RESOLVED) == PFLAG2_PADDING_RESOLVED; 18011 } 18012 18013 /** 18014 * Resolves padding depending on layout direction, if applicable, and 18015 * recomputes internal padding values to adjust for scroll bars. 18016 * 18017 * @hide 18018 */ 18019 public void resolvePadding() { 18020 final int resolvedLayoutDirection = getLayoutDirection(); 18021 18022 if (!isRtlCompatibilityMode()) { 18023 // Post Jelly Bean MR1 case: we need to take the resolved layout direction into account. 18024 // If start / end padding are defined, they will be resolved (hence overriding) to 18025 // left / right or right / left depending on the resolved layout direction. 18026 // If start / end padding are not defined, use the left / right ones. 18027 if (mBackground != null && (!mLeftPaddingDefined || !mRightPaddingDefined)) { 18028 Rect padding = sThreadLocal.get(); 18029 if (padding == null) { 18030 padding = new Rect(); 18031 sThreadLocal.set(padding); 18032 } 18033 mBackground.getPadding(padding); 18034 if (!mLeftPaddingDefined) { 18035 mUserPaddingLeftInitial = padding.left; 18036 } 18037 if (!mRightPaddingDefined) { 18038 mUserPaddingRightInitial = padding.right; 18039 } 18040 } 18041 switch (resolvedLayoutDirection) { 18042 case LAYOUT_DIRECTION_RTL: 18043 if (mUserPaddingStart != UNDEFINED_PADDING) { 18044 mUserPaddingRight = mUserPaddingStart; 18045 } else { 18046 mUserPaddingRight = mUserPaddingRightInitial; 18047 } 18048 if (mUserPaddingEnd != UNDEFINED_PADDING) { 18049 mUserPaddingLeft = mUserPaddingEnd; 18050 } else { 18051 mUserPaddingLeft = mUserPaddingLeftInitial; 18052 } 18053 break; 18054 case LAYOUT_DIRECTION_LTR: 18055 default: 18056 if (mUserPaddingStart != UNDEFINED_PADDING) { 18057 mUserPaddingLeft = mUserPaddingStart; 18058 } else { 18059 mUserPaddingLeft = mUserPaddingLeftInitial; 18060 } 18061 if (mUserPaddingEnd != UNDEFINED_PADDING) { 18062 mUserPaddingRight = mUserPaddingEnd; 18063 } else { 18064 mUserPaddingRight = mUserPaddingRightInitial; 18065 } 18066 } 18067 18068 mUserPaddingBottom = (mUserPaddingBottom >= 0) ? mUserPaddingBottom : mPaddingBottom; 18069 } 18070 18071 internalSetPadding(mUserPaddingLeft, mPaddingTop, mUserPaddingRight, mUserPaddingBottom); 18072 onRtlPropertiesChanged(resolvedLayoutDirection); 18073 18074 mPrivateFlags2 |= PFLAG2_PADDING_RESOLVED; 18075 } 18076 18077 /** 18078 * Reset the resolved layout direction. 18079 * 18080 * @hide 18081 */ 18082 public void resetResolvedPadding() { 18083 resetResolvedPaddingInternal(); 18084 } 18085 18086 /** 18087 * Used when we only want to reset *this* view's padding and not trigger overrides 18088 * in ViewGroup that reset children too. 18089 */ 18090 void resetResolvedPaddingInternal() { 18091 mPrivateFlags2 &= ~PFLAG2_PADDING_RESOLVED; 18092 } 18093 18094 /** 18095 * This is called when the view is detached from a window. At this point it 18096 * no longer has a surface for drawing. 18097 * 18098 * @see #onAttachedToWindow() 18099 */ 18100 @CallSuper 18101 protected void onDetachedFromWindow() { 18102 } 18103 18104 /** 18105 * This is a framework-internal mirror of onDetachedFromWindow() that's called 18106 * after onDetachedFromWindow(). 18107 * 18108 * If you override this you *MUST* call super.onDetachedFromWindowInternal()! 18109 * The super method should be called at the end of the overridden method to ensure 18110 * subclasses are destroyed first 18111 * 18112 * @hide 18113 */ 18114 @CallSuper 18115 protected void onDetachedFromWindowInternal() { 18116 mPrivateFlags &= ~PFLAG_CANCEL_NEXT_UP_EVENT; 18117 mPrivateFlags3 &= ~PFLAG3_IS_LAID_OUT; 18118 mPrivateFlags3 &= ~PFLAG3_TEMPORARY_DETACH; 18119 18120 removeUnsetPressCallback(); 18121 removeLongPressCallback(); 18122 removePerformClickCallback(); 18123 cancel(mSendViewScrolledAccessibilityEvent); 18124 stopNestedScroll(); 18125 18126 // Anything that started animating right before detach should already 18127 // be in its final state when re-attached. 18128 jumpDrawablesToCurrentState(); 18129 18130 destroyDrawingCache(); 18131 18132 cleanupDraw(); 18133 mCurrentAnimation = null; 18134 18135 if ((mViewFlags & TOOLTIP) == TOOLTIP) { 18136 hideTooltip(); 18137 } 18138 } 18139 18140 private void cleanupDraw() { 18141 resetDisplayList(); 18142 if (mAttachInfo != null) { 18143 mAttachInfo.mViewRootImpl.cancelInvalidate(this); 18144 } 18145 } 18146 18147 void invalidateInheritedLayoutMode(int layoutModeOfRoot) { 18148 } 18149 18150 /** 18151 * @return The number of times this view has been attached to a window 18152 */ 18153 protected int getWindowAttachCount() { 18154 return mWindowAttachCount; 18155 } 18156 18157 /** 18158 * Retrieve a unique token identifying the window this view is attached to. 18159 * @return Return the window's token for use in 18160 * {@link WindowManager.LayoutParams#token WindowManager.LayoutParams.token}. 18161 */ 18162 public IBinder getWindowToken() { 18163 return mAttachInfo != null ? mAttachInfo.mWindowToken : null; 18164 } 18165 18166 /** 18167 * Retrieve the {@link WindowId} for the window this view is 18168 * currently attached to. 18169 */ 18170 public WindowId getWindowId() { 18171 AttachInfo ai = mAttachInfo; 18172 if (ai == null) { 18173 return null; 18174 } 18175 if (ai.mWindowId == null) { 18176 try { 18177 ai.mIWindowId = ai.mSession.getWindowId(ai.mWindowToken); 18178 if (ai.mIWindowId != null) { 18179 ai.mWindowId = new WindowId(ai.mIWindowId); 18180 } 18181 } catch (RemoteException e) { 18182 } 18183 } 18184 return ai.mWindowId; 18185 } 18186 18187 /** 18188 * Retrieve a unique token identifying the top-level "real" window of 18189 * the window that this view is attached to. That is, this is like 18190 * {@link #getWindowToken}, except if the window this view in is a panel 18191 * window (attached to another containing window), then the token of 18192 * the containing window is returned instead. 18193 * 18194 * @return Returns the associated window token, either 18195 * {@link #getWindowToken()} or the containing window's token. 18196 */ 18197 public IBinder getApplicationWindowToken() { 18198 AttachInfo ai = mAttachInfo; 18199 if (ai != null) { 18200 IBinder appWindowToken = ai.mPanelParentWindowToken; 18201 if (appWindowToken == null) { 18202 appWindowToken = ai.mWindowToken; 18203 } 18204 return appWindowToken; 18205 } 18206 return null; 18207 } 18208 18209 /** 18210 * Gets the logical display to which the view's window has been attached. 18211 * 18212 * @return The logical display, or null if the view is not currently attached to a window. 18213 */ 18214 public Display getDisplay() { 18215 return mAttachInfo != null ? mAttachInfo.mDisplay : null; 18216 } 18217 18218 /** 18219 * Retrieve private session object this view hierarchy is using to 18220 * communicate with the window manager. 18221 * @return the session object to communicate with the window manager 18222 */ 18223 /*package*/ IWindowSession getWindowSession() { 18224 return mAttachInfo != null ? mAttachInfo.mSession : null; 18225 } 18226 18227 /** 18228 * Return the window this view is currently attached to. Used in 18229 * {@link android.app.ActivityView} to communicate with WM. 18230 * @hide 18231 */ 18232 protected IWindow getWindow() { 18233 return mAttachInfo != null ? mAttachInfo.mWindow : null; 18234 } 18235 18236 /** 18237 * Return the visibility value of the least visible component passed. 18238 */ 18239 int combineVisibility(int vis1, int vis2) { 18240 // This works because VISIBLE < INVISIBLE < GONE. 18241 return Math.max(vis1, vis2); 18242 } 18243 18244 /** 18245 * @param info the {@link android.view.View.AttachInfo} to associated with 18246 * this view 18247 */ 18248 void dispatchAttachedToWindow(AttachInfo info, int visibility) { 18249 mAttachInfo = info; 18250 if (mOverlay != null) { 18251 mOverlay.getOverlayView().dispatchAttachedToWindow(info, visibility); 18252 } 18253 mWindowAttachCount++; 18254 // We will need to evaluate the drawable state at least once. 18255 mPrivateFlags |= PFLAG_DRAWABLE_STATE_DIRTY; 18256 if (mFloatingTreeObserver != null) { 18257 info.mTreeObserver.merge(mFloatingTreeObserver); 18258 mFloatingTreeObserver = null; 18259 } 18260 18261 registerPendingFrameMetricsObservers(); 18262 18263 if ((mPrivateFlags&PFLAG_SCROLL_CONTAINER) != 0) { 18264 mAttachInfo.mScrollContainers.add(this); 18265 mPrivateFlags |= PFLAG_SCROLL_CONTAINER_ADDED; 18266 } 18267 // Transfer all pending runnables. 18268 if (mRunQueue != null) { 18269 mRunQueue.executeActions(info.mHandler); 18270 mRunQueue = null; 18271 } 18272 performCollectViewAttributes(mAttachInfo, visibility); 18273 onAttachedToWindow(); 18274 18275 ListenerInfo li = mListenerInfo; 18276 final CopyOnWriteArrayList<OnAttachStateChangeListener> listeners = 18277 li != null ? li.mOnAttachStateChangeListeners : null; 18278 if (listeners != null && listeners.size() > 0) { 18279 // NOTE: because of the use of CopyOnWriteArrayList, we *must* use an iterator to 18280 // perform the dispatching. The iterator is a safe guard against listeners that 18281 // could mutate the list by calling the various add/remove methods. This prevents 18282 // the array from being modified while we iterate it. 18283 for (OnAttachStateChangeListener listener : listeners) { 18284 listener.onViewAttachedToWindow(this); 18285 } 18286 } 18287 18288 int vis = info.mWindowVisibility; 18289 if (vis != GONE) { 18290 onWindowVisibilityChanged(vis); 18291 if (isShown()) { 18292 // Calling onVisibilityAggregated directly here since the subtree will also 18293 // receive dispatchAttachedToWindow and this same call 18294 onVisibilityAggregated(vis == VISIBLE); 18295 } 18296 } 18297 18298 // Send onVisibilityChanged directly instead of dispatchVisibilityChanged. 18299 // As all views in the subtree will already receive dispatchAttachedToWindow 18300 // traversing the subtree again here is not desired. 18301 onVisibilityChanged(this, visibility); 18302 18303 if ((mPrivateFlags&PFLAG_DRAWABLE_STATE_DIRTY) != 0) { 18304 // If nobody has evaluated the drawable state yet, then do it now. 18305 refreshDrawableState(); 18306 } 18307 needGlobalAttributesUpdate(false); 18308 18309 notifyEnterOrExitForAutoFillIfNeeded(true); 18310 } 18311 18312 void dispatchDetachedFromWindow() { 18313 AttachInfo info = mAttachInfo; 18314 if (info != null) { 18315 int vis = info.mWindowVisibility; 18316 if (vis != GONE) { 18317 onWindowVisibilityChanged(GONE); 18318 if (isShown()) { 18319 // Invoking onVisibilityAggregated directly here since the subtree 18320 // will also receive detached from window 18321 onVisibilityAggregated(false); 18322 } 18323 } 18324 } 18325 18326 onDetachedFromWindow(); 18327 onDetachedFromWindowInternal(); 18328 18329 InputMethodManager imm = InputMethodManager.peekInstance(); 18330 if (imm != null) { 18331 imm.onViewDetachedFromWindow(this); 18332 } 18333 18334 ListenerInfo li = mListenerInfo; 18335 final CopyOnWriteArrayList<OnAttachStateChangeListener> listeners = 18336 li != null ? li.mOnAttachStateChangeListeners : null; 18337 if (listeners != null && listeners.size() > 0) { 18338 // NOTE: because of the use of CopyOnWriteArrayList, we *must* use an iterator to 18339 // perform the dispatching. The iterator is a safe guard against listeners that 18340 // could mutate the list by calling the various add/remove methods. This prevents 18341 // the array from being modified while we iterate it. 18342 for (OnAttachStateChangeListener listener : listeners) { 18343 listener.onViewDetachedFromWindow(this); 18344 } 18345 } 18346 18347 if ((mPrivateFlags & PFLAG_SCROLL_CONTAINER_ADDED) != 0) { 18348 mAttachInfo.mScrollContainers.remove(this); 18349 mPrivateFlags &= ~PFLAG_SCROLL_CONTAINER_ADDED; 18350 } 18351 18352 mAttachInfo = null; 18353 if (mOverlay != null) { 18354 mOverlay.getOverlayView().dispatchDetachedFromWindow(); 18355 } 18356 18357 notifyEnterOrExitForAutoFillIfNeeded(false); 18358 } 18359 18360 /** 18361 * Cancel any deferred high-level input events that were previously posted to the event queue. 18362 * 18363 * <p>Many views post high-level events such as click handlers to the event queue 18364 * to run deferred in order to preserve a desired user experience - clearing visible 18365 * pressed states before executing, etc. This method will abort any events of this nature 18366 * that are currently in flight.</p> 18367 * 18368 * <p>Custom views that generate their own high-level deferred input events should override 18369 * {@link #onCancelPendingInputEvents()} and remove those pending events from the queue.</p> 18370 * 18371 * <p>This will also cancel pending input events for any child views.</p> 18372 * 18373 * <p>Note that this may not be sufficient as a debouncing strategy for clicks in all cases. 18374 * This will not impact newer events posted after this call that may occur as a result of 18375 * lower-level input events still waiting in the queue. If you are trying to prevent 18376 * double-submitted events for the duration of some sort of asynchronous transaction 18377 * you should also take other steps to protect against unexpected double inputs e.g. calling 18378 * {@link #setEnabled(boolean) setEnabled(false)} and re-enabling the view when 18379 * the transaction completes, tracking already submitted transaction IDs, etc.</p> 18380 */ 18381 public final void cancelPendingInputEvents() { 18382 dispatchCancelPendingInputEvents(); 18383 } 18384 18385 /** 18386 * Called by {@link #cancelPendingInputEvents()} to cancel input events in flight. 18387 * Overridden by ViewGroup to dispatch. Package scoped to prevent app-side meddling. 18388 */ 18389 void dispatchCancelPendingInputEvents() { 18390 mPrivateFlags3 &= ~PFLAG3_CALLED_SUPER; 18391 onCancelPendingInputEvents(); 18392 if ((mPrivateFlags3 & PFLAG3_CALLED_SUPER) != PFLAG3_CALLED_SUPER) { 18393 throw new SuperNotCalledException("View " + getClass().getSimpleName() + 18394 " did not call through to super.onCancelPendingInputEvents()"); 18395 } 18396 } 18397 18398 /** 18399 * Called as the result of a call to {@link #cancelPendingInputEvents()} on this view or 18400 * a parent view. 18401 * 18402 * <p>This method is responsible for removing any pending high-level input events that were 18403 * posted to the event queue to run later. Custom view classes that post their own deferred 18404 * high-level events via {@link #post(Runnable)}, {@link #postDelayed(Runnable, long)} or 18405 * {@link android.os.Handler} should override this method, call 18406 * <code>super.onCancelPendingInputEvents()</code> and remove those callbacks as appropriate. 18407 * </p> 18408 */ 18409 public void onCancelPendingInputEvents() { 18410 removePerformClickCallback(); 18411 cancelLongPress(); 18412 mPrivateFlags3 |= PFLAG3_CALLED_SUPER; 18413 } 18414 18415 /** 18416 * Store this view hierarchy's frozen state into the given container. 18417 * 18418 * @param container The SparseArray in which to save the view's state. 18419 * 18420 * @see #restoreHierarchyState(android.util.SparseArray) 18421 * @see #dispatchSaveInstanceState(android.util.SparseArray) 18422 * @see #onSaveInstanceState() 18423 */ 18424 public void saveHierarchyState(SparseArray<Parcelable> container) { 18425 dispatchSaveInstanceState(container); 18426 } 18427 18428 /** 18429 * Called by {@link #saveHierarchyState(android.util.SparseArray)} to store the state for 18430 * this view and its children. May be overridden to modify how freezing happens to a 18431 * view's children; for example, some views may want to not store state for their children. 18432 * 18433 * @param container The SparseArray in which to save the view's state. 18434 * 18435 * @see #dispatchRestoreInstanceState(android.util.SparseArray) 18436 * @see #saveHierarchyState(android.util.SparseArray) 18437 * @see #onSaveInstanceState() 18438 */ 18439 protected void dispatchSaveInstanceState(SparseArray<Parcelable> container) { 18440 if (mID != NO_ID && (mViewFlags & SAVE_DISABLED_MASK) == 0) { 18441 mPrivateFlags &= ~PFLAG_SAVE_STATE_CALLED; 18442 Parcelable state = onSaveInstanceState(); 18443 if ((mPrivateFlags & PFLAG_SAVE_STATE_CALLED) == 0) { 18444 throw new IllegalStateException( 18445 "Derived class did not call super.onSaveInstanceState()"); 18446 } 18447 if (state != null) { 18448 // Log.i("View", "Freezing #" + Integer.toHexString(mID) 18449 // + ": " + state); 18450 container.put(mID, state); 18451 } 18452 } 18453 } 18454 18455 /** 18456 * Hook allowing a view to generate a representation of its internal state 18457 * that can later be used to create a new instance with that same state. 18458 * This state should only contain information that is not persistent or can 18459 * not be reconstructed later. For example, you will never store your 18460 * current position on screen because that will be computed again when a 18461 * new instance of the view is placed in its view hierarchy. 18462 * <p> 18463 * Some examples of things you may store here: the current cursor position 18464 * in a text view (but usually not the text itself since that is stored in a 18465 * content provider or other persistent storage), the currently selected 18466 * item in a list view. 18467 * 18468 * @return Returns a Parcelable object containing the view's current dynamic 18469 * state, or null if there is nothing interesting to save. 18470 * @see #onRestoreInstanceState(Parcelable) 18471 * @see #saveHierarchyState(SparseArray) 18472 * @see #dispatchSaveInstanceState(SparseArray) 18473 * @see #setSaveEnabled(boolean) 18474 */ 18475 @CallSuper 18476 @Nullable protected Parcelable onSaveInstanceState() { 18477 mPrivateFlags |= PFLAG_SAVE_STATE_CALLED; 18478 if (mStartActivityRequestWho != null || isAutofilled() 18479 || mAutofillViewId > LAST_APP_AUTOFILL_ID) { 18480 BaseSavedState state = new BaseSavedState(AbsSavedState.EMPTY_STATE); 18481 18482 if (mStartActivityRequestWho != null) { 18483 state.mSavedData |= BaseSavedState.START_ACTIVITY_REQUESTED_WHO_SAVED; 18484 } 18485 18486 if (isAutofilled()) { 18487 state.mSavedData |= BaseSavedState.IS_AUTOFILLED; 18488 } 18489 18490 if (mAutofillViewId > LAST_APP_AUTOFILL_ID) { 18491 state.mSavedData |= BaseSavedState.AUTOFILL_ID; 18492 } 18493 18494 state.mStartActivityRequestWhoSaved = mStartActivityRequestWho; 18495 state.mIsAutofilled = isAutofilled(); 18496 state.mAutofillViewId = mAutofillViewId; 18497 return state; 18498 } 18499 return BaseSavedState.EMPTY_STATE; 18500 } 18501 18502 /** 18503 * Restore this view hierarchy's frozen state from the given container. 18504 * 18505 * @param container The SparseArray which holds previously frozen states. 18506 * 18507 * @see #saveHierarchyState(android.util.SparseArray) 18508 * @see #dispatchRestoreInstanceState(android.util.SparseArray) 18509 * @see #onRestoreInstanceState(android.os.Parcelable) 18510 */ 18511 public void restoreHierarchyState(SparseArray<Parcelable> container) { 18512 dispatchRestoreInstanceState(container); 18513 } 18514 18515 /** 18516 * Called by {@link #restoreHierarchyState(android.util.SparseArray)} to retrieve the 18517 * state for this view and its children. May be overridden to modify how restoring 18518 * happens to a view's children; for example, some views may want to not store state 18519 * for their children. 18520 * 18521 * @param container The SparseArray which holds previously saved state. 18522 * 18523 * @see #dispatchSaveInstanceState(android.util.SparseArray) 18524 * @see #restoreHierarchyState(android.util.SparseArray) 18525 * @see #onRestoreInstanceState(android.os.Parcelable) 18526 */ 18527 protected void dispatchRestoreInstanceState(SparseArray<Parcelable> container) { 18528 if (mID != NO_ID) { 18529 Parcelable state = container.get(mID); 18530 if (state != null) { 18531 // Log.i("View", "Restoreing #" + Integer.toHexString(mID) 18532 // + ": " + state); 18533 mPrivateFlags &= ~PFLAG_SAVE_STATE_CALLED; 18534 onRestoreInstanceState(state); 18535 if ((mPrivateFlags & PFLAG_SAVE_STATE_CALLED) == 0) { 18536 throw new IllegalStateException( 18537 "Derived class did not call super.onRestoreInstanceState()"); 18538 } 18539 } 18540 } 18541 } 18542 18543 /** 18544 * Hook allowing a view to re-apply a representation of its internal state that had previously 18545 * been generated by {@link #onSaveInstanceState}. This function will never be called with a 18546 * null state. 18547 * 18548 * @param state The frozen state that had previously been returned by 18549 * {@link #onSaveInstanceState}. 18550 * 18551 * @see #onSaveInstanceState() 18552 * @see #restoreHierarchyState(android.util.SparseArray) 18553 * @see #dispatchRestoreInstanceState(android.util.SparseArray) 18554 */ 18555 @CallSuper 18556 protected void onRestoreInstanceState(Parcelable state) { 18557 mPrivateFlags |= PFLAG_SAVE_STATE_CALLED; 18558 if (state != null && !(state instanceof AbsSavedState)) { 18559 throw new IllegalArgumentException("Wrong state class, expecting View State but " 18560 + "received " + state.getClass().toString() + " instead. This usually happens " 18561 + "when two views of different type have the same id in the same hierarchy. " 18562 + "This view's id is " + ViewDebug.resolveId(mContext, getId()) + ". Make sure " 18563 + "other views do not use the same id."); 18564 } 18565 if (state != null && state instanceof BaseSavedState) { 18566 BaseSavedState baseState = (BaseSavedState) state; 18567 18568 if ((baseState.mSavedData & BaseSavedState.START_ACTIVITY_REQUESTED_WHO_SAVED) != 0) { 18569 mStartActivityRequestWho = baseState.mStartActivityRequestWhoSaved; 18570 } 18571 if ((baseState.mSavedData & BaseSavedState.IS_AUTOFILLED) != 0) { 18572 setAutofilled(baseState.mIsAutofilled); 18573 } 18574 if ((baseState.mSavedData & BaseSavedState.AUTOFILL_ID) != 0) { 18575 // It can happen that views have the same view id and the restoration path will not 18576 // be able to distinguish between them. The autofill id needs to be unique though. 18577 // Hence prevent the same autofill view id from being restored multiple times. 18578 ((BaseSavedState) state).mSavedData &= ~BaseSavedState.AUTOFILL_ID; 18579 18580 if ((mPrivateFlags3 & PFLAG3_AUTOFILLID_EXPLICITLY_SET) != 0) { 18581 // Ignore when view already set it through setAutofillId(); 18582 if (android.view.autofill.Helper.sDebug) { 18583 Log.d(VIEW_LOG_TAG, "onRestoreInstanceState(): not setting autofillId to " 18584 + baseState.mAutofillViewId + " because view explicitly set it to " 18585 + mAutofillId); 18586 } 18587 } else { 18588 mAutofillViewId = baseState.mAutofillViewId; 18589 mAutofillId = null; // will be set on demand by getAutofillId() 18590 } 18591 } 18592 } 18593 } 18594 18595 /** 18596 * <p>Return the time at which the drawing of the view hierarchy started.</p> 18597 * 18598 * @return the drawing start time in milliseconds 18599 */ 18600 public long getDrawingTime() { 18601 return mAttachInfo != null ? mAttachInfo.mDrawingTime : 0; 18602 } 18603 18604 /** 18605 * <p>Enables or disables the duplication of the parent's state into this view. When 18606 * duplication is enabled, this view gets its drawable state from its parent rather 18607 * than from its own internal properties.</p> 18608 * 18609 * <p>Note: in the current implementation, setting this property to true after the 18610 * view was added to a ViewGroup might have no effect at all. This property should 18611 * always be used from XML or set to true before adding this view to a ViewGroup.</p> 18612 * 18613 * <p>Note: if this view's parent addStateFromChildren property is enabled and this 18614 * property is enabled, an exception will be thrown.</p> 18615 * 18616 * <p>Note: if the child view uses and updates additional states which are unknown to the 18617 * parent, these states should not be affected by this method.</p> 18618 * 18619 * @param enabled True to enable duplication of the parent's drawable state, false 18620 * to disable it. 18621 * 18622 * @see #getDrawableState() 18623 * @see #isDuplicateParentStateEnabled() 18624 */ 18625 public void setDuplicateParentStateEnabled(boolean enabled) { 18626 setFlags(enabled ? DUPLICATE_PARENT_STATE : 0, DUPLICATE_PARENT_STATE); 18627 } 18628 18629 /** 18630 * <p>Indicates whether this duplicates its drawable state from its parent.</p> 18631 * 18632 * @return True if this view's drawable state is duplicated from the parent, 18633 * false otherwise 18634 * 18635 * @see #getDrawableState() 18636 * @see #setDuplicateParentStateEnabled(boolean) 18637 */ 18638 public boolean isDuplicateParentStateEnabled() { 18639 return (mViewFlags & DUPLICATE_PARENT_STATE) == DUPLICATE_PARENT_STATE; 18640 } 18641 18642 /** 18643 * <p>Specifies the type of layer backing this view. The layer can be 18644 * {@link #LAYER_TYPE_NONE}, {@link #LAYER_TYPE_SOFTWARE} or 18645 * {@link #LAYER_TYPE_HARDWARE}.</p> 18646 * 18647 * <p>A layer is associated with an optional {@link android.graphics.Paint} 18648 * instance that controls how the layer is composed on screen. The following 18649 * properties of the paint are taken into account when composing the layer:</p> 18650 * <ul> 18651 * <li>{@link android.graphics.Paint#getAlpha() Translucency (alpha)}</li> 18652 * <li>{@link android.graphics.Paint#getXfermode() Blending mode}</li> 18653 * <li>{@link android.graphics.Paint#getColorFilter() Color filter}</li> 18654 * </ul> 18655 * 18656 * <p>If this view has an alpha value set to < 1.0 by calling 18657 * {@link #setAlpha(float)}, the alpha value of the layer's paint is superseded 18658 * by this view's alpha value.</p> 18659 * 18660 * <p>Refer to the documentation of {@link #LAYER_TYPE_NONE}, 18661 * {@link #LAYER_TYPE_SOFTWARE} and {@link #LAYER_TYPE_HARDWARE} 18662 * for more information on when and how to use layers.</p> 18663 * 18664 * @param layerType The type of layer to use with this view, must be one of 18665 * {@link #LAYER_TYPE_NONE}, {@link #LAYER_TYPE_SOFTWARE} or 18666 * {@link #LAYER_TYPE_HARDWARE} 18667 * @param paint The paint used to compose the layer. This argument is optional 18668 * and can be null. It is ignored when the layer type is 18669 * {@link #LAYER_TYPE_NONE} 18670 * 18671 * @see #getLayerType() 18672 * @see #LAYER_TYPE_NONE 18673 * @see #LAYER_TYPE_SOFTWARE 18674 * @see #LAYER_TYPE_HARDWARE 18675 * @see #setAlpha(float) 18676 * 18677 * @attr ref android.R.styleable#View_layerType 18678 */ 18679 public void setLayerType(int layerType, @Nullable Paint paint) { 18680 if (layerType < LAYER_TYPE_NONE || layerType > LAYER_TYPE_HARDWARE) { 18681 throw new IllegalArgumentException("Layer type can only be one of: LAYER_TYPE_NONE, " 18682 + "LAYER_TYPE_SOFTWARE or LAYER_TYPE_HARDWARE"); 18683 } 18684 18685 boolean typeChanged = mRenderNode.setLayerType(layerType); 18686 18687 if (!typeChanged) { 18688 setLayerPaint(paint); 18689 return; 18690 } 18691 18692 if (layerType != LAYER_TYPE_SOFTWARE) { 18693 // Destroy any previous software drawing cache if present 18694 // NOTE: even if previous layer type is HW, we do this to ensure we've cleaned up 18695 // drawing cache created in View#draw when drawing to a SW canvas. 18696 destroyDrawingCache(); 18697 } 18698 18699 mLayerType = layerType; 18700 mLayerPaint = mLayerType == LAYER_TYPE_NONE ? null : paint; 18701 mRenderNode.setLayerPaint(mLayerPaint); 18702 18703 // draw() behaves differently if we are on a layer, so we need to 18704 // invalidate() here 18705 invalidateParentCaches(); 18706 invalidate(true); 18707 } 18708 18709 /** 18710 * Updates the {@link Paint} object used with the current layer (used only if the current 18711 * layer type is not set to {@link #LAYER_TYPE_NONE}). Changed properties of the Paint 18712 * provided to {@link #setLayerType(int, android.graphics.Paint)} will be used the next time 18713 * the View is redrawn, but {@link #setLayerPaint(android.graphics.Paint)} must be called to 18714 * ensure that the view gets redrawn immediately. 18715 * 18716 * <p>A layer is associated with an optional {@link android.graphics.Paint} 18717 * instance that controls how the layer is composed on screen. The following 18718 * properties of the paint are taken into account when composing the layer:</p> 18719 * <ul> 18720 * <li>{@link android.graphics.Paint#getAlpha() Translucency (alpha)}</li> 18721 * <li>{@link android.graphics.Paint#getXfermode() Blending mode}</li> 18722 * <li>{@link android.graphics.Paint#getColorFilter() Color filter}</li> 18723 * </ul> 18724 * 18725 * <p>If this view has an alpha value set to < 1.0 by calling {@link #setAlpha(float)}, the 18726 * alpha value of the layer's paint is superseded by this view's alpha value.</p> 18727 * 18728 * @param paint The paint used to compose the layer. This argument is optional 18729 * and can be null. It is ignored when the layer type is 18730 * {@link #LAYER_TYPE_NONE} 18731 * 18732 * @see #setLayerType(int, android.graphics.Paint) 18733 */ 18734 public void setLayerPaint(@Nullable Paint paint) { 18735 int layerType = getLayerType(); 18736 if (layerType != LAYER_TYPE_NONE) { 18737 mLayerPaint = paint; 18738 if (layerType == LAYER_TYPE_HARDWARE) { 18739 if (mRenderNode.setLayerPaint(paint)) { 18740 invalidateViewProperty(false, false); 18741 } 18742 } else { 18743 invalidate(); 18744 } 18745 } 18746 } 18747 18748 /** 18749 * Indicates what type of layer is currently associated with this view. By default 18750 * a view does not have a layer, and the layer type is {@link #LAYER_TYPE_NONE}. 18751 * Refer to the documentation of {@link #setLayerType(int, android.graphics.Paint)} 18752 * for more information on the different types of layers. 18753 * 18754 * @return {@link #LAYER_TYPE_NONE}, {@link #LAYER_TYPE_SOFTWARE} or 18755 * {@link #LAYER_TYPE_HARDWARE} 18756 * 18757 * @see #setLayerType(int, android.graphics.Paint) 18758 * @see #buildLayer() 18759 * @see #LAYER_TYPE_NONE 18760 * @see #LAYER_TYPE_SOFTWARE 18761 * @see #LAYER_TYPE_HARDWARE 18762 */ 18763 public int getLayerType() { 18764 return mLayerType; 18765 } 18766 18767 /** 18768 * Forces this view's layer to be created and this view to be rendered 18769 * into its layer. If this view's layer type is set to {@link #LAYER_TYPE_NONE}, 18770 * invoking this method will have no effect. 18771 * 18772 * This method can for instance be used to render a view into its layer before 18773 * starting an animation. If this view is complex, rendering into the layer 18774 * before starting the animation will avoid skipping frames. 18775 * 18776 * @throws IllegalStateException If this view is not attached to a window 18777 * 18778 * @see #setLayerType(int, android.graphics.Paint) 18779 */ 18780 public void buildLayer() { 18781 if (mLayerType == LAYER_TYPE_NONE) return; 18782 18783 final AttachInfo attachInfo = mAttachInfo; 18784 if (attachInfo == null) { 18785 throw new IllegalStateException("This view must be attached to a window first"); 18786 } 18787 18788 if (getWidth() == 0 || getHeight() == 0) { 18789 return; 18790 } 18791 18792 switch (mLayerType) { 18793 case LAYER_TYPE_HARDWARE: 18794 updateDisplayListIfDirty(); 18795 if (attachInfo.mThreadedRenderer != null && mRenderNode.isValid()) { 18796 attachInfo.mThreadedRenderer.buildLayer(mRenderNode); 18797 } 18798 break; 18799 case LAYER_TYPE_SOFTWARE: 18800 buildDrawingCache(true); 18801 break; 18802 } 18803 } 18804 18805 /** 18806 * Destroys all hardware rendering resources. This method is invoked 18807 * when the system needs to reclaim resources. Upon execution of this 18808 * method, you should free any OpenGL resources created by the view. 18809 * 18810 * Note: you <strong>must</strong> call 18811 * <code>super.destroyHardwareResources()</code> when overriding 18812 * this method. 18813 * 18814 * @hide 18815 */ 18816 @CallSuper 18817 protected void destroyHardwareResources() { 18818 if (mOverlay != null) { 18819 mOverlay.getOverlayView().destroyHardwareResources(); 18820 } 18821 if (mGhostView != null) { 18822 mGhostView.destroyHardwareResources(); 18823 } 18824 } 18825 18826 /** 18827 * <p>Enables or disables the drawing cache. When the drawing cache is enabled, the next call 18828 * to {@link #getDrawingCache()} or {@link #buildDrawingCache()} will draw the view in a 18829 * bitmap. Calling {@link #draw(android.graphics.Canvas)} will not draw from the cache when 18830 * the cache is enabled. To benefit from the cache, you must request the drawing cache by 18831 * calling {@link #getDrawingCache()} and draw it on screen if the returned bitmap is not 18832 * null.</p> 18833 * 18834 * <p>Enabling the drawing cache is similar to 18835 * {@link #setLayerType(int, android.graphics.Paint) setting a layer} when hardware 18836 * acceleration is turned off. When hardware acceleration is turned on, enabling the 18837 * drawing cache has no effect on rendering because the system uses a different mechanism 18838 * for acceleration which ignores the flag. If you want to use a Bitmap for the view, even 18839 * when hardware acceleration is enabled, see {@link #setLayerType(int, android.graphics.Paint)} 18840 * for information on how to enable software and hardware layers.</p> 18841 * 18842 * <p>This API can be used to manually generate 18843 * a bitmap copy of this view, by setting the flag to <code>true</code> and calling 18844 * {@link #getDrawingCache()}.</p> 18845 * 18846 * @param enabled true to enable the drawing cache, false otherwise 18847 * 18848 * @see #isDrawingCacheEnabled() 18849 * @see #getDrawingCache() 18850 * @see #buildDrawingCache() 18851 * @see #setLayerType(int, android.graphics.Paint) 18852 * 18853 * @deprecated The view drawing cache was largely made obsolete with the introduction of 18854 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 18855 * layers are largely unnecessary and can easily result in a net loss in performance due to the 18856 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 18857 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 18858 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 18859 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 18860 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 18861 * software-rendered usages are discouraged and have compatibility issues with hardware-only 18862 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 18863 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 18864 * reports or unit testing the {@link PixelCopy} API is recommended. 18865 */ 18866 @Deprecated 18867 public void setDrawingCacheEnabled(boolean enabled) { 18868 mCachingFailed = false; 18869 setFlags(enabled ? DRAWING_CACHE_ENABLED : 0, DRAWING_CACHE_ENABLED); 18870 } 18871 18872 /** 18873 * <p>Indicates whether the drawing cache is enabled for this view.</p> 18874 * 18875 * @return true if the drawing cache is enabled 18876 * 18877 * @see #setDrawingCacheEnabled(boolean) 18878 * @see #getDrawingCache() 18879 * 18880 * @deprecated The view drawing cache was largely made obsolete with the introduction of 18881 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 18882 * layers are largely unnecessary and can easily result in a net loss in performance due to the 18883 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 18884 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 18885 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 18886 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 18887 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 18888 * software-rendered usages are discouraged and have compatibility issues with hardware-only 18889 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 18890 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 18891 * reports or unit testing the {@link PixelCopy} API is recommended. 18892 */ 18893 @Deprecated 18894 @ViewDebug.ExportedProperty(category = "drawing") 18895 public boolean isDrawingCacheEnabled() { 18896 return (mViewFlags & DRAWING_CACHE_ENABLED) == DRAWING_CACHE_ENABLED; 18897 } 18898 18899 /** 18900 * Debugging utility which recursively outputs the dirty state of a view and its 18901 * descendants. 18902 * 18903 * @hide 18904 */ 18905 @SuppressWarnings({"UnusedDeclaration"}) 18906 public void outputDirtyFlags(String indent, boolean clear, int clearMask) { 18907 Log.d(VIEW_LOG_TAG, indent + this + " DIRTY(" 18908 + (mPrivateFlags & View.PFLAG_DIRTY_MASK) 18909 + ") DRAWN(" + (mPrivateFlags & PFLAG_DRAWN) + ")" + " CACHE_VALID(" 18910 + (mPrivateFlags & View.PFLAG_DRAWING_CACHE_VALID) 18911 + ") INVALIDATED(" + (mPrivateFlags & PFLAG_INVALIDATED) + ")"); 18912 if (clear) { 18913 mPrivateFlags &= clearMask; 18914 } 18915 if (this instanceof ViewGroup) { 18916 ViewGroup parent = (ViewGroup) this; 18917 final int count = parent.getChildCount(); 18918 for (int i = 0; i < count; i++) { 18919 final View child = parent.getChildAt(i); 18920 child.outputDirtyFlags(indent + " ", clear, clearMask); 18921 } 18922 } 18923 } 18924 18925 /** 18926 * This method is used by ViewGroup to cause its children to restore or recreate their 18927 * display lists. It is called by getDisplayList() when the parent ViewGroup does not need 18928 * to recreate its own display list, which would happen if it went through the normal 18929 * draw/dispatchDraw mechanisms. 18930 * 18931 * @hide 18932 */ 18933 protected void dispatchGetDisplayList() {} 18934 18935 /** 18936 * A view that is not attached or hardware accelerated cannot create a display list. 18937 * This method checks these conditions and returns the appropriate result. 18938 * 18939 * @return true if view has the ability to create a display list, false otherwise. 18940 * 18941 * @hide 18942 */ 18943 public boolean canHaveDisplayList() { 18944 return !(mAttachInfo == null || mAttachInfo.mThreadedRenderer == null); 18945 } 18946 18947 /** 18948 * Gets the RenderNode for the view, and updates its DisplayList (if needed and supported) 18949 * @hide 18950 */ 18951 @NonNull 18952 public RenderNode updateDisplayListIfDirty() { 18953 final RenderNode renderNode = mRenderNode; 18954 if (!canHaveDisplayList()) { 18955 // can't populate RenderNode, don't try 18956 return renderNode; 18957 } 18958 18959 if ((mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == 0 18960 || !renderNode.isValid() 18961 || (mRecreateDisplayList)) { 18962 // Don't need to recreate the display list, just need to tell our 18963 // children to restore/recreate theirs 18964 if (renderNode.isValid() 18965 && !mRecreateDisplayList) { 18966 mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID; 18967 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 18968 dispatchGetDisplayList(); 18969 18970 return renderNode; // no work needed 18971 } 18972 18973 // If we got here, we're recreating it. Mark it as such to ensure that 18974 // we copy in child display lists into ours in drawChild() 18975 mRecreateDisplayList = true; 18976 18977 int width = mRight - mLeft; 18978 int height = mBottom - mTop; 18979 int layerType = getLayerType(); 18980 18981 final DisplayListCanvas canvas = renderNode.start(width, height); 18982 18983 try { 18984 if (layerType == LAYER_TYPE_SOFTWARE) { 18985 buildDrawingCache(true); 18986 Bitmap cache = getDrawingCache(true); 18987 if (cache != null) { 18988 canvas.drawBitmap(cache, 0, 0, mLayerPaint); 18989 } 18990 } else { 18991 computeScroll(); 18992 18993 canvas.translate(-mScrollX, -mScrollY); 18994 mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID; 18995 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 18996 18997 // Fast path for layouts with no backgrounds 18998 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { 18999 dispatchDraw(canvas); 19000 drawAutofilledHighlight(canvas); 19001 if (mOverlay != null && !mOverlay.isEmpty()) { 19002 mOverlay.getOverlayView().draw(canvas); 19003 } 19004 if (debugDraw()) { 19005 debugDrawFocus(canvas); 19006 } 19007 } else { 19008 draw(canvas); 19009 } 19010 } 19011 } finally { 19012 renderNode.end(canvas); 19013 setDisplayListProperties(renderNode); 19014 } 19015 } else { 19016 mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID; 19017 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 19018 } 19019 return renderNode; 19020 } 19021 19022 private void resetDisplayList() { 19023 mRenderNode.discardDisplayList(); 19024 if (mBackgroundRenderNode != null) { 19025 mBackgroundRenderNode.discardDisplayList(); 19026 } 19027 } 19028 19029 /** 19030 * <p>Calling this method is equivalent to calling <code>getDrawingCache(false)</code>.</p> 19031 * 19032 * @return A non-scaled bitmap representing this view or null if cache is disabled. 19033 * 19034 * @see #getDrawingCache(boolean) 19035 * 19036 * @deprecated The view drawing cache was largely made obsolete with the introduction of 19037 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 19038 * layers are largely unnecessary and can easily result in a net loss in performance due to the 19039 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 19040 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 19041 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 19042 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 19043 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 19044 * software-rendered usages are discouraged and have compatibility issues with hardware-only 19045 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 19046 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 19047 * reports or unit testing the {@link PixelCopy} API is recommended. 19048 */ 19049 @Deprecated 19050 public Bitmap getDrawingCache() { 19051 return getDrawingCache(false); 19052 } 19053 19054 /** 19055 * <p>Returns the bitmap in which this view drawing is cached. The returned bitmap 19056 * is null when caching is disabled. If caching is enabled and the cache is not ready, 19057 * this method will create it. Calling {@link #draw(android.graphics.Canvas)} will not 19058 * draw from the cache when the cache is enabled. To benefit from the cache, you must 19059 * request the drawing cache by calling this method and draw it on screen if the 19060 * returned bitmap is not null.</p> 19061 * 19062 * <p>Note about auto scaling in compatibility mode: When auto scaling is not enabled, 19063 * this method will create a bitmap of the same size as this view. Because this bitmap 19064 * will be drawn scaled by the parent ViewGroup, the result on screen might show 19065 * scaling artifacts. To avoid such artifacts, you should call this method by setting 19066 * the auto scaling to true. Doing so, however, will generate a bitmap of a different 19067 * size than the view. This implies that your application must be able to handle this 19068 * size.</p> 19069 * 19070 * @param autoScale Indicates whether the generated bitmap should be scaled based on 19071 * the current density of the screen when the application is in compatibility 19072 * mode. 19073 * 19074 * @return A bitmap representing this view or null if cache is disabled. 19075 * 19076 * @see #setDrawingCacheEnabled(boolean) 19077 * @see #isDrawingCacheEnabled() 19078 * @see #buildDrawingCache(boolean) 19079 * @see #destroyDrawingCache() 19080 * 19081 * @deprecated The view drawing cache was largely made obsolete with the introduction of 19082 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 19083 * layers are largely unnecessary and can easily result in a net loss in performance due to the 19084 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 19085 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 19086 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 19087 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 19088 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 19089 * software-rendered usages are discouraged and have compatibility issues with hardware-only 19090 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 19091 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 19092 * reports or unit testing the {@link PixelCopy} API is recommended. 19093 */ 19094 @Deprecated 19095 public Bitmap getDrawingCache(boolean autoScale) { 19096 if ((mViewFlags & WILL_NOT_CACHE_DRAWING) == WILL_NOT_CACHE_DRAWING) { 19097 return null; 19098 } 19099 if ((mViewFlags & DRAWING_CACHE_ENABLED) == DRAWING_CACHE_ENABLED) { 19100 buildDrawingCache(autoScale); 19101 } 19102 return autoScale ? mDrawingCache : mUnscaledDrawingCache; 19103 } 19104 19105 /** 19106 * <p>Frees the resources used by the drawing cache. If you call 19107 * {@link #buildDrawingCache()} manually without calling 19108 * {@link #setDrawingCacheEnabled(boolean) setDrawingCacheEnabled(true)}, you 19109 * should cleanup the cache with this method afterwards.</p> 19110 * 19111 * @see #setDrawingCacheEnabled(boolean) 19112 * @see #buildDrawingCache() 19113 * @see #getDrawingCache() 19114 * 19115 * @deprecated The view drawing cache was largely made obsolete with the introduction of 19116 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 19117 * layers are largely unnecessary and can easily result in a net loss in performance due to the 19118 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 19119 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 19120 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 19121 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 19122 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 19123 * software-rendered usages are discouraged and have compatibility issues with hardware-only 19124 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 19125 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 19126 * reports or unit testing the {@link PixelCopy} API is recommended. 19127 */ 19128 @Deprecated 19129 public void destroyDrawingCache() { 19130 if (mDrawingCache != null) { 19131 mDrawingCache.recycle(); 19132 mDrawingCache = null; 19133 } 19134 if (mUnscaledDrawingCache != null) { 19135 mUnscaledDrawingCache.recycle(); 19136 mUnscaledDrawingCache = null; 19137 } 19138 } 19139 19140 /** 19141 * Setting a solid background color for the drawing cache's bitmaps will improve 19142 * performance and memory usage. Note, though that this should only be used if this 19143 * view will always be drawn on top of a solid color. 19144 * 19145 * @param color The background color to use for the drawing cache's bitmap 19146 * 19147 * @see #setDrawingCacheEnabled(boolean) 19148 * @see #buildDrawingCache() 19149 * @see #getDrawingCache() 19150 * 19151 * @deprecated The view drawing cache was largely made obsolete with the introduction of 19152 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 19153 * layers are largely unnecessary and can easily result in a net loss in performance due to the 19154 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 19155 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 19156 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 19157 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 19158 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 19159 * software-rendered usages are discouraged and have compatibility issues with hardware-only 19160 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 19161 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 19162 * reports or unit testing the {@link PixelCopy} API is recommended. 19163 */ 19164 @Deprecated 19165 public void setDrawingCacheBackgroundColor(@ColorInt int color) { 19166 if (color != mDrawingCacheBackgroundColor) { 19167 mDrawingCacheBackgroundColor = color; 19168 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; 19169 } 19170 } 19171 19172 /** 19173 * @see #setDrawingCacheBackgroundColor(int) 19174 * 19175 * @return The background color to used for the drawing cache's bitmap 19176 * 19177 * @deprecated The view drawing cache was largely made obsolete with the introduction of 19178 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 19179 * layers are largely unnecessary and can easily result in a net loss in performance due to the 19180 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 19181 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 19182 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 19183 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 19184 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 19185 * software-rendered usages are discouraged and have compatibility issues with hardware-only 19186 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 19187 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 19188 * reports or unit testing the {@link PixelCopy} API is recommended. 19189 */ 19190 @Deprecated 19191 @ColorInt 19192 public int getDrawingCacheBackgroundColor() { 19193 return mDrawingCacheBackgroundColor; 19194 } 19195 19196 /** 19197 * <p>Calling this method is equivalent to calling <code>buildDrawingCache(false)</code>.</p> 19198 * 19199 * @see #buildDrawingCache(boolean) 19200 * 19201 * @deprecated The view drawing cache was largely made obsolete with the introduction of 19202 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 19203 * layers are largely unnecessary and can easily result in a net loss in performance due to the 19204 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 19205 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 19206 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 19207 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 19208 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 19209 * software-rendered usages are discouraged and have compatibility issues with hardware-only 19210 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 19211 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 19212 * reports or unit testing the {@link PixelCopy} API is recommended. 19213 */ 19214 @Deprecated 19215 public void buildDrawingCache() { 19216 buildDrawingCache(false); 19217 } 19218 19219 /** 19220 * <p>Forces the drawing cache to be built if the drawing cache is invalid.</p> 19221 * 19222 * <p>If you call {@link #buildDrawingCache()} manually without calling 19223 * {@link #setDrawingCacheEnabled(boolean) setDrawingCacheEnabled(true)}, you 19224 * should cleanup the cache by calling {@link #destroyDrawingCache()} afterwards.</p> 19225 * 19226 * <p>Note about auto scaling in compatibility mode: When auto scaling is not enabled, 19227 * this method will create a bitmap of the same size as this view. Because this bitmap 19228 * will be drawn scaled by the parent ViewGroup, the result on screen might show 19229 * scaling artifacts. To avoid such artifacts, you should call this method by setting 19230 * the auto scaling to true. Doing so, however, will generate a bitmap of a different 19231 * size than the view. This implies that your application must be able to handle this 19232 * size.</p> 19233 * 19234 * <p>You should avoid calling this method when hardware acceleration is enabled. If 19235 * you do not need the drawing cache bitmap, calling this method will increase memory 19236 * usage and cause the view to be rendered in software once, thus negatively impacting 19237 * performance.</p> 19238 * 19239 * @see #getDrawingCache() 19240 * @see #destroyDrawingCache() 19241 * 19242 * @deprecated The view drawing cache was largely made obsolete with the introduction of 19243 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 19244 * layers are largely unnecessary and can easily result in a net loss in performance due to the 19245 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 19246 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 19247 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 19248 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 19249 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 19250 * software-rendered usages are discouraged and have compatibility issues with hardware-only 19251 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 19252 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 19253 * reports or unit testing the {@link PixelCopy} API is recommended. 19254 */ 19255 @Deprecated 19256 public void buildDrawingCache(boolean autoScale) { 19257 if ((mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == 0 || (autoScale ? 19258 mDrawingCache == null : mUnscaledDrawingCache == null)) { 19259 if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) { 19260 Trace.traceBegin(Trace.TRACE_TAG_VIEW, 19261 "buildDrawingCache/SW Layer for " + getClass().getSimpleName()); 19262 } 19263 try { 19264 buildDrawingCacheImpl(autoScale); 19265 } finally { 19266 Trace.traceEnd(Trace.TRACE_TAG_VIEW); 19267 } 19268 } 19269 } 19270 19271 /** 19272 * private, internal implementation of buildDrawingCache, used to enable tracing 19273 */ 19274 private void buildDrawingCacheImpl(boolean autoScale) { 19275 mCachingFailed = false; 19276 19277 int width = mRight - mLeft; 19278 int height = mBottom - mTop; 19279 19280 final AttachInfo attachInfo = mAttachInfo; 19281 final boolean scalingRequired = attachInfo != null && attachInfo.mScalingRequired; 19282 19283 if (autoScale && scalingRequired) { 19284 width = (int) ((width * attachInfo.mApplicationScale) + 0.5f); 19285 height = (int) ((height * attachInfo.mApplicationScale) + 0.5f); 19286 } 19287 19288 final int drawingCacheBackgroundColor = mDrawingCacheBackgroundColor; 19289 final boolean opaque = drawingCacheBackgroundColor != 0 || isOpaque(); 19290 final boolean use32BitCache = attachInfo != null && attachInfo.mUse32BitDrawingCache; 19291 19292 final long projectedBitmapSize = width * height * (opaque && !use32BitCache ? 2 : 4); 19293 final long drawingCacheSize = 19294 ViewConfiguration.get(mContext).getScaledMaximumDrawingCacheSize(); 19295 if (width <= 0 || height <= 0 || projectedBitmapSize > drawingCacheSize) { 19296 if (width > 0 && height > 0) { 19297 Log.w(VIEW_LOG_TAG, getClass().getSimpleName() + " not displayed because it is" 19298 + " too large to fit into a software layer (or drawing cache), needs " 19299 + projectedBitmapSize + " bytes, only " 19300 + drawingCacheSize + " available"); 19301 } 19302 destroyDrawingCache(); 19303 mCachingFailed = true; 19304 return; 19305 } 19306 19307 boolean clear = true; 19308 Bitmap bitmap = autoScale ? mDrawingCache : mUnscaledDrawingCache; 19309 19310 if (bitmap == null || bitmap.getWidth() != width || bitmap.getHeight() != height) { 19311 Bitmap.Config quality; 19312 if (!opaque) { 19313 // Never pick ARGB_4444 because it looks awful 19314 // Keep the DRAWING_CACHE_QUALITY_LOW flag just in case 19315 switch (mViewFlags & DRAWING_CACHE_QUALITY_MASK) { 19316 case DRAWING_CACHE_QUALITY_AUTO: 19317 case DRAWING_CACHE_QUALITY_LOW: 19318 case DRAWING_CACHE_QUALITY_HIGH: 19319 default: 19320 quality = Bitmap.Config.ARGB_8888; 19321 break; 19322 } 19323 } else { 19324 // Optimization for translucent windows 19325 // If the window is translucent, use a 32 bits bitmap to benefit from memcpy() 19326 quality = use32BitCache ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565; 19327 } 19328 19329 // Try to cleanup memory 19330 if (bitmap != null) bitmap.recycle(); 19331 19332 try { 19333 bitmap = Bitmap.createBitmap(mResources.getDisplayMetrics(), 19334 width, height, quality); 19335 bitmap.setDensity(getResources().getDisplayMetrics().densityDpi); 19336 if (autoScale) { 19337 mDrawingCache = bitmap; 19338 } else { 19339 mUnscaledDrawingCache = bitmap; 19340 } 19341 if (opaque && use32BitCache) bitmap.setHasAlpha(false); 19342 } catch (OutOfMemoryError e) { 19343 // If there is not enough memory to create the bitmap cache, just 19344 // ignore the issue as bitmap caches are not required to draw the 19345 // view hierarchy 19346 if (autoScale) { 19347 mDrawingCache = null; 19348 } else { 19349 mUnscaledDrawingCache = null; 19350 } 19351 mCachingFailed = true; 19352 return; 19353 } 19354 19355 clear = drawingCacheBackgroundColor != 0; 19356 } 19357 19358 Canvas canvas; 19359 if (attachInfo != null) { 19360 canvas = attachInfo.mCanvas; 19361 if (canvas == null) { 19362 canvas = new Canvas(); 19363 } 19364 canvas.setBitmap(bitmap); 19365 // Temporarily clobber the cached Canvas in case one of our children 19366 // is also using a drawing cache. Without this, the children would 19367 // steal the canvas by attaching their own bitmap to it and bad, bad 19368 // thing would happen (invisible views, corrupted drawings, etc.) 19369 attachInfo.mCanvas = null; 19370 } else { 19371 // This case should hopefully never or seldom happen 19372 canvas = new Canvas(bitmap); 19373 } 19374 19375 if (clear) { 19376 bitmap.eraseColor(drawingCacheBackgroundColor); 19377 } 19378 19379 computeScroll(); 19380 final int restoreCount = canvas.save(); 19381 19382 if (autoScale && scalingRequired) { 19383 final float scale = attachInfo.mApplicationScale; 19384 canvas.scale(scale, scale); 19385 } 19386 19387 canvas.translate(-mScrollX, -mScrollY); 19388 19389 mPrivateFlags |= PFLAG_DRAWN; 19390 if (mAttachInfo == null || !mAttachInfo.mHardwareAccelerated || 19391 mLayerType != LAYER_TYPE_NONE) { 19392 mPrivateFlags |= PFLAG_DRAWING_CACHE_VALID; 19393 } 19394 19395 // Fast path for layouts with no backgrounds 19396 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { 19397 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 19398 dispatchDraw(canvas); 19399 drawAutofilledHighlight(canvas); 19400 if (mOverlay != null && !mOverlay.isEmpty()) { 19401 mOverlay.getOverlayView().draw(canvas); 19402 } 19403 } else { 19404 draw(canvas); 19405 } 19406 19407 canvas.restoreToCount(restoreCount); 19408 canvas.setBitmap(null); 19409 19410 if (attachInfo != null) { 19411 // Restore the cached Canvas for our siblings 19412 attachInfo.mCanvas = canvas; 19413 } 19414 } 19415 19416 /** 19417 * Create a snapshot of the view into a bitmap. We should probably make 19418 * some form of this public, but should think about the API. 19419 * 19420 * @hide 19421 */ 19422 public Bitmap createSnapshot(ViewDebug.CanvasProvider canvasProvider, boolean skipChildren) { 19423 int width = mRight - mLeft; 19424 int height = mBottom - mTop; 19425 19426 final AttachInfo attachInfo = mAttachInfo; 19427 final float scale = attachInfo != null ? attachInfo.mApplicationScale : 1.0f; 19428 width = (int) ((width * scale) + 0.5f); 19429 height = (int) ((height * scale) + 0.5f); 19430 19431 Canvas oldCanvas = null; 19432 try { 19433 Canvas canvas = canvasProvider.getCanvas(this, 19434 width > 0 ? width : 1, height > 0 ? height : 1); 19435 19436 if (attachInfo != null) { 19437 oldCanvas = attachInfo.mCanvas; 19438 // Temporarily clobber the cached Canvas in case one of our children 19439 // is also using a drawing cache. Without this, the children would 19440 // steal the canvas by attaching their own bitmap to it and bad, bad 19441 // things would happen (invisible views, corrupted drawings, etc.) 19442 attachInfo.mCanvas = null; 19443 } 19444 19445 computeScroll(); 19446 final int restoreCount = canvas.save(); 19447 canvas.scale(scale, scale); 19448 canvas.translate(-mScrollX, -mScrollY); 19449 19450 // Temporarily remove the dirty mask 19451 int flags = mPrivateFlags; 19452 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 19453 19454 // Fast path for layouts with no backgrounds 19455 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { 19456 dispatchDraw(canvas); 19457 drawAutofilledHighlight(canvas); 19458 if (mOverlay != null && !mOverlay.isEmpty()) { 19459 mOverlay.getOverlayView().draw(canvas); 19460 } 19461 } else { 19462 draw(canvas); 19463 } 19464 19465 mPrivateFlags = flags; 19466 canvas.restoreToCount(restoreCount); 19467 return canvasProvider.createBitmap(); 19468 } finally { 19469 if (oldCanvas != null) { 19470 attachInfo.mCanvas = oldCanvas; 19471 } 19472 } 19473 } 19474 19475 /** 19476 * Indicates whether this View is currently in edit mode. A View is usually 19477 * in edit mode when displayed within a developer tool. For instance, if 19478 * this View is being drawn by a visual user interface builder, this method 19479 * should return true. 19480 * 19481 * Subclasses should check the return value of this method to provide 19482 * different behaviors if their normal behavior might interfere with the 19483 * host environment. For instance: the class spawns a thread in its 19484 * constructor, the drawing code relies on device-specific features, etc. 19485 * 19486 * This method is usually checked in the drawing code of custom widgets. 19487 * 19488 * @return True if this View is in edit mode, false otherwise. 19489 */ 19490 public boolean isInEditMode() { 19491 return false; 19492 } 19493 19494 /** 19495 * If the View draws content inside its padding and enables fading edges, 19496 * it needs to support padding offsets. Padding offsets are added to the 19497 * fading edges to extend the length of the fade so that it covers pixels 19498 * drawn inside the padding. 19499 * 19500 * Subclasses of this class should override this method if they need 19501 * to draw content inside the padding. 19502 * 19503 * @return True if padding offset must be applied, false otherwise. 19504 * 19505 * @see #getLeftPaddingOffset() 19506 * @see #getRightPaddingOffset() 19507 * @see #getTopPaddingOffset() 19508 * @see #getBottomPaddingOffset() 19509 * 19510 * @since CURRENT 19511 */ 19512 protected boolean isPaddingOffsetRequired() { 19513 return false; 19514 } 19515 19516 /** 19517 * Amount by which to extend the left fading region. Called only when 19518 * {@link #isPaddingOffsetRequired()} returns true. 19519 * 19520 * @return The left padding offset in pixels. 19521 * 19522 * @see #isPaddingOffsetRequired() 19523 * 19524 * @since CURRENT 19525 */ 19526 protected int getLeftPaddingOffset() { 19527 return 0; 19528 } 19529 19530 /** 19531 * Amount by which to extend the right fading region. Called only when 19532 * {@link #isPaddingOffsetRequired()} returns true. 19533 * 19534 * @return The right padding offset in pixels. 19535 * 19536 * @see #isPaddingOffsetRequired() 19537 * 19538 * @since CURRENT 19539 */ 19540 protected int getRightPaddingOffset() { 19541 return 0; 19542 } 19543 19544 /** 19545 * Amount by which to extend the top fading region. Called only when 19546 * {@link #isPaddingOffsetRequired()} returns true. 19547 * 19548 * @return The top padding offset in pixels. 19549 * 19550 * @see #isPaddingOffsetRequired() 19551 * 19552 * @since CURRENT 19553 */ 19554 protected int getTopPaddingOffset() { 19555 return 0; 19556 } 19557 19558 /** 19559 * Amount by which to extend the bottom fading region. Called only when 19560 * {@link #isPaddingOffsetRequired()} returns true. 19561 * 19562 * @return The bottom padding offset in pixels. 19563 * 19564 * @see #isPaddingOffsetRequired() 19565 * 19566 * @since CURRENT 19567 */ 19568 protected int getBottomPaddingOffset() { 19569 return 0; 19570 } 19571 19572 /** 19573 * @hide 19574 * @param offsetRequired 19575 */ 19576 protected int getFadeTop(boolean offsetRequired) { 19577 int top = mPaddingTop; 19578 if (offsetRequired) top += getTopPaddingOffset(); 19579 return top; 19580 } 19581 19582 /** 19583 * @hide 19584 * @param offsetRequired 19585 */ 19586 protected int getFadeHeight(boolean offsetRequired) { 19587 int padding = mPaddingTop; 19588 if (offsetRequired) padding += getTopPaddingOffset(); 19589 return mBottom - mTop - mPaddingBottom - padding; 19590 } 19591 19592 /** 19593 * <p>Indicates whether this view is attached to a hardware accelerated 19594 * window or not.</p> 19595 * 19596 * <p>Even if this method returns true, it does not mean that every call 19597 * to {@link #draw(android.graphics.Canvas)} will be made with an hardware 19598 * accelerated {@link android.graphics.Canvas}. For instance, if this view 19599 * is drawn onto an offscreen {@link android.graphics.Bitmap} and its 19600 * window is hardware accelerated, 19601 * {@link android.graphics.Canvas#isHardwareAccelerated()} will likely 19602 * return false, and this method will return true.</p> 19603 * 19604 * @return True if the view is attached to a window and the window is 19605 * hardware accelerated; false in any other case. 19606 */ 19607 @ViewDebug.ExportedProperty(category = "drawing") 19608 public boolean isHardwareAccelerated() { 19609 return mAttachInfo != null && mAttachInfo.mHardwareAccelerated; 19610 } 19611 19612 /** 19613 * Sets a rectangular area on this view to which the view will be clipped 19614 * when it is drawn. Setting the value to null will remove the clip bounds 19615 * and the view will draw normally, using its full bounds. 19616 * 19617 * @param clipBounds The rectangular area, in the local coordinates of 19618 * this view, to which future drawing operations will be clipped. 19619 */ 19620 public void setClipBounds(Rect clipBounds) { 19621 if (clipBounds == mClipBounds 19622 || (clipBounds != null && clipBounds.equals(mClipBounds))) { 19623 return; 19624 } 19625 if (clipBounds != null) { 19626 if (mClipBounds == null) { 19627 mClipBounds = new Rect(clipBounds); 19628 } else { 19629 mClipBounds.set(clipBounds); 19630 } 19631 } else { 19632 mClipBounds = null; 19633 } 19634 mRenderNode.setClipBounds(mClipBounds); 19635 invalidateViewProperty(false, false); 19636 } 19637 19638 /** 19639 * Returns a copy of the current {@link #setClipBounds(Rect) clipBounds}. 19640 * 19641 * @return A copy of the current clip bounds if clip bounds are set, 19642 * otherwise null. 19643 */ 19644 public Rect getClipBounds() { 19645 return (mClipBounds != null) ? new Rect(mClipBounds) : null; 19646 } 19647 19648 19649 /** 19650 * Populates an output rectangle with the clip bounds of the view, 19651 * returning {@code true} if successful or {@code false} if the view's 19652 * clip bounds are {@code null}. 19653 * 19654 * @param outRect rectangle in which to place the clip bounds of the view 19655 * @return {@code true} if successful or {@code false} if the view's 19656 * clip bounds are {@code null} 19657 */ 19658 public boolean getClipBounds(Rect outRect) { 19659 if (mClipBounds != null) { 19660 outRect.set(mClipBounds); 19661 return true; 19662 } 19663 return false; 19664 } 19665 19666 /** 19667 * Utility function, called by draw(canvas, parent, drawingTime) to handle the less common 19668 * case of an active Animation being run on the view. 19669 */ 19670 private boolean applyLegacyAnimation(ViewGroup parent, long drawingTime, 19671 Animation a, boolean scalingRequired) { 19672 Transformation invalidationTransform; 19673 final int flags = parent.mGroupFlags; 19674 final boolean initialized = a.isInitialized(); 19675 if (!initialized) { 19676 a.initialize(mRight - mLeft, mBottom - mTop, parent.getWidth(), parent.getHeight()); 19677 a.initializeInvalidateRegion(0, 0, mRight - mLeft, mBottom - mTop); 19678 if (mAttachInfo != null) a.setListenerHandler(mAttachInfo.mHandler); 19679 onAnimationStart(); 19680 } 19681 19682 final Transformation t = parent.getChildTransformation(); 19683 boolean more = a.getTransformation(drawingTime, t, 1f); 19684 if (scalingRequired && mAttachInfo.mApplicationScale != 1f) { 19685 if (parent.mInvalidationTransformation == null) { 19686 parent.mInvalidationTransformation = new Transformation(); 19687 } 19688 invalidationTransform = parent.mInvalidationTransformation; 19689 a.getTransformation(drawingTime, invalidationTransform, 1f); 19690 } else { 19691 invalidationTransform = t; 19692 } 19693 19694 if (more) { 19695 if (!a.willChangeBounds()) { 19696 if ((flags & (ViewGroup.FLAG_OPTIMIZE_INVALIDATE | ViewGroup.FLAG_ANIMATION_DONE)) == 19697 ViewGroup.FLAG_OPTIMIZE_INVALIDATE) { 19698 parent.mGroupFlags |= ViewGroup.FLAG_INVALIDATE_REQUIRED; 19699 } else if ((flags & ViewGroup.FLAG_INVALIDATE_REQUIRED) == 0) { 19700 // The child need to draw an animation, potentially offscreen, so 19701 // make sure we do not cancel invalidate requests 19702 parent.mPrivateFlags |= PFLAG_DRAW_ANIMATION; 19703 parent.invalidate(mLeft, mTop, mRight, mBottom); 19704 } 19705 } else { 19706 if (parent.mInvalidateRegion == null) { 19707 parent.mInvalidateRegion = new RectF(); 19708 } 19709 final RectF region = parent.mInvalidateRegion; 19710 a.getInvalidateRegion(0, 0, mRight - mLeft, mBottom - mTop, region, 19711 invalidationTransform); 19712 19713 // The child need to draw an animation, potentially offscreen, so 19714 // make sure we do not cancel invalidate requests 19715 parent.mPrivateFlags |= PFLAG_DRAW_ANIMATION; 19716 19717 final int left = mLeft + (int) region.left; 19718 final int top = mTop + (int) region.top; 19719 parent.invalidate(left, top, left + (int) (region.width() + .5f), 19720 top + (int) (region.height() + .5f)); 19721 } 19722 } 19723 return more; 19724 } 19725 19726 /** 19727 * This method is called by getDisplayList() when a display list is recorded for a View. 19728 * It pushes any properties to the RenderNode that aren't managed by the RenderNode. 19729 */ 19730 void setDisplayListProperties(RenderNode renderNode) { 19731 if (renderNode != null) { 19732 renderNode.setHasOverlappingRendering(getHasOverlappingRendering()); 19733 renderNode.setClipToBounds(mParent instanceof ViewGroup 19734 && ((ViewGroup) mParent).getClipChildren()); 19735 19736 float alpha = 1; 19737 if (mParent instanceof ViewGroup && (((ViewGroup) mParent).mGroupFlags & 19738 ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) != 0) { 19739 ViewGroup parentVG = (ViewGroup) mParent; 19740 final Transformation t = parentVG.getChildTransformation(); 19741 if (parentVG.getChildStaticTransformation(this, t)) { 19742 final int transformType = t.getTransformationType(); 19743 if (transformType != Transformation.TYPE_IDENTITY) { 19744 if ((transformType & Transformation.TYPE_ALPHA) != 0) { 19745 alpha = t.getAlpha(); 19746 } 19747 if ((transformType & Transformation.TYPE_MATRIX) != 0) { 19748 renderNode.setStaticMatrix(t.getMatrix()); 19749 } 19750 } 19751 } 19752 } 19753 if (mTransformationInfo != null) { 19754 alpha *= getFinalAlpha(); 19755 if (alpha < 1) { 19756 final int multipliedAlpha = (int) (255 * alpha); 19757 if (onSetAlpha(multipliedAlpha)) { 19758 alpha = 1; 19759 } 19760 } 19761 renderNode.setAlpha(alpha); 19762 } else if (alpha < 1) { 19763 renderNode.setAlpha(alpha); 19764 } 19765 } 19766 } 19767 19768 /** 19769 * This method is called by ViewGroup.drawChild() to have each child view draw itself. 19770 * 19771 * This is where the View specializes rendering behavior based on layer type, 19772 * and hardware acceleration. 19773 */ 19774 boolean draw(Canvas canvas, ViewGroup parent, long drawingTime) { 19775 final boolean hardwareAcceleratedCanvas = canvas.isHardwareAccelerated(); 19776 /* If an attached view draws to a HW canvas, it may use its RenderNode + DisplayList. 19777 * 19778 * If a view is dettached, its DisplayList shouldn't exist. If the canvas isn't 19779 * HW accelerated, it can't handle drawing RenderNodes. 19780 */ 19781 boolean drawingWithRenderNode = mAttachInfo != null 19782 && mAttachInfo.mHardwareAccelerated 19783 && hardwareAcceleratedCanvas; 19784 19785 boolean more = false; 19786 final boolean childHasIdentityMatrix = hasIdentityMatrix(); 19787 final int parentFlags = parent.mGroupFlags; 19788 19789 if ((parentFlags & ViewGroup.FLAG_CLEAR_TRANSFORMATION) != 0) { 19790 parent.getChildTransformation().clear(); 19791 parent.mGroupFlags &= ~ViewGroup.FLAG_CLEAR_TRANSFORMATION; 19792 } 19793 19794 Transformation transformToApply = null; 19795 boolean concatMatrix = false; 19796 final boolean scalingRequired = mAttachInfo != null && mAttachInfo.mScalingRequired; 19797 final Animation a = getAnimation(); 19798 if (a != null) { 19799 more = applyLegacyAnimation(parent, drawingTime, a, scalingRequired); 19800 concatMatrix = a.willChangeTransformationMatrix(); 19801 if (concatMatrix) { 19802 mPrivateFlags3 |= PFLAG3_VIEW_IS_ANIMATING_TRANSFORM; 19803 } 19804 transformToApply = parent.getChildTransformation(); 19805 } else { 19806 if ((mPrivateFlags3 & PFLAG3_VIEW_IS_ANIMATING_TRANSFORM) != 0) { 19807 // No longer animating: clear out old animation matrix 19808 mRenderNode.setAnimationMatrix(null); 19809 mPrivateFlags3 &= ~PFLAG3_VIEW_IS_ANIMATING_TRANSFORM; 19810 } 19811 if (!drawingWithRenderNode 19812 && (parentFlags & ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) != 0) { 19813 final Transformation t = parent.getChildTransformation(); 19814 final boolean hasTransform = parent.getChildStaticTransformation(this, t); 19815 if (hasTransform) { 19816 final int transformType = t.getTransformationType(); 19817 transformToApply = transformType != Transformation.TYPE_IDENTITY ? t : null; 19818 concatMatrix = (transformType & Transformation.TYPE_MATRIX) != 0; 19819 } 19820 } 19821 } 19822 19823 concatMatrix |= !childHasIdentityMatrix; 19824 19825 // Sets the flag as early as possible to allow draw() implementations 19826 // to call invalidate() successfully when doing animations 19827 mPrivateFlags |= PFLAG_DRAWN; 19828 19829 if (!concatMatrix && 19830 (parentFlags & (ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS | 19831 ViewGroup.FLAG_CLIP_CHILDREN)) == ViewGroup.FLAG_CLIP_CHILDREN && 19832 canvas.quickReject(mLeft, mTop, mRight, mBottom, Canvas.EdgeType.BW) && 19833 (mPrivateFlags & PFLAG_DRAW_ANIMATION) == 0) { 19834 mPrivateFlags2 |= PFLAG2_VIEW_QUICK_REJECTED; 19835 return more; 19836 } 19837 mPrivateFlags2 &= ~PFLAG2_VIEW_QUICK_REJECTED; 19838 19839 if (hardwareAcceleratedCanvas) { 19840 // Clear INVALIDATED flag to allow invalidation to occur during rendering, but 19841 // retain the flag's value temporarily in the mRecreateDisplayList flag 19842 mRecreateDisplayList = (mPrivateFlags & PFLAG_INVALIDATED) != 0; 19843 mPrivateFlags &= ~PFLAG_INVALIDATED; 19844 } 19845 19846 RenderNode renderNode = null; 19847 Bitmap cache = null; 19848 int layerType = getLayerType(); // TODO: signify cache state with just 'cache' local 19849 if (layerType == LAYER_TYPE_SOFTWARE || !drawingWithRenderNode) { 19850 if (layerType != LAYER_TYPE_NONE) { 19851 // If not drawing with RenderNode, treat HW layers as SW 19852 layerType = LAYER_TYPE_SOFTWARE; 19853 buildDrawingCache(true); 19854 } 19855 cache = getDrawingCache(true); 19856 } 19857 19858 if (drawingWithRenderNode) { 19859 // Delay getting the display list until animation-driven alpha values are 19860 // set up and possibly passed on to the view 19861 renderNode = updateDisplayListIfDirty(); 19862 if (!renderNode.isValid()) { 19863 // Uncommon, but possible. If a view is removed from the hierarchy during the call 19864 // to getDisplayList(), the display list will be marked invalid and we should not 19865 // try to use it again. 19866 renderNode = null; 19867 drawingWithRenderNode = false; 19868 } 19869 } 19870 19871 int sx = 0; 19872 int sy = 0; 19873 if (!drawingWithRenderNode) { 19874 computeScroll(); 19875 sx = mScrollX; 19876 sy = mScrollY; 19877 } 19878 19879 final boolean drawingWithDrawingCache = cache != null && !drawingWithRenderNode; 19880 final boolean offsetForScroll = cache == null && !drawingWithRenderNode; 19881 19882 int restoreTo = -1; 19883 if (!drawingWithRenderNode || transformToApply != null) { 19884 restoreTo = canvas.save(); 19885 } 19886 if (offsetForScroll) { 19887 canvas.translate(mLeft - sx, mTop - sy); 19888 } else { 19889 if (!drawingWithRenderNode) { 19890 canvas.translate(mLeft, mTop); 19891 } 19892 if (scalingRequired) { 19893 if (drawingWithRenderNode) { 19894 // TODO: Might not need this if we put everything inside the DL 19895 restoreTo = canvas.save(); 19896 } 19897 // mAttachInfo cannot be null, otherwise scalingRequired == false 19898 final float scale = 1.0f / mAttachInfo.mApplicationScale; 19899 canvas.scale(scale, scale); 19900 } 19901 } 19902 19903 float alpha = drawingWithRenderNode ? 1 : (getAlpha() * getTransitionAlpha()); 19904 if (transformToApply != null 19905 || alpha < 1 19906 || !hasIdentityMatrix() 19907 || (mPrivateFlags3 & PFLAG3_VIEW_IS_ANIMATING_ALPHA) != 0) { 19908 if (transformToApply != null || !childHasIdentityMatrix) { 19909 int transX = 0; 19910 int transY = 0; 19911 19912 if (offsetForScroll) { 19913 transX = -sx; 19914 transY = -sy; 19915 } 19916 19917 if (transformToApply != null) { 19918 if (concatMatrix) { 19919 if (drawingWithRenderNode) { 19920 renderNode.setAnimationMatrix(transformToApply.getMatrix()); 19921 } else { 19922 // Undo the scroll translation, apply the transformation matrix, 19923 // then redo the scroll translate to get the correct result. 19924 canvas.translate(-transX, -transY); 19925 canvas.concat(transformToApply.getMatrix()); 19926 canvas.translate(transX, transY); 19927 } 19928 parent.mGroupFlags |= ViewGroup.FLAG_CLEAR_TRANSFORMATION; 19929 } 19930 19931 float transformAlpha = transformToApply.getAlpha(); 19932 if (transformAlpha < 1) { 19933 alpha *= transformAlpha; 19934 parent.mGroupFlags |= ViewGroup.FLAG_CLEAR_TRANSFORMATION; 19935 } 19936 } 19937 19938 if (!childHasIdentityMatrix && !drawingWithRenderNode) { 19939 canvas.translate(-transX, -transY); 19940 canvas.concat(getMatrix()); 19941 canvas.translate(transX, transY); 19942 } 19943 } 19944 19945 // Deal with alpha if it is or used to be <1 19946 if (alpha < 1 || (mPrivateFlags3 & PFLAG3_VIEW_IS_ANIMATING_ALPHA) != 0) { 19947 if (alpha < 1) { 19948 mPrivateFlags3 |= PFLAG3_VIEW_IS_ANIMATING_ALPHA; 19949 } else { 19950 mPrivateFlags3 &= ~PFLAG3_VIEW_IS_ANIMATING_ALPHA; 19951 } 19952 parent.mGroupFlags |= ViewGroup.FLAG_CLEAR_TRANSFORMATION; 19953 if (!drawingWithDrawingCache) { 19954 final int multipliedAlpha = (int) (255 * alpha); 19955 if (!onSetAlpha(multipliedAlpha)) { 19956 if (drawingWithRenderNode) { 19957 renderNode.setAlpha(alpha * getAlpha() * getTransitionAlpha()); 19958 } else if (layerType == LAYER_TYPE_NONE) { 19959 canvas.saveLayerAlpha(sx, sy, sx + getWidth(), sy + getHeight(), 19960 multipliedAlpha); 19961 } 19962 } else { 19963 // Alpha is handled by the child directly, clobber the layer's alpha 19964 mPrivateFlags |= PFLAG_ALPHA_SET; 19965 } 19966 } 19967 } 19968 } else if ((mPrivateFlags & PFLAG_ALPHA_SET) == PFLAG_ALPHA_SET) { 19969 onSetAlpha(255); 19970 mPrivateFlags &= ~PFLAG_ALPHA_SET; 19971 } 19972 19973 if (!drawingWithRenderNode) { 19974 // apply clips directly, since RenderNode won't do it for this draw 19975 if ((parentFlags & ViewGroup.FLAG_CLIP_CHILDREN) != 0 && cache == null) { 19976 if (offsetForScroll) { 19977 canvas.clipRect(sx, sy, sx + getWidth(), sy + getHeight()); 19978 } else { 19979 if (!scalingRequired || cache == null) { 19980 canvas.clipRect(0, 0, getWidth(), getHeight()); 19981 } else { 19982 canvas.clipRect(0, 0, cache.getWidth(), cache.getHeight()); 19983 } 19984 } 19985 } 19986 19987 if (mClipBounds != null) { 19988 // clip bounds ignore scroll 19989 canvas.clipRect(mClipBounds); 19990 } 19991 } 19992 19993 if (!drawingWithDrawingCache) { 19994 if (drawingWithRenderNode) { 19995 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 19996 ((DisplayListCanvas) canvas).drawRenderNode(renderNode); 19997 } else { 19998 // Fast path for layouts with no backgrounds 19999 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { 20000 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 20001 dispatchDraw(canvas); 20002 } else { 20003 draw(canvas); 20004 } 20005 } 20006 } else if (cache != null) { 20007 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 20008 if (layerType == LAYER_TYPE_NONE || mLayerPaint == null) { 20009 // no layer paint, use temporary paint to draw bitmap 20010 Paint cachePaint = parent.mCachePaint; 20011 if (cachePaint == null) { 20012 cachePaint = new Paint(); 20013 cachePaint.setDither(false); 20014 parent.mCachePaint = cachePaint; 20015 } 20016 cachePaint.setAlpha((int) (alpha * 255)); 20017 canvas.drawBitmap(cache, 0.0f, 0.0f, cachePaint); 20018 } else { 20019 // use layer paint to draw the bitmap, merging the two alphas, but also restore 20020 int layerPaintAlpha = mLayerPaint.getAlpha(); 20021 if (alpha < 1) { 20022 mLayerPaint.setAlpha((int) (alpha * layerPaintAlpha)); 20023 } 20024 canvas.drawBitmap(cache, 0.0f, 0.0f, mLayerPaint); 20025 if (alpha < 1) { 20026 mLayerPaint.setAlpha(layerPaintAlpha); 20027 } 20028 } 20029 } 20030 20031 if (restoreTo >= 0) { 20032 canvas.restoreToCount(restoreTo); 20033 } 20034 20035 if (a != null && !more) { 20036 if (!hardwareAcceleratedCanvas && !a.getFillAfter()) { 20037 onSetAlpha(255); 20038 } 20039 parent.finishAnimatingView(this, a); 20040 } 20041 20042 if (more && hardwareAcceleratedCanvas) { 20043 if (a.hasAlpha() && (mPrivateFlags & PFLAG_ALPHA_SET) == PFLAG_ALPHA_SET) { 20044 // alpha animations should cause the child to recreate its display list 20045 invalidate(true); 20046 } 20047 } 20048 20049 mRecreateDisplayList = false; 20050 20051 return more; 20052 } 20053 20054 static Paint getDebugPaint() { 20055 if (sDebugPaint == null) { 20056 sDebugPaint = new Paint(); 20057 sDebugPaint.setAntiAlias(false); 20058 } 20059 return sDebugPaint; 20060 } 20061 20062 final int dipsToPixels(int dips) { 20063 float scale = getContext().getResources().getDisplayMetrics().density; 20064 return (int) (dips * scale + 0.5f); 20065 } 20066 20067 final private void debugDrawFocus(Canvas canvas) { 20068 if (isFocused()) { 20069 final int cornerSquareSize = dipsToPixels(DEBUG_CORNERS_SIZE_DIP); 20070 final int l = mScrollX; 20071 final int r = l + mRight - mLeft; 20072 final int t = mScrollY; 20073 final int b = t + mBottom - mTop; 20074 20075 final Paint paint = getDebugPaint(); 20076 paint.setColor(DEBUG_CORNERS_COLOR); 20077 20078 // Draw squares in corners. 20079 paint.setStyle(Paint.Style.FILL); 20080 canvas.drawRect(l, t, l + cornerSquareSize, t + cornerSquareSize, paint); 20081 canvas.drawRect(r - cornerSquareSize, t, r, t + cornerSquareSize, paint); 20082 canvas.drawRect(l, b - cornerSquareSize, l + cornerSquareSize, b, paint); 20083 canvas.drawRect(r - cornerSquareSize, b - cornerSquareSize, r, b, paint); 20084 20085 // Draw big X across the view. 20086 paint.setStyle(Paint.Style.STROKE); 20087 canvas.drawLine(l, t, r, b, paint); 20088 canvas.drawLine(l, b, r, t, paint); 20089 } 20090 } 20091 20092 /** 20093 * Manually render this view (and all of its children) to the given Canvas. 20094 * The view must have already done a full layout before this function is 20095 * called. When implementing a view, implement 20096 * {@link #onDraw(android.graphics.Canvas)} instead of overriding this method. 20097 * If you do need to override this method, call the superclass version. 20098 * 20099 * @param canvas The Canvas to which the View is rendered. 20100 */ 20101 @CallSuper 20102 public void draw(Canvas canvas) { 20103 final int privateFlags = mPrivateFlags; 20104 final boolean dirtyOpaque = (privateFlags & PFLAG_DIRTY_MASK) == PFLAG_DIRTY_OPAQUE && 20105 (mAttachInfo == null || !mAttachInfo.mIgnoreDirtyState); 20106 mPrivateFlags = (privateFlags & ~PFLAG_DIRTY_MASK) | PFLAG_DRAWN; 20107 20108 /* 20109 * Draw traversal performs several drawing steps which must be executed 20110 * in the appropriate order: 20111 * 20112 * 1. Draw the background 20113 * 2. If necessary, save the canvas' layers to prepare for fading 20114 * 3. Draw view's content 20115 * 4. Draw children 20116 * 5. If necessary, draw the fading edges and restore layers 20117 * 6. Draw decorations (scrollbars for instance) 20118 */ 20119 20120 // Step 1, draw the background, if needed 20121 int saveCount; 20122 20123 if (!dirtyOpaque) { 20124 drawBackground(canvas); 20125 } 20126 20127 // skip step 2 & 5 if possible (common case) 20128 final int viewFlags = mViewFlags; 20129 boolean horizontalEdges = (viewFlags & FADING_EDGE_HORIZONTAL) != 0; 20130 boolean verticalEdges = (viewFlags & FADING_EDGE_VERTICAL) != 0; 20131 if (!verticalEdges && !horizontalEdges) { 20132 // Step 3, draw the content 20133 if (!dirtyOpaque) onDraw(canvas); 20134 20135 // Step 4, draw the children 20136 dispatchDraw(canvas); 20137 20138 drawAutofilledHighlight(canvas); 20139 20140 // Overlay is part of the content and draws beneath Foreground 20141 if (mOverlay != null && !mOverlay.isEmpty()) { 20142 mOverlay.getOverlayView().dispatchDraw(canvas); 20143 } 20144 20145 // Step 6, draw decorations (foreground, scrollbars) 20146 onDrawForeground(canvas); 20147 20148 // Step 7, draw the default focus highlight 20149 drawDefaultFocusHighlight(canvas); 20150 20151 if (debugDraw()) { 20152 debugDrawFocus(canvas); 20153 } 20154 20155 // we're done... 20156 return; 20157 } 20158 20159 /* 20160 * Here we do the full fledged routine... 20161 * (this is an uncommon case where speed matters less, 20162 * this is why we repeat some of the tests that have been 20163 * done above) 20164 */ 20165 20166 boolean drawTop = false; 20167 boolean drawBottom = false; 20168 boolean drawLeft = false; 20169 boolean drawRight = false; 20170 20171 float topFadeStrength = 0.0f; 20172 float bottomFadeStrength = 0.0f; 20173 float leftFadeStrength = 0.0f; 20174 float rightFadeStrength = 0.0f; 20175 20176 // Step 2, save the canvas' layers 20177 int paddingLeft = mPaddingLeft; 20178 20179 final boolean offsetRequired = isPaddingOffsetRequired(); 20180 if (offsetRequired) { 20181 paddingLeft += getLeftPaddingOffset(); 20182 } 20183 20184 int left = mScrollX + paddingLeft; 20185 int right = left + mRight - mLeft - mPaddingRight - paddingLeft; 20186 int top = mScrollY + getFadeTop(offsetRequired); 20187 int bottom = top + getFadeHeight(offsetRequired); 20188 20189 if (offsetRequired) { 20190 right += getRightPaddingOffset(); 20191 bottom += getBottomPaddingOffset(); 20192 } 20193 20194 final ScrollabilityCache scrollabilityCache = mScrollCache; 20195 final float fadeHeight = scrollabilityCache.fadingEdgeLength; 20196 int length = (int) fadeHeight; 20197 20198 // clip the fade length if top and bottom fades overlap 20199 // overlapping fades produce odd-looking artifacts 20200 if (verticalEdges && (top + length > bottom - length)) { 20201 length = (bottom - top) / 2; 20202 } 20203 20204 // also clip horizontal fades if necessary 20205 if (horizontalEdges && (left + length > right - length)) { 20206 length = (right - left) / 2; 20207 } 20208 20209 if (verticalEdges) { 20210 topFadeStrength = Math.max(0.0f, Math.min(1.0f, getTopFadingEdgeStrength())); 20211 drawTop = topFadeStrength * fadeHeight > 1.0f; 20212 bottomFadeStrength = Math.max(0.0f, Math.min(1.0f, getBottomFadingEdgeStrength())); 20213 drawBottom = bottomFadeStrength * fadeHeight > 1.0f; 20214 } 20215 20216 if (horizontalEdges) { 20217 leftFadeStrength = Math.max(0.0f, Math.min(1.0f, getLeftFadingEdgeStrength())); 20218 drawLeft = leftFadeStrength * fadeHeight > 1.0f; 20219 rightFadeStrength = Math.max(0.0f, Math.min(1.0f, getRightFadingEdgeStrength())); 20220 drawRight = rightFadeStrength * fadeHeight > 1.0f; 20221 } 20222 20223 saveCount = canvas.getSaveCount(); 20224 20225 int solidColor = getSolidColor(); 20226 if (solidColor == 0) { 20227 final int flags = Canvas.HAS_ALPHA_LAYER_SAVE_FLAG; 20228 20229 if (drawTop) { 20230 canvas.saveLayer(left, top, right, top + length, null, flags); 20231 } 20232 20233 if (drawBottom) { 20234 canvas.saveLayer(left, bottom - length, right, bottom, null, flags); 20235 } 20236 20237 if (drawLeft) { 20238 canvas.saveLayer(left, top, left + length, bottom, null, flags); 20239 } 20240 20241 if (drawRight) { 20242 canvas.saveLayer(right - length, top, right, bottom, null, flags); 20243 } 20244 } else { 20245 scrollabilityCache.setFadeColor(solidColor); 20246 } 20247 20248 // Step 3, draw the content 20249 if (!dirtyOpaque) onDraw(canvas); 20250 20251 // Step 4, draw the children 20252 dispatchDraw(canvas); 20253 20254 // Step 5, draw the fade effect and restore layers 20255 final Paint p = scrollabilityCache.paint; 20256 final Matrix matrix = scrollabilityCache.matrix; 20257 final Shader fade = scrollabilityCache.shader; 20258 20259 if (drawTop) { 20260 matrix.setScale(1, fadeHeight * topFadeStrength); 20261 matrix.postTranslate(left, top); 20262 fade.setLocalMatrix(matrix); 20263 p.setShader(fade); 20264 canvas.drawRect(left, top, right, top + length, p); 20265 } 20266 20267 if (drawBottom) { 20268 matrix.setScale(1, fadeHeight * bottomFadeStrength); 20269 matrix.postRotate(180); 20270 matrix.postTranslate(left, bottom); 20271 fade.setLocalMatrix(matrix); 20272 p.setShader(fade); 20273 canvas.drawRect(left, bottom - length, right, bottom, p); 20274 } 20275 20276 if (drawLeft) { 20277 matrix.setScale(1, fadeHeight * leftFadeStrength); 20278 matrix.postRotate(-90); 20279 matrix.postTranslate(left, top); 20280 fade.setLocalMatrix(matrix); 20281 p.setShader(fade); 20282 canvas.drawRect(left, top, left + length, bottom, p); 20283 } 20284 20285 if (drawRight) { 20286 matrix.setScale(1, fadeHeight * rightFadeStrength); 20287 matrix.postRotate(90); 20288 matrix.postTranslate(right, top); 20289 fade.setLocalMatrix(matrix); 20290 p.setShader(fade); 20291 canvas.drawRect(right - length, top, right, bottom, p); 20292 } 20293 20294 canvas.restoreToCount(saveCount); 20295 20296 drawAutofilledHighlight(canvas); 20297 20298 // Overlay is part of the content and draws beneath Foreground 20299 if (mOverlay != null && !mOverlay.isEmpty()) { 20300 mOverlay.getOverlayView().dispatchDraw(canvas); 20301 } 20302 20303 // Step 6, draw decorations (foreground, scrollbars) 20304 onDrawForeground(canvas); 20305 20306 if (debugDraw()) { 20307 debugDrawFocus(canvas); 20308 } 20309 } 20310 20311 /** 20312 * Draws the background onto the specified canvas. 20313 * 20314 * @param canvas Canvas on which to draw the background 20315 */ 20316 private void drawBackground(Canvas canvas) { 20317 final Drawable background = mBackground; 20318 if (background == null) { 20319 return; 20320 } 20321 20322 setBackgroundBounds(); 20323 20324 // Attempt to use a display list if requested. 20325 if (canvas.isHardwareAccelerated() && mAttachInfo != null 20326 && mAttachInfo.mThreadedRenderer != null) { 20327 mBackgroundRenderNode = getDrawableRenderNode(background, mBackgroundRenderNode); 20328 20329 final RenderNode renderNode = mBackgroundRenderNode; 20330 if (renderNode != null && renderNode.isValid()) { 20331 setBackgroundRenderNodeProperties(renderNode); 20332 ((DisplayListCanvas) canvas).drawRenderNode(renderNode); 20333 return; 20334 } 20335 } 20336 20337 final int scrollX = mScrollX; 20338 final int scrollY = mScrollY; 20339 if ((scrollX | scrollY) == 0) { 20340 background.draw(canvas); 20341 } else { 20342 canvas.translate(scrollX, scrollY); 20343 background.draw(canvas); 20344 canvas.translate(-scrollX, -scrollY); 20345 } 20346 } 20347 20348 /** 20349 * Sets the correct background bounds and rebuilds the outline, if needed. 20350 * <p/> 20351 * This is called by LayoutLib. 20352 */ 20353 void setBackgroundBounds() { 20354 if (mBackgroundSizeChanged && mBackground != null) { 20355 mBackground.setBounds(0, 0, mRight - mLeft, mBottom - mTop); 20356 mBackgroundSizeChanged = false; 20357 rebuildOutline(); 20358 } 20359 } 20360 20361 private void setBackgroundRenderNodeProperties(RenderNode renderNode) { 20362 renderNode.setTranslationX(mScrollX); 20363 renderNode.setTranslationY(mScrollY); 20364 } 20365 20366 /** 20367 * Creates a new display list or updates the existing display list for the 20368 * specified Drawable. 20369 * 20370 * @param drawable Drawable for which to create a display list 20371 * @param renderNode Existing RenderNode, or {@code null} 20372 * @return A valid display list for the specified drawable 20373 */ 20374 private RenderNode getDrawableRenderNode(Drawable drawable, RenderNode renderNode) { 20375 if (renderNode == null) { 20376 renderNode = RenderNode.create(drawable.getClass().getName(), this); 20377 } 20378 20379 final Rect bounds = drawable.getBounds(); 20380 final int width = bounds.width(); 20381 final int height = bounds.height(); 20382 final DisplayListCanvas canvas = renderNode.start(width, height); 20383 20384 // Reverse left/top translation done by drawable canvas, which will 20385 // instead be applied by rendernode's LTRB bounds below. This way, the 20386 // drawable's bounds match with its rendernode bounds and its content 20387 // will lie within those bounds in the rendernode tree. 20388 canvas.translate(-bounds.left, -bounds.top); 20389 20390 try { 20391 drawable.draw(canvas); 20392 } finally { 20393 renderNode.end(canvas); 20394 } 20395 20396 // Set up drawable properties that are view-independent. 20397 renderNode.setLeftTopRightBottom(bounds.left, bounds.top, bounds.right, bounds.bottom); 20398 renderNode.setProjectBackwards(drawable.isProjected()); 20399 renderNode.setProjectionReceiver(true); 20400 renderNode.setClipToBounds(false); 20401 return renderNode; 20402 } 20403 20404 /** 20405 * Returns the overlay for this view, creating it if it does not yet exist. 20406 * Adding drawables to the overlay will cause them to be displayed whenever 20407 * the view itself is redrawn. Objects in the overlay should be actively 20408 * managed: remove them when they should not be displayed anymore. The 20409 * overlay will always have the same size as its host view. 20410 * 20411 * <p>Note: Overlays do not currently work correctly with {@link 20412 * SurfaceView} or {@link TextureView}; contents in overlays for these 20413 * types of views may not display correctly.</p> 20414 * 20415 * @return The ViewOverlay object for this view. 20416 * @see ViewOverlay 20417 */ 20418 public ViewOverlay getOverlay() { 20419 if (mOverlay == null) { 20420 mOverlay = new ViewOverlay(mContext, this); 20421 } 20422 return mOverlay; 20423 } 20424 20425 /** 20426 * Override this if your view is known to always be drawn on top of a solid color background, 20427 * and needs to draw fading edges. Returning a non-zero color enables the view system to 20428 * optimize the drawing of the fading edges. If you do return a non-zero color, the alpha 20429 * should be set to 0xFF. 20430 * 20431 * @see #setVerticalFadingEdgeEnabled(boolean) 20432 * @see #setHorizontalFadingEdgeEnabled(boolean) 20433 * 20434 * @return The known solid color background for this view, or 0 if the color may vary 20435 */ 20436 @ViewDebug.ExportedProperty(category = "drawing") 20437 @ColorInt 20438 public int getSolidColor() { 20439 return 0; 20440 } 20441 20442 /** 20443 * Build a human readable string representation of the specified view flags. 20444 * 20445 * @param flags the view flags to convert to a string 20446 * @return a String representing the supplied flags 20447 */ 20448 private static String printFlags(int flags) { 20449 String output = ""; 20450 int numFlags = 0; 20451 if ((flags & FOCUSABLE) == FOCUSABLE) { 20452 output += "TAKES_FOCUS"; 20453 numFlags++; 20454 } 20455 20456 switch (flags & VISIBILITY_MASK) { 20457 case INVISIBLE: 20458 if (numFlags > 0) { 20459 output += " "; 20460 } 20461 output += "INVISIBLE"; 20462 // USELESS HERE numFlags++; 20463 break; 20464 case GONE: 20465 if (numFlags > 0) { 20466 output += " "; 20467 } 20468 output += "GONE"; 20469 // USELESS HERE numFlags++; 20470 break; 20471 default: 20472 break; 20473 } 20474 return output; 20475 } 20476 20477 /** 20478 * Build a human readable string representation of the specified private 20479 * view flags. 20480 * 20481 * @param privateFlags the private view flags to convert to a string 20482 * @return a String representing the supplied flags 20483 */ 20484 private static String printPrivateFlags(int privateFlags) { 20485 String output = ""; 20486 int numFlags = 0; 20487 20488 if ((privateFlags & PFLAG_WANTS_FOCUS) == PFLAG_WANTS_FOCUS) { 20489 output += "WANTS_FOCUS"; 20490 numFlags++; 20491 } 20492 20493 if ((privateFlags & PFLAG_FOCUSED) == PFLAG_FOCUSED) { 20494 if (numFlags > 0) { 20495 output += " "; 20496 } 20497 output += "FOCUSED"; 20498 numFlags++; 20499 } 20500 20501 if ((privateFlags & PFLAG_SELECTED) == PFLAG_SELECTED) { 20502 if (numFlags > 0) { 20503 output += " "; 20504 } 20505 output += "SELECTED"; 20506 numFlags++; 20507 } 20508 20509 if ((privateFlags & PFLAG_IS_ROOT_NAMESPACE) == PFLAG_IS_ROOT_NAMESPACE) { 20510 if (numFlags > 0) { 20511 output += " "; 20512 } 20513 output += "IS_ROOT_NAMESPACE"; 20514 numFlags++; 20515 } 20516 20517 if ((privateFlags & PFLAG_HAS_BOUNDS) == PFLAG_HAS_BOUNDS) { 20518 if (numFlags > 0) { 20519 output += " "; 20520 } 20521 output += "HAS_BOUNDS"; 20522 numFlags++; 20523 } 20524 20525 if ((privateFlags & PFLAG_DRAWN) == PFLAG_DRAWN) { 20526 if (numFlags > 0) { 20527 output += " "; 20528 } 20529 output += "DRAWN"; 20530 // USELESS HERE numFlags++; 20531 } 20532 return output; 20533 } 20534 20535 /** 20536 * <p>Indicates whether or not this view's layout will be requested during 20537 * the next hierarchy layout pass.</p> 20538 * 20539 * @return true if the layout will be forced during next layout pass 20540 */ 20541 public boolean isLayoutRequested() { 20542 return (mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT; 20543 } 20544 20545 /** 20546 * Return true if o is a ViewGroup that is laying out using optical bounds. 20547 * @hide 20548 */ 20549 public static boolean isLayoutModeOptical(Object o) { 20550 return o instanceof ViewGroup && ((ViewGroup) o).isLayoutModeOptical(); 20551 } 20552 20553 private boolean setOpticalFrame(int left, int top, int right, int bottom) { 20554 Insets parentInsets = mParent instanceof View ? 20555 ((View) mParent).getOpticalInsets() : Insets.NONE; 20556 Insets childInsets = getOpticalInsets(); 20557 return setFrame( 20558 left + parentInsets.left - childInsets.left, 20559 top + parentInsets.top - childInsets.top, 20560 right + parentInsets.left + childInsets.right, 20561 bottom + parentInsets.top + childInsets.bottom); 20562 } 20563 20564 /** 20565 * Assign a size and position to a view and all of its 20566 * descendants 20567 * 20568 * <p>This is the second phase of the layout mechanism. 20569 * (The first is measuring). In this phase, each parent calls 20570 * layout on all of its children to position them. 20571 * This is typically done using the child measurements 20572 * that were stored in the measure pass().</p> 20573 * 20574 * <p>Derived classes should not override this method. 20575 * Derived classes with children should override 20576 * onLayout. In that method, they should 20577 * call layout on each of their children.</p> 20578 * 20579 * @param l Left position, relative to parent 20580 * @param t Top position, relative to parent 20581 * @param r Right position, relative to parent 20582 * @param b Bottom position, relative to parent 20583 */ 20584 @SuppressWarnings({"unchecked"}) 20585 public void layout(int l, int t, int r, int b) { 20586 if ((mPrivateFlags3 & PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT) != 0) { 20587 onMeasure(mOldWidthMeasureSpec, mOldHeightMeasureSpec); 20588 mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT; 20589 } 20590 20591 int oldL = mLeft; 20592 int oldT = mTop; 20593 int oldB = mBottom; 20594 int oldR = mRight; 20595 20596 boolean changed = isLayoutModeOptical(mParent) ? 20597 setOpticalFrame(l, t, r, b) : setFrame(l, t, r, b); 20598 20599 if (changed || (mPrivateFlags & PFLAG_LAYOUT_REQUIRED) == PFLAG_LAYOUT_REQUIRED) { 20600 onLayout(changed, l, t, r, b); 20601 20602 if (shouldDrawRoundScrollbar()) { 20603 if(mRoundScrollbarRenderer == null) { 20604 mRoundScrollbarRenderer = new RoundScrollbarRenderer(this); 20605 } 20606 } else { 20607 mRoundScrollbarRenderer = null; 20608 } 20609 20610 mPrivateFlags &= ~PFLAG_LAYOUT_REQUIRED; 20611 20612 ListenerInfo li = mListenerInfo; 20613 if (li != null && li.mOnLayoutChangeListeners != null) { 20614 ArrayList<OnLayoutChangeListener> listenersCopy = 20615 (ArrayList<OnLayoutChangeListener>)li.mOnLayoutChangeListeners.clone(); 20616 int numListeners = listenersCopy.size(); 20617 for (int i = 0; i < numListeners; ++i) { 20618 listenersCopy.get(i).onLayoutChange(this, l, t, r, b, oldL, oldT, oldR, oldB); 20619 } 20620 } 20621 } 20622 20623 final boolean wasLayoutValid = isLayoutValid(); 20624 20625 mPrivateFlags &= ~PFLAG_FORCE_LAYOUT; 20626 mPrivateFlags3 |= PFLAG3_IS_LAID_OUT; 20627 20628 if (!wasLayoutValid && isFocused()) { 20629 mPrivateFlags &= ~PFLAG_WANTS_FOCUS; 20630 if (canTakeFocus()) { 20631 // We have a robust focus, so parents should no longer be wanting focus. 20632 clearParentsWantFocus(); 20633 } else if (!getViewRootImpl().isInLayout()) { 20634 // This is a weird case. Most-likely the user, rather than ViewRootImpl, called 20635 // layout. In this case, there's no guarantee that parent layouts will be evaluated 20636 // and thus the safest action is to clear focus here. 20637 clearFocusInternal(null, /* propagate */ true, /* refocus */ false); 20638 clearParentsWantFocus(); 20639 } else if (!hasParentWantsFocus()) { 20640 // original requestFocus was likely on this view directly, so just clear focus 20641 clearFocusInternal(null, /* propagate */ true, /* refocus */ false); 20642 } 20643 // otherwise, we let parents handle re-assigning focus during their layout passes. 20644 } else if ((mPrivateFlags & PFLAG_WANTS_FOCUS) != 0) { 20645 mPrivateFlags &= ~PFLAG_WANTS_FOCUS; 20646 View focused = findFocus(); 20647 if (focused != null) { 20648 // Try to restore focus as close as possible to our starting focus. 20649 if (!restoreDefaultFocus() && !hasParentWantsFocus()) { 20650 // Give up and clear focus once we've reached the top-most parent which wants 20651 // focus. 20652 focused.clearFocusInternal(null, /* propagate */ true, /* refocus */ false); 20653 } 20654 } 20655 } 20656 20657 if ((mPrivateFlags3 & PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT) != 0) { 20658 mPrivateFlags3 &= ~PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT; 20659 notifyEnterOrExitForAutoFillIfNeeded(true); 20660 } 20661 } 20662 20663 private boolean hasParentWantsFocus() { 20664 ViewParent parent = mParent; 20665 while (parent instanceof ViewGroup) { 20666 ViewGroup pv = (ViewGroup) parent; 20667 if ((pv.mPrivateFlags & PFLAG_WANTS_FOCUS) != 0) { 20668 return true; 20669 } 20670 parent = pv.mParent; 20671 } 20672 return false; 20673 } 20674 20675 /** 20676 * Called from layout when this view should 20677 * assign a size and position to each of its children. 20678 * 20679 * Derived classes with children should override 20680 * this method and call layout on each of 20681 * their children. 20682 * @param changed This is a new size or position for this view 20683 * @param left Left position, relative to parent 20684 * @param top Top position, relative to parent 20685 * @param right Right position, relative to parent 20686 * @param bottom Bottom position, relative to parent 20687 */ 20688 protected void onLayout(boolean changed, int left, int top, int right, int bottom) { 20689 } 20690 20691 /** 20692 * Assign a size and position to this view. 20693 * 20694 * This is called from layout. 20695 * 20696 * @param left Left position, relative to parent 20697 * @param top Top position, relative to parent 20698 * @param right Right position, relative to parent 20699 * @param bottom Bottom position, relative to parent 20700 * @return true if the new size and position are different than the 20701 * previous ones 20702 * {@hide} 20703 */ 20704 protected boolean setFrame(int left, int top, int right, int bottom) { 20705 boolean changed = false; 20706 20707 if (DBG) { 20708 Log.d(VIEW_LOG_TAG, this + " View.setFrame(" + left + "," + top + "," 20709 + right + "," + bottom + ")"); 20710 } 20711 20712 if (mLeft != left || mRight != right || mTop != top || mBottom != bottom) { 20713 changed = true; 20714 20715 // Remember our drawn bit 20716 int drawn = mPrivateFlags & PFLAG_DRAWN; 20717 20718 int oldWidth = mRight - mLeft; 20719 int oldHeight = mBottom - mTop; 20720 int newWidth = right - left; 20721 int newHeight = bottom - top; 20722 boolean sizeChanged = (newWidth != oldWidth) || (newHeight != oldHeight); 20723 20724 // Invalidate our old position 20725 invalidate(sizeChanged); 20726 20727 mLeft = left; 20728 mTop = top; 20729 mRight = right; 20730 mBottom = bottom; 20731 mRenderNode.setLeftTopRightBottom(mLeft, mTop, mRight, mBottom); 20732 20733 mPrivateFlags |= PFLAG_HAS_BOUNDS; 20734 20735 20736 if (sizeChanged) { 20737 sizeChange(newWidth, newHeight, oldWidth, oldHeight); 20738 } 20739 20740 if ((mViewFlags & VISIBILITY_MASK) == VISIBLE || mGhostView != null) { 20741 // If we are visible, force the DRAWN bit to on so that 20742 // this invalidate will go through (at least to our parent). 20743 // This is because someone may have invalidated this view 20744 // before this call to setFrame came in, thereby clearing 20745 // the DRAWN bit. 20746 mPrivateFlags |= PFLAG_DRAWN; 20747 invalidate(sizeChanged); 20748 // parent display list may need to be recreated based on a change in the bounds 20749 // of any child 20750 invalidateParentCaches(); 20751 } 20752 20753 // Reset drawn bit to original value (invalidate turns it off) 20754 mPrivateFlags |= drawn; 20755 20756 mBackgroundSizeChanged = true; 20757 mDefaultFocusHighlightSizeChanged = true; 20758 if (mForegroundInfo != null) { 20759 mForegroundInfo.mBoundsChanged = true; 20760 } 20761 20762 notifySubtreeAccessibilityStateChangedIfNeeded(); 20763 } 20764 return changed; 20765 } 20766 20767 /** 20768 * Same as setFrame, but public and hidden. For use in {@link android.transition.ChangeBounds}. 20769 * @hide 20770 */ 20771 public void setLeftTopRightBottom(int left, int top, int right, int bottom) { 20772 setFrame(left, top, right, bottom); 20773 } 20774 20775 private void sizeChange(int newWidth, int newHeight, int oldWidth, int oldHeight) { 20776 onSizeChanged(newWidth, newHeight, oldWidth, oldHeight); 20777 if (mOverlay != null) { 20778 mOverlay.getOverlayView().setRight(newWidth); 20779 mOverlay.getOverlayView().setBottom(newHeight); 20780 } 20781 // If this isn't laid out yet, focus assignment will be handled during the "deferment/ 20782 // backtracking" of requestFocus during layout, so don't touch focus here. 20783 if (!sCanFocusZeroSized && isLayoutValid()) { 20784 if (newWidth <= 0 || newHeight <= 0) { 20785 if (hasFocus()) { 20786 clearFocus(); 20787 if (mParent instanceof ViewGroup) { 20788 ((ViewGroup) mParent).clearFocusedInCluster(); 20789 } 20790 } 20791 clearAccessibilityFocus(); 20792 } else if (oldWidth <= 0 || oldHeight <= 0) { 20793 if (mParent != null && canTakeFocus()) { 20794 mParent.focusableViewAvailable(this); 20795 } 20796 } 20797 } 20798 rebuildOutline(); 20799 } 20800 20801 /** 20802 * Finalize inflating a view from XML. This is called as the last phase 20803 * of inflation, after all child views have been added. 20804 * 20805 * <p>Even if the subclass overrides onFinishInflate, they should always be 20806 * sure to call the super method, so that we get called. 20807 */ 20808 @CallSuper 20809 protected void onFinishInflate() { 20810 } 20811 20812 /** 20813 * Returns the resources associated with this view. 20814 * 20815 * @return Resources object. 20816 */ 20817 public Resources getResources() { 20818 return mResources; 20819 } 20820 20821 /** 20822 * Invalidates the specified Drawable. 20823 * 20824 * @param drawable the drawable to invalidate 20825 */ 20826 @Override 20827 public void invalidateDrawable(@NonNull Drawable drawable) { 20828 if (verifyDrawable(drawable)) { 20829 final Rect dirty = drawable.getDirtyBounds(); 20830 final int scrollX = mScrollX; 20831 final int scrollY = mScrollY; 20832 20833 invalidate(dirty.left + scrollX, dirty.top + scrollY, 20834 dirty.right + scrollX, dirty.bottom + scrollY); 20835 rebuildOutline(); 20836 } 20837 } 20838 20839 /** 20840 * Schedules an action on a drawable to occur at a specified time. 20841 * 20842 * @param who the recipient of the action 20843 * @param what the action to run on the drawable 20844 * @param when the time at which the action must occur. Uses the 20845 * {@link SystemClock#uptimeMillis} timebase. 20846 */ 20847 @Override 20848 public void scheduleDrawable(@NonNull Drawable who, @NonNull Runnable what, long when) { 20849 if (verifyDrawable(who) && what != null) { 20850 final long delay = when - SystemClock.uptimeMillis(); 20851 if (mAttachInfo != null) { 20852 mAttachInfo.mViewRootImpl.mChoreographer.postCallbackDelayed( 20853 Choreographer.CALLBACK_ANIMATION, what, who, 20854 Choreographer.subtractFrameDelay(delay)); 20855 } else { 20856 // Postpone the runnable until we know 20857 // on which thread it needs to run. 20858 getRunQueue().postDelayed(what, delay); 20859 } 20860 } 20861 } 20862 20863 /** 20864 * Cancels a scheduled action on a drawable. 20865 * 20866 * @param who the recipient of the action 20867 * @param what the action to cancel 20868 */ 20869 @Override 20870 public void unscheduleDrawable(@NonNull Drawable who, @NonNull Runnable what) { 20871 if (verifyDrawable(who) && what != null) { 20872 if (mAttachInfo != null) { 20873 mAttachInfo.mViewRootImpl.mChoreographer.removeCallbacks( 20874 Choreographer.CALLBACK_ANIMATION, what, who); 20875 } 20876 getRunQueue().removeCallbacks(what); 20877 } 20878 } 20879 20880 /** 20881 * Unschedule any events associated with the given Drawable. This can be 20882 * used when selecting a new Drawable into a view, so that the previous 20883 * one is completely unscheduled. 20884 * 20885 * @param who The Drawable to unschedule. 20886 * 20887 * @see #drawableStateChanged 20888 */ 20889 public void unscheduleDrawable(Drawable who) { 20890 if (mAttachInfo != null && who != null) { 20891 mAttachInfo.mViewRootImpl.mChoreographer.removeCallbacks( 20892 Choreographer.CALLBACK_ANIMATION, null, who); 20893 } 20894 } 20895 20896 /** 20897 * Resolve the Drawables depending on the layout direction. This is implicitly supposing 20898 * that the View directionality can and will be resolved before its Drawables. 20899 * 20900 * Will call {@link View#onResolveDrawables} when resolution is done. 20901 * 20902 * @hide 20903 */ 20904 protected void resolveDrawables() { 20905 // Drawables resolution may need to happen before resolving the layout direction (which is 20906 // done only during the measure() call). 20907 // If the layout direction is not resolved yet, we cannot resolve the Drawables except in 20908 // one case: when the raw layout direction has not been defined as LAYOUT_DIRECTION_INHERIT. 20909 // So, if the raw layout direction is LAYOUT_DIRECTION_LTR or LAYOUT_DIRECTION_RTL or 20910 // LAYOUT_DIRECTION_LOCALE, we can "cheat" and we don't need to wait for the layout 20911 // direction to be resolved as its resolved value will be the same as its raw value. 20912 if (!isLayoutDirectionResolved() && 20913 getRawLayoutDirection() == View.LAYOUT_DIRECTION_INHERIT) { 20914 return; 20915 } 20916 20917 final int layoutDirection = isLayoutDirectionResolved() ? 20918 getLayoutDirection() : getRawLayoutDirection(); 20919 20920 if (mBackground != null) { 20921 mBackground.setLayoutDirection(layoutDirection); 20922 } 20923 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null) { 20924 mForegroundInfo.mDrawable.setLayoutDirection(layoutDirection); 20925 } 20926 if (mDefaultFocusHighlight != null) { 20927 mDefaultFocusHighlight.setLayoutDirection(layoutDirection); 20928 } 20929 mPrivateFlags2 |= PFLAG2_DRAWABLE_RESOLVED; 20930 onResolveDrawables(layoutDirection); 20931 } 20932 20933 boolean areDrawablesResolved() { 20934 return (mPrivateFlags2 & PFLAG2_DRAWABLE_RESOLVED) == PFLAG2_DRAWABLE_RESOLVED; 20935 } 20936 20937 /** 20938 * Called when layout direction has been resolved. 20939 * 20940 * The default implementation does nothing. 20941 * 20942 * @param layoutDirection The resolved layout direction. 20943 * 20944 * @see #LAYOUT_DIRECTION_LTR 20945 * @see #LAYOUT_DIRECTION_RTL 20946 * 20947 * @hide 20948 */ 20949 public void onResolveDrawables(@ResolvedLayoutDir int layoutDirection) { 20950 } 20951 20952 /** 20953 * @hide 20954 */ 20955 protected void resetResolvedDrawables() { 20956 resetResolvedDrawablesInternal(); 20957 } 20958 20959 void resetResolvedDrawablesInternal() { 20960 mPrivateFlags2 &= ~PFLAG2_DRAWABLE_RESOLVED; 20961 } 20962 20963 /** 20964 * If your view subclass is displaying its own Drawable objects, it should 20965 * override this function and return true for any Drawable it is 20966 * displaying. This allows animations for those drawables to be 20967 * scheduled. 20968 * 20969 * <p>Be sure to call through to the super class when overriding this 20970 * function. 20971 * 20972 * @param who The Drawable to verify. Return true if it is one you are 20973 * displaying, else return the result of calling through to the 20974 * super class. 20975 * 20976 * @return boolean If true than the Drawable is being displayed in the 20977 * view; else false and it is not allowed to animate. 20978 * 20979 * @see #unscheduleDrawable(android.graphics.drawable.Drawable) 20980 * @see #drawableStateChanged() 20981 */ 20982 @CallSuper 20983 protected boolean verifyDrawable(@NonNull Drawable who) { 20984 // Avoid verifying the scroll bar drawable so that we don't end up in 20985 // an invalidation loop. This effectively prevents the scroll bar 20986 // drawable from triggering invalidations and scheduling runnables. 20987 return who == mBackground || (mForegroundInfo != null && mForegroundInfo.mDrawable == who) 20988 || (mDefaultFocusHighlight == who); 20989 } 20990 20991 /** 20992 * This function is called whenever the state of the view changes in such 20993 * a way that it impacts the state of drawables being shown. 20994 * <p> 20995 * If the View has a StateListAnimator, it will also be called to run necessary state 20996 * change animations. 20997 * <p> 20998 * Be sure to call through to the superclass when overriding this function. 20999 * 21000 * @see Drawable#setState(int[]) 21001 */ 21002 @CallSuper 21003 protected void drawableStateChanged() { 21004 final int[] state = getDrawableState(); 21005 boolean changed = false; 21006 21007 final Drawable bg = mBackground; 21008 if (bg != null && bg.isStateful()) { 21009 changed |= bg.setState(state); 21010 } 21011 21012 final Drawable hl = mDefaultFocusHighlight; 21013 if (hl != null && hl.isStateful()) { 21014 changed |= hl.setState(state); 21015 } 21016 21017 final Drawable fg = mForegroundInfo != null ? mForegroundInfo.mDrawable : null; 21018 if (fg != null && fg.isStateful()) { 21019 changed |= fg.setState(state); 21020 } 21021 21022 if (mScrollCache != null) { 21023 final Drawable scrollBar = mScrollCache.scrollBar; 21024 if (scrollBar != null && scrollBar.isStateful()) { 21025 changed |= scrollBar.setState(state) 21026 && mScrollCache.state != ScrollabilityCache.OFF; 21027 } 21028 } 21029 21030 if (mStateListAnimator != null) { 21031 mStateListAnimator.setState(state); 21032 } 21033 21034 if (changed) { 21035 invalidate(); 21036 } 21037 } 21038 21039 /** 21040 * This function is called whenever the view hotspot changes and needs to 21041 * be propagated to drawables or child views managed by the view. 21042 * <p> 21043 * Dispatching to child views is handled by 21044 * {@link #dispatchDrawableHotspotChanged(float, float)}. 21045 * <p> 21046 * Be sure to call through to the superclass when overriding this function. 21047 * 21048 * @param x hotspot x coordinate 21049 * @param y hotspot y coordinate 21050 */ 21051 @CallSuper 21052 public void drawableHotspotChanged(float x, float y) { 21053 if (mBackground != null) { 21054 mBackground.setHotspot(x, y); 21055 } 21056 if (mDefaultFocusHighlight != null) { 21057 mDefaultFocusHighlight.setHotspot(x, y); 21058 } 21059 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null) { 21060 mForegroundInfo.mDrawable.setHotspot(x, y); 21061 } 21062 21063 dispatchDrawableHotspotChanged(x, y); 21064 } 21065 21066 /** 21067 * Dispatches drawableHotspotChanged to all of this View's children. 21068 * 21069 * @param x hotspot x coordinate 21070 * @param y hotspot y coordinate 21071 * @see #drawableHotspotChanged(float, float) 21072 */ 21073 public void dispatchDrawableHotspotChanged(float x, float y) { 21074 } 21075 21076 /** 21077 * Call this to force a view to update its drawable state. This will cause 21078 * drawableStateChanged to be called on this view. Views that are interested 21079 * in the new state should call getDrawableState. 21080 * 21081 * @see #drawableStateChanged 21082 * @see #getDrawableState 21083 */ 21084 public void refreshDrawableState() { 21085 mPrivateFlags |= PFLAG_DRAWABLE_STATE_DIRTY; 21086 drawableStateChanged(); 21087 21088 ViewParent parent = mParent; 21089 if (parent != null) { 21090 parent.childDrawableStateChanged(this); 21091 } 21092 } 21093 21094 /** 21095 * Create a default focus highlight if it doesn't exist. 21096 * @return a default focus highlight. 21097 */ 21098 private Drawable getDefaultFocusHighlightDrawable() { 21099 if (mDefaultFocusHighlightCache == null) { 21100 if (mContext != null) { 21101 final int[] attrs = new int[] { android.R.attr.selectableItemBackground }; 21102 final TypedArray ta = mContext.obtainStyledAttributes(attrs); 21103 mDefaultFocusHighlightCache = ta.getDrawable(0); 21104 ta.recycle(); 21105 } 21106 } 21107 return mDefaultFocusHighlightCache; 21108 } 21109 21110 /** 21111 * Set the current default focus highlight. 21112 * @param highlight the highlight drawable, or {@code null} if it's no longer needed. 21113 */ 21114 private void setDefaultFocusHighlight(Drawable highlight) { 21115 mDefaultFocusHighlight = highlight; 21116 mDefaultFocusHighlightSizeChanged = true; 21117 if (highlight != null) { 21118 if ((mPrivateFlags & PFLAG_SKIP_DRAW) != 0) { 21119 mPrivateFlags &= ~PFLAG_SKIP_DRAW; 21120 } 21121 highlight.setLayoutDirection(getLayoutDirection()); 21122 if (highlight.isStateful()) { 21123 highlight.setState(getDrawableState()); 21124 } 21125 if (isAttachedToWindow()) { 21126 highlight.setVisible(getWindowVisibility() == VISIBLE && isShown(), false); 21127 } 21128 // Set callback last, since the view may still be initializing. 21129 highlight.setCallback(this); 21130 } else if ((mViewFlags & WILL_NOT_DRAW) != 0 && mBackground == null 21131 && (mForegroundInfo == null || mForegroundInfo.mDrawable == null)) { 21132 mPrivateFlags |= PFLAG_SKIP_DRAW; 21133 } 21134 invalidate(); 21135 } 21136 21137 /** 21138 * Check whether we need to draw a default focus highlight when this view gets focused, 21139 * which requires: 21140 * <ul> 21141 * <li>In both background and foreground, {@link android.R.attr#state_focused} 21142 * is not defined.</li> 21143 * <li>This view is not in touch mode.</li> 21144 * <li>This view doesn't opt out for a default focus highlight, via 21145 * {@link #setDefaultFocusHighlightEnabled(boolean)}.</li> 21146 * <li>This view is attached to window.</li> 21147 * </ul> 21148 * @return {@code true} if a default focus highlight is needed. 21149 * @hide 21150 */ 21151 @TestApi 21152 public boolean isDefaultFocusHighlightNeeded(Drawable background, Drawable foreground) { 21153 final boolean lackFocusState = (background == null || !background.isStateful() 21154 || !background.hasFocusStateSpecified()) 21155 && (foreground == null || !foreground.isStateful() 21156 || !foreground.hasFocusStateSpecified()); 21157 return !isInTouchMode() && getDefaultFocusHighlightEnabled() && lackFocusState 21158 && isAttachedToWindow() && sUseDefaultFocusHighlight; 21159 } 21160 21161 /** 21162 * When this view is focused, switches on/off the default focused highlight. 21163 * <p> 21164 * This always happens when this view is focused, and only at this moment the default focus 21165 * highlight can be visible. 21166 */ 21167 private void switchDefaultFocusHighlight() { 21168 if (isFocused()) { 21169 final boolean needed = isDefaultFocusHighlightNeeded(mBackground, 21170 mForegroundInfo == null ? null : mForegroundInfo.mDrawable); 21171 final boolean active = mDefaultFocusHighlight != null; 21172 if (needed && !active) { 21173 setDefaultFocusHighlight(getDefaultFocusHighlightDrawable()); 21174 } else if (!needed && active) { 21175 // The highlight is no longer needed, so tear it down. 21176 setDefaultFocusHighlight(null); 21177 } 21178 } 21179 } 21180 21181 /** 21182 * Draw the default focus highlight onto the canvas. 21183 * @param canvas the canvas where we're drawing the highlight. 21184 */ 21185 private void drawDefaultFocusHighlight(Canvas canvas) { 21186 if (mDefaultFocusHighlight != null) { 21187 if (mDefaultFocusHighlightSizeChanged) { 21188 mDefaultFocusHighlightSizeChanged = false; 21189 final int l = mScrollX; 21190 final int r = l + mRight - mLeft; 21191 final int t = mScrollY; 21192 final int b = t + mBottom - mTop; 21193 mDefaultFocusHighlight.setBounds(l, t, r, b); 21194 } 21195 mDefaultFocusHighlight.draw(canvas); 21196 } 21197 } 21198 21199 /** 21200 * Return an array of resource IDs of the drawable states representing the 21201 * current state of the view. 21202 * 21203 * @return The current drawable state 21204 * 21205 * @see Drawable#setState(int[]) 21206 * @see #drawableStateChanged() 21207 * @see #onCreateDrawableState(int) 21208 */ 21209 public final int[] getDrawableState() { 21210 if ((mDrawableState != null) && ((mPrivateFlags & PFLAG_DRAWABLE_STATE_DIRTY) == 0)) { 21211 return mDrawableState; 21212 } else { 21213 mDrawableState = onCreateDrawableState(0); 21214 mPrivateFlags &= ~PFLAG_DRAWABLE_STATE_DIRTY; 21215 return mDrawableState; 21216 } 21217 } 21218 21219 /** 21220 * Generate the new {@link android.graphics.drawable.Drawable} state for 21221 * this view. This is called by the view 21222 * system when the cached Drawable state is determined to be invalid. To 21223 * retrieve the current state, you should use {@link #getDrawableState}. 21224 * 21225 * @param extraSpace if non-zero, this is the number of extra entries you 21226 * would like in the returned array in which you can place your own 21227 * states. 21228 * 21229 * @return Returns an array holding the current {@link Drawable} state of 21230 * the view. 21231 * 21232 * @see #mergeDrawableStates(int[], int[]) 21233 */ 21234 protected int[] onCreateDrawableState(int extraSpace) { 21235 if ((mViewFlags & DUPLICATE_PARENT_STATE) == DUPLICATE_PARENT_STATE && 21236 mParent instanceof View) { 21237 return ((View) mParent).onCreateDrawableState(extraSpace); 21238 } 21239 21240 int[] drawableState; 21241 21242 int privateFlags = mPrivateFlags; 21243 21244 int viewStateIndex = 0; 21245 if ((privateFlags & PFLAG_PRESSED) != 0) viewStateIndex |= StateSet.VIEW_STATE_PRESSED; 21246 if ((mViewFlags & ENABLED_MASK) == ENABLED) viewStateIndex |= StateSet.VIEW_STATE_ENABLED; 21247 if (isFocused()) viewStateIndex |= StateSet.VIEW_STATE_FOCUSED; 21248 if ((privateFlags & PFLAG_SELECTED) != 0) viewStateIndex |= StateSet.VIEW_STATE_SELECTED; 21249 if (hasWindowFocus()) viewStateIndex |= StateSet.VIEW_STATE_WINDOW_FOCUSED; 21250 if ((privateFlags & PFLAG_ACTIVATED) != 0) viewStateIndex |= StateSet.VIEW_STATE_ACTIVATED; 21251 if (mAttachInfo != null && mAttachInfo.mHardwareAccelerationRequested && 21252 ThreadedRenderer.isAvailable()) { 21253 // This is set if HW acceleration is requested, even if the current 21254 // process doesn't allow it. This is just to allow app preview 21255 // windows to better match their app. 21256 viewStateIndex |= StateSet.VIEW_STATE_ACCELERATED; 21257 } 21258 if ((privateFlags & PFLAG_HOVERED) != 0) viewStateIndex |= StateSet.VIEW_STATE_HOVERED; 21259 21260 final int privateFlags2 = mPrivateFlags2; 21261 if ((privateFlags2 & PFLAG2_DRAG_CAN_ACCEPT) != 0) { 21262 viewStateIndex |= StateSet.VIEW_STATE_DRAG_CAN_ACCEPT; 21263 } 21264 if ((privateFlags2 & PFLAG2_DRAG_HOVERED) != 0) { 21265 viewStateIndex |= StateSet.VIEW_STATE_DRAG_HOVERED; 21266 } 21267 21268 drawableState = StateSet.get(viewStateIndex); 21269 21270 //noinspection ConstantIfStatement 21271 if (false) { 21272 Log.i("View", "drawableStateIndex=" + viewStateIndex); 21273 Log.i("View", toString() 21274 + " pressed=" + ((privateFlags & PFLAG_PRESSED) != 0) 21275 + " en=" + ((mViewFlags & ENABLED_MASK) == ENABLED) 21276 + " fo=" + hasFocus() 21277 + " sl=" + ((privateFlags & PFLAG_SELECTED) != 0) 21278 + " wf=" + hasWindowFocus() 21279 + ": " + Arrays.toString(drawableState)); 21280 } 21281 21282 if (extraSpace == 0) { 21283 return drawableState; 21284 } 21285 21286 final int[] fullState; 21287 if (drawableState != null) { 21288 fullState = new int[drawableState.length + extraSpace]; 21289 System.arraycopy(drawableState, 0, fullState, 0, drawableState.length); 21290 } else { 21291 fullState = new int[extraSpace]; 21292 } 21293 21294 return fullState; 21295 } 21296 21297 /** 21298 * Merge your own state values in <var>additionalState</var> into the base 21299 * state values <var>baseState</var> that were returned by 21300 * {@link #onCreateDrawableState(int)}. 21301 * 21302 * @param baseState The base state values returned by 21303 * {@link #onCreateDrawableState(int)}, which will be modified to also hold your 21304 * own additional state values. 21305 * 21306 * @param additionalState The additional state values you would like 21307 * added to <var>baseState</var>; this array is not modified. 21308 * 21309 * @return As a convenience, the <var>baseState</var> array you originally 21310 * passed into the function is returned. 21311 * 21312 * @see #onCreateDrawableState(int) 21313 */ 21314 protected static int[] mergeDrawableStates(int[] baseState, int[] additionalState) { 21315 final int N = baseState.length; 21316 int i = N - 1; 21317 while (i >= 0 && baseState[i] == 0) { 21318 i--; 21319 } 21320 System.arraycopy(additionalState, 0, baseState, i + 1, additionalState.length); 21321 return baseState; 21322 } 21323 21324 /** 21325 * Call {@link Drawable#jumpToCurrentState() Drawable.jumpToCurrentState()} 21326 * on all Drawable objects associated with this view. 21327 * <p> 21328 * Also calls {@link StateListAnimator#jumpToCurrentState()} if there is a StateListAnimator 21329 * attached to this view. 21330 */ 21331 @CallSuper 21332 public void jumpDrawablesToCurrentState() { 21333 if (mBackground != null) { 21334 mBackground.jumpToCurrentState(); 21335 } 21336 if (mStateListAnimator != null) { 21337 mStateListAnimator.jumpToCurrentState(); 21338 } 21339 if (mDefaultFocusHighlight != null) { 21340 mDefaultFocusHighlight.jumpToCurrentState(); 21341 } 21342 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null) { 21343 mForegroundInfo.mDrawable.jumpToCurrentState(); 21344 } 21345 } 21346 21347 /** 21348 * Sets the background color for this view. 21349 * @param color the color of the background 21350 */ 21351 @RemotableViewMethod 21352 public void setBackgroundColor(@ColorInt int color) { 21353 if (mBackground instanceof ColorDrawable) { 21354 ((ColorDrawable) mBackground.mutate()).setColor(color); 21355 computeOpaqueFlags(); 21356 mBackgroundResource = 0; 21357 } else { 21358 setBackground(new ColorDrawable(color)); 21359 } 21360 } 21361 21362 /** 21363 * Set the background to a given resource. The resource should refer to 21364 * a Drawable object or 0 to remove the background. 21365 * @param resid The identifier of the resource. 21366 * 21367 * @attr ref android.R.styleable#View_background 21368 */ 21369 @RemotableViewMethod 21370 public void setBackgroundResource(@DrawableRes int resid) { 21371 if (resid != 0 && resid == mBackgroundResource) { 21372 return; 21373 } 21374 21375 Drawable d = null; 21376 if (resid != 0) { 21377 d = mContext.getDrawable(resid); 21378 } 21379 setBackground(d); 21380 21381 mBackgroundResource = resid; 21382 } 21383 21384 /** 21385 * Set the background to a given Drawable, or remove the background. If the 21386 * background has padding, this View's padding is set to the background's 21387 * padding. However, when a background is removed, this View's padding isn't 21388 * touched. If setting the padding is desired, please use 21389 * {@link #setPadding(int, int, int, int)}. 21390 * 21391 * @param background The Drawable to use as the background, or null to remove the 21392 * background 21393 */ 21394 public void setBackground(Drawable background) { 21395 //noinspection deprecation 21396 setBackgroundDrawable(background); 21397 } 21398 21399 /** 21400 * @deprecated use {@link #setBackground(Drawable)} instead 21401 */ 21402 @Deprecated 21403 public void setBackgroundDrawable(Drawable background) { 21404 computeOpaqueFlags(); 21405 21406 if (background == mBackground) { 21407 return; 21408 } 21409 21410 boolean requestLayout = false; 21411 21412 mBackgroundResource = 0; 21413 21414 /* 21415 * Regardless of whether we're setting a new background or not, we want 21416 * to clear the previous drawable. setVisible first while we still have the callback set. 21417 */ 21418 if (mBackground != null) { 21419 if (isAttachedToWindow()) { 21420 mBackground.setVisible(false, false); 21421 } 21422 mBackground.setCallback(null); 21423 unscheduleDrawable(mBackground); 21424 } 21425 21426 if (background != null) { 21427 Rect padding = sThreadLocal.get(); 21428 if (padding == null) { 21429 padding = new Rect(); 21430 sThreadLocal.set(padding); 21431 } 21432 resetResolvedDrawablesInternal(); 21433 background.setLayoutDirection(getLayoutDirection()); 21434 if (background.getPadding(padding)) { 21435 resetResolvedPaddingInternal(); 21436 switch (background.getLayoutDirection()) { 21437 case LAYOUT_DIRECTION_RTL: 21438 mUserPaddingLeftInitial = padding.right; 21439 mUserPaddingRightInitial = padding.left; 21440 internalSetPadding(padding.right, padding.top, padding.left, padding.bottom); 21441 break; 21442 case LAYOUT_DIRECTION_LTR: 21443 default: 21444 mUserPaddingLeftInitial = padding.left; 21445 mUserPaddingRightInitial = padding.right; 21446 internalSetPadding(padding.left, padding.top, padding.right, padding.bottom); 21447 } 21448 mLeftPaddingDefined = false; 21449 mRightPaddingDefined = false; 21450 } 21451 21452 // Compare the minimum sizes of the old Drawable and the new. If there isn't an old or 21453 // if it has a different minimum size, we should layout again 21454 if (mBackground == null 21455 || mBackground.getMinimumHeight() != background.getMinimumHeight() 21456 || mBackground.getMinimumWidth() != background.getMinimumWidth()) { 21457 requestLayout = true; 21458 } 21459 21460 // Set mBackground before we set this as the callback and start making other 21461 // background drawable state change calls. In particular, the setVisible call below 21462 // can result in drawables attempting to start animations or otherwise invalidate, 21463 // which requires the view set as the callback (us) to recognize the drawable as 21464 // belonging to it as per verifyDrawable. 21465 mBackground = background; 21466 if (background.isStateful()) { 21467 background.setState(getDrawableState()); 21468 } 21469 if (isAttachedToWindow()) { 21470 background.setVisible(getWindowVisibility() == VISIBLE && isShown(), false); 21471 } 21472 21473 applyBackgroundTint(); 21474 21475 // Set callback last, since the view may still be initializing. 21476 background.setCallback(this); 21477 21478 if ((mPrivateFlags & PFLAG_SKIP_DRAW) != 0) { 21479 mPrivateFlags &= ~PFLAG_SKIP_DRAW; 21480 requestLayout = true; 21481 } 21482 } else { 21483 /* Remove the background */ 21484 mBackground = null; 21485 if ((mViewFlags & WILL_NOT_DRAW) != 0 21486 && (mDefaultFocusHighlight == null) 21487 && (mForegroundInfo == null || mForegroundInfo.mDrawable == null)) { 21488 mPrivateFlags |= PFLAG_SKIP_DRAW; 21489 } 21490 21491 /* 21492 * When the background is set, we try to apply its padding to this 21493 * View. When the background is removed, we don't touch this View's 21494 * padding. This is noted in the Javadocs. Hence, we don't need to 21495 * requestLayout(), the invalidate() below is sufficient. 21496 */ 21497 21498 // The old background's minimum size could have affected this 21499 // View's layout, so let's requestLayout 21500 requestLayout = true; 21501 } 21502 21503 computeOpaqueFlags(); 21504 21505 if (requestLayout) { 21506 requestLayout(); 21507 } 21508 21509 mBackgroundSizeChanged = true; 21510 invalidate(true); 21511 invalidateOutline(); 21512 } 21513 21514 /** 21515 * Gets the background drawable 21516 * 21517 * @return The drawable used as the background for this view, if any. 21518 * 21519 * @see #setBackground(Drawable) 21520 * 21521 * @attr ref android.R.styleable#View_background 21522 */ 21523 public Drawable getBackground() { 21524 return mBackground; 21525 } 21526 21527 /** 21528 * Applies a tint to the background drawable. Does not modify the current tint 21529 * mode, which is {@link PorterDuff.Mode#SRC_IN} by default. 21530 * <p> 21531 * Subsequent calls to {@link #setBackground(Drawable)} will automatically 21532 * mutate the drawable and apply the specified tint and tint mode using 21533 * {@link Drawable#setTintList(ColorStateList)}. 21534 * 21535 * @param tint the tint to apply, may be {@code null} to clear tint 21536 * 21537 * @attr ref android.R.styleable#View_backgroundTint 21538 * @see #getBackgroundTintList() 21539 * @see Drawable#setTintList(ColorStateList) 21540 */ 21541 public void setBackgroundTintList(@Nullable ColorStateList tint) { 21542 if (mBackgroundTint == null) { 21543 mBackgroundTint = new TintInfo(); 21544 } 21545 mBackgroundTint.mTintList = tint; 21546 mBackgroundTint.mHasTintList = true; 21547 21548 applyBackgroundTint(); 21549 } 21550 21551 /** 21552 * Return the tint applied to the background drawable, if specified. 21553 * 21554 * @return the tint applied to the background drawable 21555 * @attr ref android.R.styleable#View_backgroundTint 21556 * @see #setBackgroundTintList(ColorStateList) 21557 */ 21558 @Nullable 21559 public ColorStateList getBackgroundTintList() { 21560 return mBackgroundTint != null ? mBackgroundTint.mTintList : null; 21561 } 21562 21563 /** 21564 * Specifies the blending mode used to apply the tint specified by 21565 * {@link #setBackgroundTintList(ColorStateList)}} to the background 21566 * drawable. The default mode is {@link PorterDuff.Mode#SRC_IN}. 21567 * 21568 * @param tintMode the blending mode used to apply the tint, may be 21569 * {@code null} to clear tint 21570 * @attr ref android.R.styleable#View_backgroundTintMode 21571 * @see #getBackgroundTintMode() 21572 * @see Drawable#setTintMode(PorterDuff.Mode) 21573 */ 21574 public void setBackgroundTintMode(@Nullable PorterDuff.Mode tintMode) { 21575 if (mBackgroundTint == null) { 21576 mBackgroundTint = new TintInfo(); 21577 } 21578 mBackgroundTint.mTintMode = tintMode; 21579 mBackgroundTint.mHasTintMode = true; 21580 21581 applyBackgroundTint(); 21582 } 21583 21584 /** 21585 * Return the blending mode used to apply the tint to the background 21586 * drawable, if specified. 21587 * 21588 * @return the blending mode used to apply the tint to the background 21589 * drawable 21590 * @attr ref android.R.styleable#View_backgroundTintMode 21591 * @see #setBackgroundTintMode(PorterDuff.Mode) 21592 */ 21593 @Nullable 21594 public PorterDuff.Mode getBackgroundTintMode() { 21595 return mBackgroundTint != null ? mBackgroundTint.mTintMode : null; 21596 } 21597 21598 private void applyBackgroundTint() { 21599 if (mBackground != null && mBackgroundTint != null) { 21600 final TintInfo tintInfo = mBackgroundTint; 21601 if (tintInfo.mHasTintList || tintInfo.mHasTintMode) { 21602 mBackground = mBackground.mutate(); 21603 21604 if (tintInfo.mHasTintList) { 21605 mBackground.setTintList(tintInfo.mTintList); 21606 } 21607 21608 if (tintInfo.mHasTintMode) { 21609 mBackground.setTintMode(tintInfo.mTintMode); 21610 } 21611 21612 // The drawable (or one of its children) may not have been 21613 // stateful before applying the tint, so let's try again. 21614 if (mBackground.isStateful()) { 21615 mBackground.setState(getDrawableState()); 21616 } 21617 } 21618 } 21619 } 21620 21621 /** 21622 * Returns the drawable used as the foreground of this View. The 21623 * foreground drawable, if non-null, is always drawn on top of the view's content. 21624 * 21625 * @return a Drawable or null if no foreground was set 21626 * 21627 * @see #onDrawForeground(Canvas) 21628 */ 21629 public Drawable getForeground() { 21630 return mForegroundInfo != null ? mForegroundInfo.mDrawable : null; 21631 } 21632 21633 /** 21634 * Supply a Drawable that is to be rendered on top of all of the content in the view. 21635 * 21636 * @param foreground the Drawable to be drawn on top of the children 21637 * 21638 * @attr ref android.R.styleable#View_foreground 21639 */ 21640 public void setForeground(Drawable foreground) { 21641 if (mForegroundInfo == null) { 21642 if (foreground == null) { 21643 // Nothing to do. 21644 return; 21645 } 21646 mForegroundInfo = new ForegroundInfo(); 21647 } 21648 21649 if (foreground == mForegroundInfo.mDrawable) { 21650 // Nothing to do 21651 return; 21652 } 21653 21654 if (mForegroundInfo.mDrawable != null) { 21655 if (isAttachedToWindow()) { 21656 mForegroundInfo.mDrawable.setVisible(false, false); 21657 } 21658 mForegroundInfo.mDrawable.setCallback(null); 21659 unscheduleDrawable(mForegroundInfo.mDrawable); 21660 } 21661 21662 mForegroundInfo.mDrawable = foreground; 21663 mForegroundInfo.mBoundsChanged = true; 21664 if (foreground != null) { 21665 if ((mPrivateFlags & PFLAG_SKIP_DRAW) != 0) { 21666 mPrivateFlags &= ~PFLAG_SKIP_DRAW; 21667 } 21668 foreground.setLayoutDirection(getLayoutDirection()); 21669 if (foreground.isStateful()) { 21670 foreground.setState(getDrawableState()); 21671 } 21672 applyForegroundTint(); 21673 if (isAttachedToWindow()) { 21674 foreground.setVisible(getWindowVisibility() == VISIBLE && isShown(), false); 21675 } 21676 // Set callback last, since the view may still be initializing. 21677 foreground.setCallback(this); 21678 } else if ((mViewFlags & WILL_NOT_DRAW) != 0 && mBackground == null 21679 && (mDefaultFocusHighlight == null)) { 21680 mPrivateFlags |= PFLAG_SKIP_DRAW; 21681 } 21682 requestLayout(); 21683 invalidate(); 21684 } 21685 21686 /** 21687 * Magic bit used to support features of framework-internal window decor implementation details. 21688 * This used to live exclusively in FrameLayout. 21689 * 21690 * @return true if the foreground should draw inside the padding region or false 21691 * if it should draw inset by the view's padding 21692 * @hide internal use only; only used by FrameLayout and internal screen layouts. 21693 */ 21694 public boolean isForegroundInsidePadding() { 21695 return mForegroundInfo != null ? mForegroundInfo.mInsidePadding : true; 21696 } 21697 21698 /** 21699 * Describes how the foreground is positioned. 21700 * 21701 * @return foreground gravity. 21702 * 21703 * @see #setForegroundGravity(int) 21704 * 21705 * @attr ref android.R.styleable#View_foregroundGravity 21706 */ 21707 public int getForegroundGravity() { 21708 return mForegroundInfo != null ? mForegroundInfo.mGravity 21709 : Gravity.START | Gravity.TOP; 21710 } 21711 21712 /** 21713 * Describes how the foreground is positioned. Defaults to START and TOP. 21714 * 21715 * @param gravity see {@link android.view.Gravity} 21716 * 21717 * @see #getForegroundGravity() 21718 * 21719 * @attr ref android.R.styleable#View_foregroundGravity 21720 */ 21721 public void setForegroundGravity(int gravity) { 21722 if (mForegroundInfo == null) { 21723 mForegroundInfo = new ForegroundInfo(); 21724 } 21725 21726 if (mForegroundInfo.mGravity != gravity) { 21727 if ((gravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK) == 0) { 21728 gravity |= Gravity.START; 21729 } 21730 21731 if ((gravity & Gravity.VERTICAL_GRAVITY_MASK) == 0) { 21732 gravity |= Gravity.TOP; 21733 } 21734 21735 mForegroundInfo.mGravity = gravity; 21736 requestLayout(); 21737 } 21738 } 21739 21740 /** 21741 * Applies a tint to the foreground drawable. Does not modify the current tint 21742 * mode, which is {@link PorterDuff.Mode#SRC_IN} by default. 21743 * <p> 21744 * Subsequent calls to {@link #setForeground(Drawable)} will automatically 21745 * mutate the drawable and apply the specified tint and tint mode using 21746 * {@link Drawable#setTintList(ColorStateList)}. 21747 * 21748 * @param tint the tint to apply, may be {@code null} to clear tint 21749 * 21750 * @attr ref android.R.styleable#View_foregroundTint 21751 * @see #getForegroundTintList() 21752 * @see Drawable#setTintList(ColorStateList) 21753 */ 21754 public void setForegroundTintList(@Nullable ColorStateList tint) { 21755 if (mForegroundInfo == null) { 21756 mForegroundInfo = new ForegroundInfo(); 21757 } 21758 if (mForegroundInfo.mTintInfo == null) { 21759 mForegroundInfo.mTintInfo = new TintInfo(); 21760 } 21761 mForegroundInfo.mTintInfo.mTintList = tint; 21762 mForegroundInfo.mTintInfo.mHasTintList = true; 21763 21764 applyForegroundTint(); 21765 } 21766 21767 /** 21768 * Return the tint applied to the foreground drawable, if specified. 21769 * 21770 * @return the tint applied to the foreground drawable 21771 * @attr ref android.R.styleable#View_foregroundTint 21772 * @see #setForegroundTintList(ColorStateList) 21773 */ 21774 @Nullable 21775 public ColorStateList getForegroundTintList() { 21776 return mForegroundInfo != null && mForegroundInfo.mTintInfo != null 21777 ? mForegroundInfo.mTintInfo.mTintList : null; 21778 } 21779 21780 /** 21781 * Specifies the blending mode used to apply the tint specified by 21782 * {@link #setForegroundTintList(ColorStateList)}} to the background 21783 * drawable. The default mode is {@link PorterDuff.Mode#SRC_IN}. 21784 * 21785 * @param tintMode the blending mode used to apply the tint, may be 21786 * {@code null} to clear tint 21787 * @attr ref android.R.styleable#View_foregroundTintMode 21788 * @see #getForegroundTintMode() 21789 * @see Drawable#setTintMode(PorterDuff.Mode) 21790 */ 21791 public void setForegroundTintMode(@Nullable PorterDuff.Mode tintMode) { 21792 if (mForegroundInfo == null) { 21793 mForegroundInfo = new ForegroundInfo(); 21794 } 21795 if (mForegroundInfo.mTintInfo == null) { 21796 mForegroundInfo.mTintInfo = new TintInfo(); 21797 } 21798 mForegroundInfo.mTintInfo.mTintMode = tintMode; 21799 mForegroundInfo.mTintInfo.mHasTintMode = true; 21800 21801 applyForegroundTint(); 21802 } 21803 21804 /** 21805 * Return the blending mode used to apply the tint to the foreground 21806 * drawable, if specified. 21807 * 21808 * @return the blending mode used to apply the tint to the foreground 21809 * drawable 21810 * @attr ref android.R.styleable#View_foregroundTintMode 21811 * @see #setForegroundTintMode(PorterDuff.Mode) 21812 */ 21813 @Nullable 21814 public PorterDuff.Mode getForegroundTintMode() { 21815 return mForegroundInfo != null && mForegroundInfo.mTintInfo != null 21816 ? mForegroundInfo.mTintInfo.mTintMode : null; 21817 } 21818 21819 private void applyForegroundTint() { 21820 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null 21821 && mForegroundInfo.mTintInfo != null) { 21822 final TintInfo tintInfo = mForegroundInfo.mTintInfo; 21823 if (tintInfo.mHasTintList || tintInfo.mHasTintMode) { 21824 mForegroundInfo.mDrawable = mForegroundInfo.mDrawable.mutate(); 21825 21826 if (tintInfo.mHasTintList) { 21827 mForegroundInfo.mDrawable.setTintList(tintInfo.mTintList); 21828 } 21829 21830 if (tintInfo.mHasTintMode) { 21831 mForegroundInfo.mDrawable.setTintMode(tintInfo.mTintMode); 21832 } 21833 21834 // The drawable (or one of its children) may not have been 21835 // stateful before applying the tint, so let's try again. 21836 if (mForegroundInfo.mDrawable.isStateful()) { 21837 mForegroundInfo.mDrawable.setState(getDrawableState()); 21838 } 21839 } 21840 } 21841 } 21842 21843 /** 21844 * Get the drawable to be overlayed when a view is autofilled 21845 * 21846 * @return The drawable 21847 * 21848 * @throws IllegalStateException if the drawable could not be found. 21849 */ 21850 @Nullable private Drawable getAutofilledDrawable() { 21851 if (mAttachInfo == null) { 21852 return null; 21853 } 21854 // Lazily load the isAutofilled drawable. 21855 if (mAttachInfo.mAutofilledDrawable == null) { 21856 Context rootContext = getRootView().getContext(); 21857 TypedArray a = rootContext.getTheme().obtainStyledAttributes(AUTOFILL_HIGHLIGHT_ATTR); 21858 int attributeResourceId = a.getResourceId(0, 0); 21859 mAttachInfo.mAutofilledDrawable = rootContext.getDrawable(attributeResourceId); 21860 a.recycle(); 21861 } 21862 21863 return mAttachInfo.mAutofilledDrawable; 21864 } 21865 21866 /** 21867 * Draw {@link View#isAutofilled()} highlight over view if the view is autofilled. 21868 * 21869 * @param canvas The canvas to draw on 21870 */ 21871 private void drawAutofilledHighlight(@NonNull Canvas canvas) { 21872 if (isAutofilled()) { 21873 Drawable autofilledHighlight = getAutofilledDrawable(); 21874 21875 if (autofilledHighlight != null) { 21876 autofilledHighlight.setBounds(0, 0, getWidth(), getHeight()); 21877 autofilledHighlight.draw(canvas); 21878 } 21879 } 21880 } 21881 21882 /** 21883 * Draw any foreground content for this view. 21884 * 21885 * <p>Foreground content may consist of scroll bars, a {@link #setForeground foreground} 21886 * drawable or other view-specific decorations. The foreground is drawn on top of the 21887 * primary view content.</p> 21888 * 21889 * @param canvas canvas to draw into 21890 */ 21891 public void onDrawForeground(Canvas canvas) { 21892 onDrawScrollIndicators(canvas); 21893 onDrawScrollBars(canvas); 21894 21895 final Drawable foreground = mForegroundInfo != null ? mForegroundInfo.mDrawable : null; 21896 if (foreground != null) { 21897 if (mForegroundInfo.mBoundsChanged) { 21898 mForegroundInfo.mBoundsChanged = false; 21899 final Rect selfBounds = mForegroundInfo.mSelfBounds; 21900 final Rect overlayBounds = mForegroundInfo.mOverlayBounds; 21901 21902 if (mForegroundInfo.mInsidePadding) { 21903 selfBounds.set(0, 0, getWidth(), getHeight()); 21904 } else { 21905 selfBounds.set(getPaddingLeft(), getPaddingTop(), 21906 getWidth() - getPaddingRight(), getHeight() - getPaddingBottom()); 21907 } 21908 21909 final int ld = getLayoutDirection(); 21910 Gravity.apply(mForegroundInfo.mGravity, foreground.getIntrinsicWidth(), 21911 foreground.getIntrinsicHeight(), selfBounds, overlayBounds, ld); 21912 foreground.setBounds(overlayBounds); 21913 } 21914 21915 foreground.draw(canvas); 21916 } 21917 } 21918 21919 /** 21920 * Sets the padding. The view may add on the space required to display 21921 * the scrollbars, depending on the style and visibility of the scrollbars. 21922 * So the values returned from {@link #getPaddingLeft}, {@link #getPaddingTop}, 21923 * {@link #getPaddingRight} and {@link #getPaddingBottom} may be different 21924 * from the values set in this call. 21925 * 21926 * @attr ref android.R.styleable#View_padding 21927 * @attr ref android.R.styleable#View_paddingBottom 21928 * @attr ref android.R.styleable#View_paddingLeft 21929 * @attr ref android.R.styleable#View_paddingRight 21930 * @attr ref android.R.styleable#View_paddingTop 21931 * @param left the left padding in pixels 21932 * @param top the top padding in pixels 21933 * @param right the right padding in pixels 21934 * @param bottom the bottom padding in pixels 21935 */ 21936 public void setPadding(int left, int top, int right, int bottom) { 21937 resetResolvedPaddingInternal(); 21938 21939 mUserPaddingStart = UNDEFINED_PADDING; 21940 mUserPaddingEnd = UNDEFINED_PADDING; 21941 21942 mUserPaddingLeftInitial = left; 21943 mUserPaddingRightInitial = right; 21944 21945 mLeftPaddingDefined = true; 21946 mRightPaddingDefined = true; 21947 21948 internalSetPadding(left, top, right, bottom); 21949 } 21950 21951 /** 21952 * @hide 21953 */ 21954 protected void internalSetPadding(int left, int top, int right, int bottom) { 21955 mUserPaddingLeft = left; 21956 mUserPaddingRight = right; 21957 mUserPaddingBottom = bottom; 21958 21959 final int viewFlags = mViewFlags; 21960 boolean changed = false; 21961 21962 // Common case is there are no scroll bars. 21963 if ((viewFlags & (SCROLLBARS_VERTICAL|SCROLLBARS_HORIZONTAL)) != 0) { 21964 if ((viewFlags & SCROLLBARS_VERTICAL) != 0) { 21965 final int offset = (viewFlags & SCROLLBARS_INSET_MASK) == 0 21966 ? 0 : getVerticalScrollbarWidth(); 21967 switch (mVerticalScrollbarPosition) { 21968 case SCROLLBAR_POSITION_DEFAULT: 21969 if (isLayoutRtl()) { 21970 left += offset; 21971 } else { 21972 right += offset; 21973 } 21974 break; 21975 case SCROLLBAR_POSITION_RIGHT: 21976 right += offset; 21977 break; 21978 case SCROLLBAR_POSITION_LEFT: 21979 left += offset; 21980 break; 21981 } 21982 } 21983 if ((viewFlags & SCROLLBARS_HORIZONTAL) != 0) { 21984 bottom += (viewFlags & SCROLLBARS_INSET_MASK) == 0 21985 ? 0 : getHorizontalScrollbarHeight(); 21986 } 21987 } 21988 21989 if (mPaddingLeft != left) { 21990 changed = true; 21991 mPaddingLeft = left; 21992 } 21993 if (mPaddingTop != top) { 21994 changed = true; 21995 mPaddingTop = top; 21996 } 21997 if (mPaddingRight != right) { 21998 changed = true; 21999 mPaddingRight = right; 22000 } 22001 if (mPaddingBottom != bottom) { 22002 changed = true; 22003 mPaddingBottom = bottom; 22004 } 22005 22006 if (changed) { 22007 requestLayout(); 22008 invalidateOutline(); 22009 } 22010 } 22011 22012 /** 22013 * Sets the relative padding. The view may add on the space required to display 22014 * the scrollbars, depending on the style and visibility of the scrollbars. 22015 * So the values returned from {@link #getPaddingStart}, {@link #getPaddingTop}, 22016 * {@link #getPaddingEnd} and {@link #getPaddingBottom} may be different 22017 * from the values set in this call. 22018 * 22019 * @attr ref android.R.styleable#View_padding 22020 * @attr ref android.R.styleable#View_paddingBottom 22021 * @attr ref android.R.styleable#View_paddingStart 22022 * @attr ref android.R.styleable#View_paddingEnd 22023 * @attr ref android.R.styleable#View_paddingTop 22024 * @param start the start padding in pixels 22025 * @param top the top padding in pixels 22026 * @param end the end padding in pixels 22027 * @param bottom the bottom padding in pixels 22028 */ 22029 public void setPaddingRelative(int start, int top, int end, int bottom) { 22030 resetResolvedPaddingInternal(); 22031 22032 mUserPaddingStart = start; 22033 mUserPaddingEnd = end; 22034 mLeftPaddingDefined = true; 22035 mRightPaddingDefined = true; 22036 22037 switch(getLayoutDirection()) { 22038 case LAYOUT_DIRECTION_RTL: 22039 mUserPaddingLeftInitial = end; 22040 mUserPaddingRightInitial = start; 22041 internalSetPadding(end, top, start, bottom); 22042 break; 22043 case LAYOUT_DIRECTION_LTR: 22044 default: 22045 mUserPaddingLeftInitial = start; 22046 mUserPaddingRightInitial = end; 22047 internalSetPadding(start, top, end, bottom); 22048 } 22049 } 22050 22051 /** 22052 * Returns the top padding of this view. 22053 * 22054 * @return the top padding in pixels 22055 */ 22056 public int getPaddingTop() { 22057 return mPaddingTop; 22058 } 22059 22060 /** 22061 * Returns the bottom padding of this view. If there are inset and enabled 22062 * scrollbars, this value may include the space required to display the 22063 * scrollbars as well. 22064 * 22065 * @return the bottom padding in pixels 22066 */ 22067 public int getPaddingBottom() { 22068 return mPaddingBottom; 22069 } 22070 22071 /** 22072 * Returns the left padding of this view. If there are inset and enabled 22073 * scrollbars, this value may include the space required to display the 22074 * scrollbars as well. 22075 * 22076 * @return the left padding in pixels 22077 */ 22078 public int getPaddingLeft() { 22079 if (!isPaddingResolved()) { 22080 resolvePadding(); 22081 } 22082 return mPaddingLeft; 22083 } 22084 22085 /** 22086 * Returns the start padding of this view depending on its resolved layout direction. 22087 * If there are inset and enabled scrollbars, this value may include the space 22088 * required to display the scrollbars as well. 22089 * 22090 * @return the start padding in pixels 22091 */ 22092 public int getPaddingStart() { 22093 if (!isPaddingResolved()) { 22094 resolvePadding(); 22095 } 22096 return (getLayoutDirection() == LAYOUT_DIRECTION_RTL) ? 22097 mPaddingRight : mPaddingLeft; 22098 } 22099 22100 /** 22101 * Returns the right padding of this view. If there are inset and enabled 22102 * scrollbars, this value may include the space required to display the 22103 * scrollbars as well. 22104 * 22105 * @return the right padding in pixels 22106 */ 22107 public int getPaddingRight() { 22108 if (!isPaddingResolved()) { 22109 resolvePadding(); 22110 } 22111 return mPaddingRight; 22112 } 22113 22114 /** 22115 * Returns the end padding of this view depending on its resolved layout direction. 22116 * If there are inset and enabled scrollbars, this value may include the space 22117 * required to display the scrollbars as well. 22118 * 22119 * @return the end padding in pixels 22120 */ 22121 public int getPaddingEnd() { 22122 if (!isPaddingResolved()) { 22123 resolvePadding(); 22124 } 22125 return (getLayoutDirection() == LAYOUT_DIRECTION_RTL) ? 22126 mPaddingLeft : mPaddingRight; 22127 } 22128 22129 /** 22130 * Return if the padding has been set through relative values 22131 * {@link #setPaddingRelative(int, int, int, int)} or through 22132 * @attr ref android.R.styleable#View_paddingStart or 22133 * @attr ref android.R.styleable#View_paddingEnd 22134 * 22135 * @return true if the padding is relative or false if it is not. 22136 */ 22137 public boolean isPaddingRelative() { 22138 return (mUserPaddingStart != UNDEFINED_PADDING || mUserPaddingEnd != UNDEFINED_PADDING); 22139 } 22140 22141 Insets computeOpticalInsets() { 22142 return (mBackground == null) ? Insets.NONE : mBackground.getOpticalInsets(); 22143 } 22144 22145 /** 22146 * @hide 22147 */ 22148 public void resetPaddingToInitialValues() { 22149 if (isRtlCompatibilityMode()) { 22150 mPaddingLeft = mUserPaddingLeftInitial; 22151 mPaddingRight = mUserPaddingRightInitial; 22152 return; 22153 } 22154 if (isLayoutRtl()) { 22155 mPaddingLeft = (mUserPaddingEnd >= 0) ? mUserPaddingEnd : mUserPaddingLeftInitial; 22156 mPaddingRight = (mUserPaddingStart >= 0) ? mUserPaddingStart : mUserPaddingRightInitial; 22157 } else { 22158 mPaddingLeft = (mUserPaddingStart >= 0) ? mUserPaddingStart : mUserPaddingLeftInitial; 22159 mPaddingRight = (mUserPaddingEnd >= 0) ? mUserPaddingEnd : mUserPaddingRightInitial; 22160 } 22161 } 22162 22163 /** 22164 * @hide 22165 */ 22166 public Insets getOpticalInsets() { 22167 if (mLayoutInsets == null) { 22168 mLayoutInsets = computeOpticalInsets(); 22169 } 22170 return mLayoutInsets; 22171 } 22172 22173 /** 22174 * Set this view's optical insets. 22175 * 22176 * <p>This method should be treated similarly to setMeasuredDimension and not as a general 22177 * property. Views that compute their own optical insets should call it as part of measurement. 22178 * This method does not request layout. If you are setting optical insets outside of 22179 * measure/layout itself you will want to call requestLayout() yourself. 22180 * </p> 22181 * @hide 22182 */ 22183 public void setOpticalInsets(Insets insets) { 22184 mLayoutInsets = insets; 22185 } 22186 22187 /** 22188 * Changes the selection state of this view. A view can be selected or not. 22189 * Note that selection is not the same as focus. Views are typically 22190 * selected in the context of an AdapterView like ListView or GridView; 22191 * the selected view is the view that is highlighted. 22192 * 22193 * @param selected true if the view must be selected, false otherwise 22194 */ 22195 public void setSelected(boolean selected) { 22196 //noinspection DoubleNegation 22197 if (((mPrivateFlags & PFLAG_SELECTED) != 0) != selected) { 22198 mPrivateFlags = (mPrivateFlags & ~PFLAG_SELECTED) | (selected ? PFLAG_SELECTED : 0); 22199 if (!selected) resetPressedState(); 22200 invalidate(true); 22201 refreshDrawableState(); 22202 dispatchSetSelected(selected); 22203 if (selected) { 22204 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED); 22205 } else { 22206 notifyViewAccessibilityStateChangedIfNeeded( 22207 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 22208 } 22209 } 22210 } 22211 22212 /** 22213 * Dispatch setSelected to all of this View's children. 22214 * 22215 * @see #setSelected(boolean) 22216 * 22217 * @param selected The new selected state 22218 */ 22219 protected void dispatchSetSelected(boolean selected) { 22220 } 22221 22222 /** 22223 * Indicates the selection state of this view. 22224 * 22225 * @return true if the view is selected, false otherwise 22226 */ 22227 @ViewDebug.ExportedProperty 22228 public boolean isSelected() { 22229 return (mPrivateFlags & PFLAG_SELECTED) != 0; 22230 } 22231 22232 /** 22233 * Changes the activated state of this view. A view can be activated or not. 22234 * Note that activation is not the same as selection. Selection is 22235 * a transient property, representing the view (hierarchy) the user is 22236 * currently interacting with. Activation is a longer-term state that the 22237 * user can move views in and out of. For example, in a list view with 22238 * single or multiple selection enabled, the views in the current selection 22239 * set are activated. (Um, yeah, we are deeply sorry about the terminology 22240 * here.) The activated state is propagated down to children of the view it 22241 * is set on. 22242 * 22243 * @param activated true if the view must be activated, false otherwise 22244 */ 22245 public void setActivated(boolean activated) { 22246 //noinspection DoubleNegation 22247 if (((mPrivateFlags & PFLAG_ACTIVATED) != 0) != activated) { 22248 mPrivateFlags = (mPrivateFlags & ~PFLAG_ACTIVATED) | (activated ? PFLAG_ACTIVATED : 0); 22249 invalidate(true); 22250 refreshDrawableState(); 22251 dispatchSetActivated(activated); 22252 } 22253 } 22254 22255 /** 22256 * Dispatch setActivated to all of this View's children. 22257 * 22258 * @see #setActivated(boolean) 22259 * 22260 * @param activated The new activated state 22261 */ 22262 protected void dispatchSetActivated(boolean activated) { 22263 } 22264 22265 /** 22266 * Indicates the activation state of this view. 22267 * 22268 * @return true if the view is activated, false otherwise 22269 */ 22270 @ViewDebug.ExportedProperty 22271 public boolean isActivated() { 22272 return (mPrivateFlags & PFLAG_ACTIVATED) != 0; 22273 } 22274 22275 /** 22276 * Returns the ViewTreeObserver for this view's hierarchy. The view tree 22277 * observer can be used to get notifications when global events, like 22278 * layout, happen. 22279 * 22280 * The returned ViewTreeObserver observer is not guaranteed to remain 22281 * valid for the lifetime of this View. If the caller of this method keeps 22282 * a long-lived reference to ViewTreeObserver, it should always check for 22283 * the return value of {@link ViewTreeObserver#isAlive()}. 22284 * 22285 * @return The ViewTreeObserver for this view's hierarchy. 22286 */ 22287 public ViewTreeObserver getViewTreeObserver() { 22288 if (mAttachInfo != null) { 22289 return mAttachInfo.mTreeObserver; 22290 } 22291 if (mFloatingTreeObserver == null) { 22292 mFloatingTreeObserver = new ViewTreeObserver(mContext); 22293 } 22294 return mFloatingTreeObserver; 22295 } 22296 22297 /** 22298 * <p>Finds the topmost view in the current view hierarchy.</p> 22299 * 22300 * @return the topmost view containing this view 22301 */ 22302 public View getRootView() { 22303 if (mAttachInfo != null) { 22304 final View v = mAttachInfo.mRootView; 22305 if (v != null) { 22306 return v; 22307 } 22308 } 22309 22310 View parent = this; 22311 22312 while (parent.mParent != null && parent.mParent instanceof View) { 22313 parent = (View) parent.mParent; 22314 } 22315 22316 return parent; 22317 } 22318 22319 /** 22320 * Transforms a motion event from view-local coordinates to on-screen 22321 * coordinates. 22322 * 22323 * @param ev the view-local motion event 22324 * @return false if the transformation could not be applied 22325 * @hide 22326 */ 22327 public boolean toGlobalMotionEvent(MotionEvent ev) { 22328 final AttachInfo info = mAttachInfo; 22329 if (info == null) { 22330 return false; 22331 } 22332 22333 final Matrix m = info.mTmpMatrix; 22334 m.set(Matrix.IDENTITY_MATRIX); 22335 transformMatrixToGlobal(m); 22336 ev.transform(m); 22337 return true; 22338 } 22339 22340 /** 22341 * Transforms a motion event from on-screen coordinates to view-local 22342 * coordinates. 22343 * 22344 * @param ev the on-screen motion event 22345 * @return false if the transformation could not be applied 22346 * @hide 22347 */ 22348 public boolean toLocalMotionEvent(MotionEvent ev) { 22349 final AttachInfo info = mAttachInfo; 22350 if (info == null) { 22351 return false; 22352 } 22353 22354 final Matrix m = info.mTmpMatrix; 22355 m.set(Matrix.IDENTITY_MATRIX); 22356 transformMatrixToLocal(m); 22357 ev.transform(m); 22358 return true; 22359 } 22360 22361 /** 22362 * Modifies the input matrix such that it maps view-local coordinates to 22363 * on-screen coordinates. 22364 * 22365 * @param m input matrix to modify 22366 * @hide 22367 */ 22368 public void transformMatrixToGlobal(Matrix m) { 22369 final ViewParent parent = mParent; 22370 if (parent instanceof View) { 22371 final View vp = (View) parent; 22372 vp.transformMatrixToGlobal(m); 22373 m.preTranslate(-vp.mScrollX, -vp.mScrollY); 22374 } else if (parent instanceof ViewRootImpl) { 22375 final ViewRootImpl vr = (ViewRootImpl) parent; 22376 vr.transformMatrixToGlobal(m); 22377 m.preTranslate(0, -vr.mCurScrollY); 22378 } 22379 22380 m.preTranslate(mLeft, mTop); 22381 22382 if (!hasIdentityMatrix()) { 22383 m.preConcat(getMatrix()); 22384 } 22385 } 22386 22387 /** 22388 * Modifies the input matrix such that it maps on-screen coordinates to 22389 * view-local coordinates. 22390 * 22391 * @param m input matrix to modify 22392 * @hide 22393 */ 22394 public void transformMatrixToLocal(Matrix m) { 22395 final ViewParent parent = mParent; 22396 if (parent instanceof View) { 22397 final View vp = (View) parent; 22398 vp.transformMatrixToLocal(m); 22399 m.postTranslate(vp.mScrollX, vp.mScrollY); 22400 } else if (parent instanceof ViewRootImpl) { 22401 final ViewRootImpl vr = (ViewRootImpl) parent; 22402 vr.transformMatrixToLocal(m); 22403 m.postTranslate(0, vr.mCurScrollY); 22404 } 22405 22406 m.postTranslate(-mLeft, -mTop); 22407 22408 if (!hasIdentityMatrix()) { 22409 m.postConcat(getInverseMatrix()); 22410 } 22411 } 22412 22413 /** 22414 * @hide 22415 */ 22416 @ViewDebug.ExportedProperty(category = "layout", indexMapping = { 22417 @ViewDebug.IntToString(from = 0, to = "x"), 22418 @ViewDebug.IntToString(from = 1, to = "y") 22419 }) 22420 public int[] getLocationOnScreen() { 22421 int[] location = new int[2]; 22422 getLocationOnScreen(location); 22423 return location; 22424 } 22425 22426 /** 22427 * <p>Computes the coordinates of this view on the screen. The argument 22428 * must be an array of two integers. After the method returns, the array 22429 * contains the x and y location in that order.</p> 22430 * 22431 * @param outLocation an array of two integers in which to hold the coordinates 22432 */ 22433 public void getLocationOnScreen(@Size(2) int[] outLocation) { 22434 getLocationInWindow(outLocation); 22435 22436 final AttachInfo info = mAttachInfo; 22437 if (info != null) { 22438 outLocation[0] += info.mWindowLeft; 22439 outLocation[1] += info.mWindowTop; 22440 } 22441 } 22442 22443 /** 22444 * <p>Computes the coordinates of this view in its window. The argument 22445 * must be an array of two integers. After the method returns, the array 22446 * contains the x and y location in that order.</p> 22447 * 22448 * @param outLocation an array of two integers in which to hold the coordinates 22449 */ 22450 public void getLocationInWindow(@Size(2) int[] outLocation) { 22451 if (outLocation == null || outLocation.length < 2) { 22452 throw new IllegalArgumentException("outLocation must be an array of two integers"); 22453 } 22454 22455 outLocation[0] = 0; 22456 outLocation[1] = 0; 22457 22458 transformFromViewToWindowSpace(outLocation); 22459 } 22460 22461 /** @hide */ 22462 public void transformFromViewToWindowSpace(@Size(2) int[] inOutLocation) { 22463 if (inOutLocation == null || inOutLocation.length < 2) { 22464 throw new IllegalArgumentException("inOutLocation must be an array of two integers"); 22465 } 22466 22467 if (mAttachInfo == null) { 22468 // When the view is not attached to a window, this method does not make sense 22469 inOutLocation[0] = inOutLocation[1] = 0; 22470 return; 22471 } 22472 22473 float position[] = mAttachInfo.mTmpTransformLocation; 22474 position[0] = inOutLocation[0]; 22475 position[1] = inOutLocation[1]; 22476 22477 if (!hasIdentityMatrix()) { 22478 getMatrix().mapPoints(position); 22479 } 22480 22481 position[0] += mLeft; 22482 position[1] += mTop; 22483 22484 ViewParent viewParent = mParent; 22485 while (viewParent instanceof View) { 22486 final View view = (View) viewParent; 22487 22488 position[0] -= view.mScrollX; 22489 position[1] -= view.mScrollY; 22490 22491 if (!view.hasIdentityMatrix()) { 22492 view.getMatrix().mapPoints(position); 22493 } 22494 22495 position[0] += view.mLeft; 22496 position[1] += view.mTop; 22497 22498 viewParent = view.mParent; 22499 } 22500 22501 if (viewParent instanceof ViewRootImpl) { 22502 // *cough* 22503 final ViewRootImpl vr = (ViewRootImpl) viewParent; 22504 position[1] -= vr.mCurScrollY; 22505 } 22506 22507 inOutLocation[0] = Math.round(position[0]); 22508 inOutLocation[1] = Math.round(position[1]); 22509 } 22510 22511 /** 22512 * @param id the id of the view to be found 22513 * @return the view of the specified id, null if cannot be found 22514 * @hide 22515 */ 22516 protected <T extends View> T findViewTraversal(@IdRes int id) { 22517 if (id == mID) { 22518 return (T) this; 22519 } 22520 return null; 22521 } 22522 22523 /** 22524 * @param tag the tag of the view to be found 22525 * @return the view of specified tag, null if cannot be found 22526 * @hide 22527 */ 22528 protected <T extends View> T findViewWithTagTraversal(Object tag) { 22529 if (tag != null && tag.equals(mTag)) { 22530 return (T) this; 22531 } 22532 return null; 22533 } 22534 22535 /** 22536 * @param predicate The predicate to evaluate. 22537 * @param childToSkip If not null, ignores this child during the recursive traversal. 22538 * @return The first view that matches the predicate or null. 22539 * @hide 22540 */ 22541 protected <T extends View> T findViewByPredicateTraversal(Predicate<View> predicate, 22542 View childToSkip) { 22543 if (predicate.test(this)) { 22544 return (T) this; 22545 } 22546 return null; 22547 } 22548 22549 /** 22550 * Finds the first descendant view with the given ID, the view itself if 22551 * the ID matches {@link #getId()}, or {@code null} if the ID is invalid 22552 * (< 0) or there is no matching view in the hierarchy. 22553 * <p> 22554 * <strong>Note:</strong> In most cases -- depending on compiler support -- 22555 * the resulting view is automatically cast to the target class type. If 22556 * the target class type is unconstrained, an explicit cast may be 22557 * necessary. 22558 * 22559 * @param id the ID to search for 22560 * @return a view with given ID if found, or {@code null} otherwise 22561 * @see View#requireViewById(int) 22562 */ 22563 @Nullable 22564 public final <T extends View> T findViewById(@IdRes int id) { 22565 if (id == NO_ID) { 22566 return null; 22567 } 22568 return findViewTraversal(id); 22569 } 22570 22571 /** 22572 * Finds the first descendant view with the given ID, the view itself if the ID matches 22573 * {@link #getId()}, or throws an IllegalArgumentException if the ID is invalid or there is no 22574 * matching view in the hierarchy. 22575 * <p> 22576 * <strong>Note:</strong> In most cases -- depending on compiler support -- 22577 * the resulting view is automatically cast to the target class type. If 22578 * the target class type is unconstrained, an explicit cast may be 22579 * necessary. 22580 * 22581 * @param id the ID to search for 22582 * @return a view with given ID 22583 * @see View#findViewById(int) 22584 */ 22585 @NonNull 22586 public final <T extends View> T requireViewById(@IdRes int id) { 22587 T view = findViewById(id); 22588 if (view == null) { 22589 throw new IllegalArgumentException("ID does not reference a View inside this View"); 22590 } 22591 return view; 22592 } 22593 22594 /** 22595 * Finds a view by its unuque and stable accessibility id. 22596 * 22597 * @param accessibilityId The searched accessibility id. 22598 * @return The found view. 22599 */ 22600 final <T extends View> T findViewByAccessibilityId(int accessibilityId) { 22601 if (accessibilityId < 0) { 22602 return null; 22603 } 22604 T view = findViewByAccessibilityIdTraversal(accessibilityId); 22605 if (view != null) { 22606 return view.includeForAccessibility() ? view : null; 22607 } 22608 return null; 22609 } 22610 22611 /** 22612 * Performs the traversal to find a view by its unique and stable accessibility id. 22613 * 22614 * <strong>Note:</strong>This method does not stop at the root namespace 22615 * boundary since the user can touch the screen at an arbitrary location 22616 * potentially crossing the root namespace boundary which will send an 22617 * accessibility event to accessibility services and they should be able 22618 * to obtain the event source. Also accessibility ids are guaranteed to be 22619 * unique in the window. 22620 * 22621 * @param accessibilityId The accessibility id. 22622 * @return The found view. 22623 * @hide 22624 */ 22625 public <T extends View> T findViewByAccessibilityIdTraversal(int accessibilityId) { 22626 if (getAccessibilityViewId() == accessibilityId) { 22627 return (T) this; 22628 } 22629 return null; 22630 } 22631 22632 /** 22633 * Performs the traversal to find a view by its autofill id. 22634 * 22635 * <strong>Note:</strong>This method does not stop at the root namespace 22636 * boundary. 22637 * 22638 * @param autofillId The autofill id. 22639 * @return The found view. 22640 * @hide 22641 */ 22642 public <T extends View> T findViewByAutofillIdTraversal(int autofillId) { 22643 if (getAutofillViewId() == autofillId) { 22644 return (T) this; 22645 } 22646 return null; 22647 } 22648 22649 /** 22650 * Look for a child view with the given tag. If this view has the given 22651 * tag, return this view. 22652 * 22653 * @param tag The tag to search for, using "tag.equals(getTag())". 22654 * @return The View that has the given tag in the hierarchy or null 22655 */ 22656 public final <T extends View> T findViewWithTag(Object tag) { 22657 if (tag == null) { 22658 return null; 22659 } 22660 return findViewWithTagTraversal(tag); 22661 } 22662 22663 /** 22664 * Look for a child view that matches the specified predicate. 22665 * If this view matches the predicate, return this view. 22666 * 22667 * @param predicate The predicate to evaluate. 22668 * @return The first view that matches the predicate or null. 22669 * @hide 22670 */ 22671 public final <T extends View> T findViewByPredicate(Predicate<View> predicate) { 22672 return findViewByPredicateTraversal(predicate, null); 22673 } 22674 22675 /** 22676 * Look for a child view that matches the specified predicate, 22677 * starting with the specified view and its descendents and then 22678 * recusively searching the ancestors and siblings of that view 22679 * until this view is reached. 22680 * 22681 * This method is useful in cases where the predicate does not match 22682 * a single unique view (perhaps multiple views use the same id) 22683 * and we are trying to find the view that is "closest" in scope to the 22684 * starting view. 22685 * 22686 * @param start The view to start from. 22687 * @param predicate The predicate to evaluate. 22688 * @return The first view that matches the predicate or null. 22689 * @hide 22690 */ 22691 public final <T extends View> T findViewByPredicateInsideOut( 22692 View start, Predicate<View> predicate) { 22693 View childToSkip = null; 22694 for (;;) { 22695 T view = start.findViewByPredicateTraversal(predicate, childToSkip); 22696 if (view != null || start == this) { 22697 return view; 22698 } 22699 22700 ViewParent parent = start.getParent(); 22701 if (parent == null || !(parent instanceof View)) { 22702 return null; 22703 } 22704 22705 childToSkip = start; 22706 start = (View) parent; 22707 } 22708 } 22709 22710 /** 22711 * Sets the identifier for this view. The identifier does not have to be 22712 * unique in this view's hierarchy. The identifier should be a positive 22713 * number. 22714 * 22715 * @see #NO_ID 22716 * @see #getId() 22717 * @see #findViewById(int) 22718 * 22719 * @param id a number used to identify the view 22720 * 22721 * @attr ref android.R.styleable#View_id 22722 */ 22723 public void setId(@IdRes int id) { 22724 mID = id; 22725 if (mID == View.NO_ID && mLabelForId != View.NO_ID) { 22726 mID = generateViewId(); 22727 } 22728 } 22729 22730 /** 22731 * {@hide} 22732 * 22733 * @param isRoot true if the view belongs to the root namespace, false 22734 * otherwise 22735 */ 22736 public void setIsRootNamespace(boolean isRoot) { 22737 if (isRoot) { 22738 mPrivateFlags |= PFLAG_IS_ROOT_NAMESPACE; 22739 } else { 22740 mPrivateFlags &= ~PFLAG_IS_ROOT_NAMESPACE; 22741 } 22742 } 22743 22744 /** 22745 * {@hide} 22746 * 22747 * @return true if the view belongs to the root namespace, false otherwise 22748 */ 22749 public boolean isRootNamespace() { 22750 return (mPrivateFlags&PFLAG_IS_ROOT_NAMESPACE) != 0; 22751 } 22752 22753 /** 22754 * Returns this view's identifier. 22755 * 22756 * @return a positive integer used to identify the view or {@link #NO_ID} 22757 * if the view has no ID 22758 * 22759 * @see #setId(int) 22760 * @see #findViewById(int) 22761 * @attr ref android.R.styleable#View_id 22762 */ 22763 @IdRes 22764 @ViewDebug.CapturedViewProperty 22765 public int getId() { 22766 return mID; 22767 } 22768 22769 /** 22770 * Returns this view's tag. 22771 * 22772 * @return the Object stored in this view as a tag, or {@code null} if not 22773 * set 22774 * 22775 * @see #setTag(Object) 22776 * @see #getTag(int) 22777 */ 22778 @ViewDebug.ExportedProperty 22779 public Object getTag() { 22780 return mTag; 22781 } 22782 22783 /** 22784 * Sets the tag associated with this view. A tag can be used to mark 22785 * a view in its hierarchy and does not have to be unique within the 22786 * hierarchy. Tags can also be used to store data within a view without 22787 * resorting to another data structure. 22788 * 22789 * @param tag an Object to tag the view with 22790 * 22791 * @see #getTag() 22792 * @see #setTag(int, Object) 22793 */ 22794 public void setTag(final Object tag) { 22795 mTag = tag; 22796 } 22797 22798 /** 22799 * Returns the tag associated with this view and the specified key. 22800 * 22801 * @param key The key identifying the tag 22802 * 22803 * @return the Object stored in this view as a tag, or {@code null} if not 22804 * set 22805 * 22806 * @see #setTag(int, Object) 22807 * @see #getTag() 22808 */ 22809 public Object getTag(int key) { 22810 if (mKeyedTags != null) return mKeyedTags.get(key); 22811 return null; 22812 } 22813 22814 /** 22815 * Sets a tag associated with this view and a key. A tag can be used 22816 * to mark a view in its hierarchy and does not have to be unique within 22817 * the hierarchy. Tags can also be used to store data within a view 22818 * without resorting to another data structure. 22819 * 22820 * The specified key should be an id declared in the resources of the 22821 * application to ensure it is unique (see the <a 22822 * href="{@docRoot}guide/topics/resources/more-resources.html#Id">ID resource type</a>). 22823 * Keys identified as belonging to 22824 * the Android framework or not associated with any package will cause 22825 * an {@link IllegalArgumentException} to be thrown. 22826 * 22827 * @param key The key identifying the tag 22828 * @param tag An Object to tag the view with 22829 * 22830 * @throws IllegalArgumentException If they specified key is not valid 22831 * 22832 * @see #setTag(Object) 22833 * @see #getTag(int) 22834 */ 22835 public void setTag(int key, final Object tag) { 22836 // If the package id is 0x00 or 0x01, it's either an undefined package 22837 // or a framework id 22838 if ((key >>> 24) < 2) { 22839 throw new IllegalArgumentException("The key must be an application-specific " 22840 + "resource id."); 22841 } 22842 22843 setKeyedTag(key, tag); 22844 } 22845 22846 /** 22847 * Variation of {@link #setTag(int, Object)} that enforces the key to be a 22848 * framework id. 22849 * 22850 * @hide 22851 */ 22852 public void setTagInternal(int key, Object tag) { 22853 if ((key >>> 24) != 0x1) { 22854 throw new IllegalArgumentException("The key must be a framework-specific " 22855 + "resource id."); 22856 } 22857 22858 setKeyedTag(key, tag); 22859 } 22860 22861 private void setKeyedTag(int key, Object tag) { 22862 if (mKeyedTags == null) { 22863 mKeyedTags = new SparseArray<Object>(2); 22864 } 22865 22866 mKeyedTags.put(key, tag); 22867 } 22868 22869 /** 22870 * Prints information about this view in the log output, with the tag 22871 * {@link #VIEW_LOG_TAG}. 22872 * 22873 * @hide 22874 */ 22875 public void debug() { 22876 debug(0); 22877 } 22878 22879 /** 22880 * Prints information about this view in the log output, with the tag 22881 * {@link #VIEW_LOG_TAG}. Each line in the output is preceded with an 22882 * indentation defined by the <code>depth</code>. 22883 * 22884 * @param depth the indentation level 22885 * 22886 * @hide 22887 */ 22888 protected void debug(int depth) { 22889 String output = debugIndent(depth - 1); 22890 22891 output += "+ " + this; 22892 int id = getId(); 22893 if (id != -1) { 22894 output += " (id=" + id + ")"; 22895 } 22896 Object tag = getTag(); 22897 if (tag != null) { 22898 output += " (tag=" + tag + ")"; 22899 } 22900 Log.d(VIEW_LOG_TAG, output); 22901 22902 if ((mPrivateFlags & PFLAG_FOCUSED) != 0) { 22903 output = debugIndent(depth) + " FOCUSED"; 22904 Log.d(VIEW_LOG_TAG, output); 22905 } 22906 22907 output = debugIndent(depth); 22908 output += "frame={" + mLeft + ", " + mTop + ", " + mRight 22909 + ", " + mBottom + "} scroll={" + mScrollX + ", " + mScrollY 22910 + "} "; 22911 Log.d(VIEW_LOG_TAG, output); 22912 22913 if (mPaddingLeft != 0 || mPaddingTop != 0 || mPaddingRight != 0 22914 || mPaddingBottom != 0) { 22915 output = debugIndent(depth); 22916 output += "padding={" + mPaddingLeft + ", " + mPaddingTop 22917 + ", " + mPaddingRight + ", " + mPaddingBottom + "}"; 22918 Log.d(VIEW_LOG_TAG, output); 22919 } 22920 22921 output = debugIndent(depth); 22922 output += "mMeasureWidth=" + mMeasuredWidth + 22923 " mMeasureHeight=" + mMeasuredHeight; 22924 Log.d(VIEW_LOG_TAG, output); 22925 22926 output = debugIndent(depth); 22927 if (mLayoutParams == null) { 22928 output += "BAD! no layout params"; 22929 } else { 22930 output = mLayoutParams.debug(output); 22931 } 22932 Log.d(VIEW_LOG_TAG, output); 22933 22934 output = debugIndent(depth); 22935 output += "flags={"; 22936 output += View.printFlags(mViewFlags); 22937 output += "}"; 22938 Log.d(VIEW_LOG_TAG, output); 22939 22940 output = debugIndent(depth); 22941 output += "privateFlags={"; 22942 output += View.printPrivateFlags(mPrivateFlags); 22943 output += "}"; 22944 Log.d(VIEW_LOG_TAG, output); 22945 } 22946 22947 /** 22948 * Creates a string of whitespaces used for indentation. 22949 * 22950 * @param depth the indentation level 22951 * @return a String containing (depth * 2 + 3) * 2 white spaces 22952 * 22953 * @hide 22954 */ 22955 protected static String debugIndent(int depth) { 22956 StringBuilder spaces = new StringBuilder((depth * 2 + 3) * 2); 22957 for (int i = 0; i < (depth * 2) + 3; i++) { 22958 spaces.append(' ').append(' '); 22959 } 22960 return spaces.toString(); 22961 } 22962 22963 /** 22964 * <p>Return the offset of the widget's text baseline from the widget's top 22965 * boundary. If this widget does not support baseline alignment, this 22966 * method returns -1. </p> 22967 * 22968 * @return the offset of the baseline within the widget's bounds or -1 22969 * if baseline alignment is not supported 22970 */ 22971 @ViewDebug.ExportedProperty(category = "layout") 22972 public int getBaseline() { 22973 return -1; 22974 } 22975 22976 /** 22977 * Returns whether the view hierarchy is currently undergoing a layout pass. This 22978 * information is useful to avoid situations such as calling {@link #requestLayout()} during 22979 * a layout pass. 22980 * 22981 * @return whether the view hierarchy is currently undergoing a layout pass 22982 */ 22983 public boolean isInLayout() { 22984 ViewRootImpl viewRoot = getViewRootImpl(); 22985 return (viewRoot != null && viewRoot.isInLayout()); 22986 } 22987 22988 /** 22989 * Call this when something has changed which has invalidated the 22990 * layout of this view. This will schedule a layout pass of the view 22991 * tree. This should not be called while the view hierarchy is currently in a layout 22992 * pass ({@link #isInLayout()}. If layout is happening, the request may be honored at the 22993 * end of the current layout pass (and then layout will run again) or after the current 22994 * frame is drawn and the next layout occurs. 22995 * 22996 * <p>Subclasses which override this method should call the superclass method to 22997 * handle possible request-during-layout errors correctly.</p> 22998 */ 22999 @CallSuper 23000 public void requestLayout() { 23001 if (mMeasureCache != null) mMeasureCache.clear(); 23002 23003 if (mAttachInfo != null && mAttachInfo.mViewRequestingLayout == null) { 23004 // Only trigger request-during-layout logic if this is the view requesting it, 23005 // not the views in its parent hierarchy 23006 ViewRootImpl viewRoot = getViewRootImpl(); 23007 if (viewRoot != null && viewRoot.isInLayout()) { 23008 if (!viewRoot.requestLayoutDuringLayout(this)) { 23009 return; 23010 } 23011 } 23012 mAttachInfo.mViewRequestingLayout = this; 23013 } 23014 23015 mPrivateFlags |= PFLAG_FORCE_LAYOUT; 23016 mPrivateFlags |= PFLAG_INVALIDATED; 23017 23018 if (mParent != null && !mParent.isLayoutRequested()) { 23019 mParent.requestLayout(); 23020 } 23021 if (mAttachInfo != null && mAttachInfo.mViewRequestingLayout == this) { 23022 mAttachInfo.mViewRequestingLayout = null; 23023 } 23024 } 23025 23026 /** 23027 * Forces this view to be laid out during the next layout pass. 23028 * This method does not call requestLayout() or forceLayout() 23029 * on the parent. 23030 */ 23031 public void forceLayout() { 23032 if (mMeasureCache != null) mMeasureCache.clear(); 23033 23034 mPrivateFlags |= PFLAG_FORCE_LAYOUT; 23035 mPrivateFlags |= PFLAG_INVALIDATED; 23036 } 23037 23038 /** 23039 * <p> 23040 * This is called to find out how big a view should be. The parent 23041 * supplies constraint information in the width and height parameters. 23042 * </p> 23043 * 23044 * <p> 23045 * The actual measurement work of a view is performed in 23046 * {@link #onMeasure(int, int)}, called by this method. Therefore, only 23047 * {@link #onMeasure(int, int)} can and must be overridden by subclasses. 23048 * </p> 23049 * 23050 * 23051 * @param widthMeasureSpec Horizontal space requirements as imposed by the 23052 * parent 23053 * @param heightMeasureSpec Vertical space requirements as imposed by the 23054 * parent 23055 * 23056 * @see #onMeasure(int, int) 23057 */ 23058 public final void measure(int widthMeasureSpec, int heightMeasureSpec) { 23059 boolean optical = isLayoutModeOptical(this); 23060 if (optical != isLayoutModeOptical(mParent)) { 23061 Insets insets = getOpticalInsets(); 23062 int oWidth = insets.left + insets.right; 23063 int oHeight = insets.top + insets.bottom; 23064 widthMeasureSpec = MeasureSpec.adjust(widthMeasureSpec, optical ? -oWidth : oWidth); 23065 heightMeasureSpec = MeasureSpec.adjust(heightMeasureSpec, optical ? -oHeight : oHeight); 23066 } 23067 23068 // Suppress sign extension for the low bytes 23069 long key = (long) widthMeasureSpec << 32 | (long) heightMeasureSpec & 0xffffffffL; 23070 if (mMeasureCache == null) mMeasureCache = new LongSparseLongArray(2); 23071 23072 final boolean forceLayout = (mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT; 23073 23074 // Optimize layout by avoiding an extra EXACTLY pass when the view is 23075 // already measured as the correct size. In API 23 and below, this 23076 // extra pass is required to make LinearLayout re-distribute weight. 23077 final boolean specChanged = widthMeasureSpec != mOldWidthMeasureSpec 23078 || heightMeasureSpec != mOldHeightMeasureSpec; 23079 final boolean isSpecExactly = MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY 23080 && MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.EXACTLY; 23081 final boolean matchesSpecSize = getMeasuredWidth() == MeasureSpec.getSize(widthMeasureSpec) 23082 && getMeasuredHeight() == MeasureSpec.getSize(heightMeasureSpec); 23083 final boolean needsLayout = specChanged 23084 && (sAlwaysRemeasureExactly || !isSpecExactly || !matchesSpecSize); 23085 23086 if (forceLayout || needsLayout) { 23087 // first clears the measured dimension flag 23088 mPrivateFlags &= ~PFLAG_MEASURED_DIMENSION_SET; 23089 23090 resolveRtlPropertiesIfNeeded(); 23091 23092 int cacheIndex = forceLayout ? -1 : mMeasureCache.indexOfKey(key); 23093 if (cacheIndex < 0 || sIgnoreMeasureCache) { 23094 // measure ourselves, this should set the measured dimension flag back 23095 onMeasure(widthMeasureSpec, heightMeasureSpec); 23096 mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT; 23097 } else { 23098 long value = mMeasureCache.valueAt(cacheIndex); 23099 // Casting a long to int drops the high 32 bits, no mask needed 23100 setMeasuredDimensionRaw((int) (value >> 32), (int) value); 23101 mPrivateFlags3 |= PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT; 23102 } 23103 23104 // flag not set, setMeasuredDimension() was not invoked, we raise 23105 // an exception to warn the developer 23106 if ((mPrivateFlags & PFLAG_MEASURED_DIMENSION_SET) != PFLAG_MEASURED_DIMENSION_SET) { 23107 throw new IllegalStateException("View with id " + getId() + ": " 23108 + getClass().getName() + "#onMeasure() did not set the" 23109 + " measured dimension by calling" 23110 + " setMeasuredDimension()"); 23111 } 23112 23113 mPrivateFlags |= PFLAG_LAYOUT_REQUIRED; 23114 } 23115 23116 mOldWidthMeasureSpec = widthMeasureSpec; 23117 mOldHeightMeasureSpec = heightMeasureSpec; 23118 23119 mMeasureCache.put(key, ((long) mMeasuredWidth) << 32 | 23120 (long) mMeasuredHeight & 0xffffffffL); // suppress sign extension 23121 } 23122 23123 /** 23124 * <p> 23125 * Measure the view and its content to determine the measured width and the 23126 * measured height. This method is invoked by {@link #measure(int, int)} and 23127 * should be overridden by subclasses to provide accurate and efficient 23128 * measurement of their contents. 23129 * </p> 23130 * 23131 * <p> 23132 * <strong>CONTRACT:</strong> When overriding this method, you 23133 * <em>must</em> call {@link #setMeasuredDimension(int, int)} to store the 23134 * measured width and height of this view. Failure to do so will trigger an 23135 * <code>IllegalStateException</code>, thrown by 23136 * {@link #measure(int, int)}. Calling the superclass' 23137 * {@link #onMeasure(int, int)} is a valid use. 23138 * </p> 23139 * 23140 * <p> 23141 * The base class implementation of measure defaults to the background size, 23142 * unless a larger size is allowed by the MeasureSpec. Subclasses should 23143 * override {@link #onMeasure(int, int)} to provide better measurements of 23144 * their content. 23145 * </p> 23146 * 23147 * <p> 23148 * If this method is overridden, it is the subclass's responsibility to make 23149 * sure the measured height and width are at least the view's minimum height 23150 * and width ({@link #getSuggestedMinimumHeight()} and 23151 * {@link #getSuggestedMinimumWidth()}). 23152 * </p> 23153 * 23154 * @param widthMeasureSpec horizontal space requirements as imposed by the parent. 23155 * The requirements are encoded with 23156 * {@link android.view.View.MeasureSpec}. 23157 * @param heightMeasureSpec vertical space requirements as imposed by the parent. 23158 * The requirements are encoded with 23159 * {@link android.view.View.MeasureSpec}. 23160 * 23161 * @see #getMeasuredWidth() 23162 * @see #getMeasuredHeight() 23163 * @see #setMeasuredDimension(int, int) 23164 * @see #getSuggestedMinimumHeight() 23165 * @see #getSuggestedMinimumWidth() 23166 * @see android.view.View.MeasureSpec#getMode(int) 23167 * @see android.view.View.MeasureSpec#getSize(int) 23168 */ 23169 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 23170 setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec), 23171 getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec)); 23172 } 23173 23174 /** 23175 * <p>This method must be called by {@link #onMeasure(int, int)} to store the 23176 * measured width and measured height. Failing to do so will trigger an 23177 * exception at measurement time.</p> 23178 * 23179 * @param measuredWidth The measured width of this view. May be a complex 23180 * bit mask as defined by {@link #MEASURED_SIZE_MASK} and 23181 * {@link #MEASURED_STATE_TOO_SMALL}. 23182 * @param measuredHeight The measured height of this view. May be a complex 23183 * bit mask as defined by {@link #MEASURED_SIZE_MASK} and 23184 * {@link #MEASURED_STATE_TOO_SMALL}. 23185 */ 23186 protected final void setMeasuredDimension(int measuredWidth, int measuredHeight) { 23187 boolean optical = isLayoutModeOptical(this); 23188 if (optical != isLayoutModeOptical(mParent)) { 23189 Insets insets = getOpticalInsets(); 23190 int opticalWidth = insets.left + insets.right; 23191 int opticalHeight = insets.top + insets.bottom; 23192 23193 measuredWidth += optical ? opticalWidth : -opticalWidth; 23194 measuredHeight += optical ? opticalHeight : -opticalHeight; 23195 } 23196 setMeasuredDimensionRaw(measuredWidth, measuredHeight); 23197 } 23198 23199 /** 23200 * Sets the measured dimension without extra processing for things like optical bounds. 23201 * Useful for reapplying consistent values that have already been cooked with adjustments 23202 * for optical bounds, etc. such as those from the measurement cache. 23203 * 23204 * @param measuredWidth The measured width of this view. May be a complex 23205 * bit mask as defined by {@link #MEASURED_SIZE_MASK} and 23206 * {@link #MEASURED_STATE_TOO_SMALL}. 23207 * @param measuredHeight The measured height of this view. May be a complex 23208 * bit mask as defined by {@link #MEASURED_SIZE_MASK} and 23209 * {@link #MEASURED_STATE_TOO_SMALL}. 23210 */ 23211 private void setMeasuredDimensionRaw(int measuredWidth, int measuredHeight) { 23212 mMeasuredWidth = measuredWidth; 23213 mMeasuredHeight = measuredHeight; 23214 23215 mPrivateFlags |= PFLAG_MEASURED_DIMENSION_SET; 23216 } 23217 23218 /** 23219 * Merge two states as returned by {@link #getMeasuredState()}. 23220 * @param curState The current state as returned from a view or the result 23221 * of combining multiple views. 23222 * @param newState The new view state to combine. 23223 * @return Returns a new integer reflecting the combination of the two 23224 * states. 23225 */ 23226 public static int combineMeasuredStates(int curState, int newState) { 23227 return curState | newState; 23228 } 23229 23230 /** 23231 * Version of {@link #resolveSizeAndState(int, int, int)} 23232 * returning only the {@link #MEASURED_SIZE_MASK} bits of the result. 23233 */ 23234 public static int resolveSize(int size, int measureSpec) { 23235 return resolveSizeAndState(size, measureSpec, 0) & MEASURED_SIZE_MASK; 23236 } 23237 23238 /** 23239 * Utility to reconcile a desired size and state, with constraints imposed 23240 * by a MeasureSpec. Will take the desired size, unless a different size 23241 * is imposed by the constraints. The returned value is a compound integer, 23242 * with the resolved size in the {@link #MEASURED_SIZE_MASK} bits and 23243 * optionally the bit {@link #MEASURED_STATE_TOO_SMALL} set if the 23244 * resulting size is smaller than the size the view wants to be. 23245 * 23246 * @param size How big the view wants to be. 23247 * @param measureSpec Constraints imposed by the parent. 23248 * @param childMeasuredState Size information bit mask for the view's 23249 * children. 23250 * @return Size information bit mask as defined by 23251 * {@link #MEASURED_SIZE_MASK} and 23252 * {@link #MEASURED_STATE_TOO_SMALL}. 23253 */ 23254 public static int resolveSizeAndState(int size, int measureSpec, int childMeasuredState) { 23255 final int specMode = MeasureSpec.getMode(measureSpec); 23256 final int specSize = MeasureSpec.getSize(measureSpec); 23257 final int result; 23258 switch (specMode) { 23259 case MeasureSpec.AT_MOST: 23260 if (specSize < size) { 23261 result = specSize | MEASURED_STATE_TOO_SMALL; 23262 } else { 23263 result = size; 23264 } 23265 break; 23266 case MeasureSpec.EXACTLY: 23267 result = specSize; 23268 break; 23269 case MeasureSpec.UNSPECIFIED: 23270 default: 23271 result = size; 23272 } 23273 return result | (childMeasuredState & MEASURED_STATE_MASK); 23274 } 23275 23276 /** 23277 * Utility to return a default size. Uses the supplied size if the 23278 * MeasureSpec imposed no constraints. Will get larger if allowed 23279 * by the MeasureSpec. 23280 * 23281 * @param size Default size for this view 23282 * @param measureSpec Constraints imposed by the parent 23283 * @return The size this view should be. 23284 */ 23285 public static int getDefaultSize(int size, int measureSpec) { 23286 int result = size; 23287 int specMode = MeasureSpec.getMode(measureSpec); 23288 int specSize = MeasureSpec.getSize(measureSpec); 23289 23290 switch (specMode) { 23291 case MeasureSpec.UNSPECIFIED: 23292 result = size; 23293 break; 23294 case MeasureSpec.AT_MOST: 23295 case MeasureSpec.EXACTLY: 23296 result = specSize; 23297 break; 23298 } 23299 return result; 23300 } 23301 23302 /** 23303 * Returns the suggested minimum height that the view should use. This 23304 * returns the maximum of the view's minimum height 23305 * and the background's minimum height 23306 * ({@link android.graphics.drawable.Drawable#getMinimumHeight()}). 23307 * <p> 23308 * When being used in {@link #onMeasure(int, int)}, the caller should still 23309 * ensure the returned height is within the requirements of the parent. 23310 * 23311 * @return The suggested minimum height of the view. 23312 */ 23313 protected int getSuggestedMinimumHeight() { 23314 return (mBackground == null) ? mMinHeight : max(mMinHeight, mBackground.getMinimumHeight()); 23315 23316 } 23317 23318 /** 23319 * Returns the suggested minimum width that the view should use. This 23320 * returns the maximum of the view's minimum width 23321 * and the background's minimum width 23322 * ({@link android.graphics.drawable.Drawable#getMinimumWidth()}). 23323 * <p> 23324 * When being used in {@link #onMeasure(int, int)}, the caller should still 23325 * ensure the returned width is within the requirements of the parent. 23326 * 23327 * @return The suggested minimum width of the view. 23328 */ 23329 protected int getSuggestedMinimumWidth() { 23330 return (mBackground == null) ? mMinWidth : max(mMinWidth, mBackground.getMinimumWidth()); 23331 } 23332 23333 /** 23334 * Returns the minimum height of the view. 23335 * 23336 * @return the minimum height the view will try to be, in pixels 23337 * 23338 * @see #setMinimumHeight(int) 23339 * 23340 * @attr ref android.R.styleable#View_minHeight 23341 */ 23342 public int getMinimumHeight() { 23343 return mMinHeight; 23344 } 23345 23346 /** 23347 * Sets the minimum height of the view. It is not guaranteed the view will 23348 * be able to achieve this minimum height (for example, if its parent layout 23349 * constrains it with less available height). 23350 * 23351 * @param minHeight The minimum height the view will try to be, in pixels 23352 * 23353 * @see #getMinimumHeight() 23354 * 23355 * @attr ref android.R.styleable#View_minHeight 23356 */ 23357 @RemotableViewMethod 23358 public void setMinimumHeight(int minHeight) { 23359 mMinHeight = minHeight; 23360 requestLayout(); 23361 } 23362 23363 /** 23364 * Returns the minimum width of the view. 23365 * 23366 * @return the minimum width the view will try to be, in pixels 23367 * 23368 * @see #setMinimumWidth(int) 23369 * 23370 * @attr ref android.R.styleable#View_minWidth 23371 */ 23372 public int getMinimumWidth() { 23373 return mMinWidth; 23374 } 23375 23376 /** 23377 * Sets the minimum width of the view. It is not guaranteed the view will 23378 * be able to achieve this minimum width (for example, if its parent layout 23379 * constrains it with less available width). 23380 * 23381 * @param minWidth The minimum width the view will try to be, in pixels 23382 * 23383 * @see #getMinimumWidth() 23384 * 23385 * @attr ref android.R.styleable#View_minWidth 23386 */ 23387 public void setMinimumWidth(int minWidth) { 23388 mMinWidth = minWidth; 23389 requestLayout(); 23390 23391 } 23392 23393 /** 23394 * Get the animation currently associated with this view. 23395 * 23396 * @return The animation that is currently playing or 23397 * scheduled to play for this view. 23398 */ 23399 public Animation getAnimation() { 23400 return mCurrentAnimation; 23401 } 23402 23403 /** 23404 * Start the specified animation now. 23405 * 23406 * @param animation the animation to start now 23407 */ 23408 public void startAnimation(Animation animation) { 23409 animation.setStartTime(Animation.START_ON_FIRST_FRAME); 23410 setAnimation(animation); 23411 invalidateParentCaches(); 23412 invalidate(true); 23413 } 23414 23415 /** 23416 * Cancels any animations for this view. 23417 */ 23418 public void clearAnimation() { 23419 if (mCurrentAnimation != null) { 23420 mCurrentAnimation.detach(); 23421 } 23422 mCurrentAnimation = null; 23423 invalidateParentIfNeeded(); 23424 } 23425 23426 /** 23427 * Sets the next animation to play for this view. 23428 * If you want the animation to play immediately, use 23429 * {@link #startAnimation(android.view.animation.Animation)} instead. 23430 * This method provides allows fine-grained 23431 * control over the start time and invalidation, but you 23432 * must make sure that 1) the animation has a start time set, and 23433 * 2) the view's parent (which controls animations on its children) 23434 * will be invalidated when the animation is supposed to 23435 * start. 23436 * 23437 * @param animation The next animation, or null. 23438 */ 23439 public void setAnimation(Animation animation) { 23440 mCurrentAnimation = animation; 23441 23442 if (animation != null) { 23443 // If the screen is off assume the animation start time is now instead of 23444 // the next frame we draw. Keeping the START_ON_FIRST_FRAME start time 23445 // would cause the animation to start when the screen turns back on 23446 if (mAttachInfo != null && mAttachInfo.mDisplayState == Display.STATE_OFF 23447 && animation.getStartTime() == Animation.START_ON_FIRST_FRAME) { 23448 animation.setStartTime(AnimationUtils.currentAnimationTimeMillis()); 23449 } 23450 animation.reset(); 23451 } 23452 } 23453 23454 /** 23455 * Invoked by a parent ViewGroup to notify the start of the animation 23456 * currently associated with this view. If you override this method, 23457 * always call super.onAnimationStart(); 23458 * 23459 * @see #setAnimation(android.view.animation.Animation) 23460 * @see #getAnimation() 23461 */ 23462 @CallSuper 23463 protected void onAnimationStart() { 23464 mPrivateFlags |= PFLAG_ANIMATION_STARTED; 23465 } 23466 23467 /** 23468 * Invoked by a parent ViewGroup to notify the end of the animation 23469 * currently associated with this view. If you override this method, 23470 * always call super.onAnimationEnd(); 23471 * 23472 * @see #setAnimation(android.view.animation.Animation) 23473 * @see #getAnimation() 23474 */ 23475 @CallSuper 23476 protected void onAnimationEnd() { 23477 mPrivateFlags &= ~PFLAG_ANIMATION_STARTED; 23478 } 23479 23480 /** 23481 * Invoked if there is a Transform that involves alpha. Subclass that can 23482 * draw themselves with the specified alpha should return true, and then 23483 * respect that alpha when their onDraw() is called. If this returns false 23484 * then the view may be redirected to draw into an offscreen buffer to 23485 * fulfill the request, which will look fine, but may be slower than if the 23486 * subclass handles it internally. The default implementation returns false. 23487 * 23488 * @param alpha The alpha (0..255) to apply to the view's drawing 23489 * @return true if the view can draw with the specified alpha. 23490 */ 23491 protected boolean onSetAlpha(int alpha) { 23492 return false; 23493 } 23494 23495 /** 23496 * This is used by the RootView to perform an optimization when 23497 * the view hierarchy contains one or several SurfaceView. 23498 * SurfaceView is always considered transparent, but its children are not, 23499 * therefore all View objects remove themselves from the global transparent 23500 * region (passed as a parameter to this function). 23501 * 23502 * @param region The transparent region for this ViewAncestor (window). 23503 * 23504 * @return Returns true if the effective visibility of the view at this 23505 * point is opaque, regardless of the transparent region; returns false 23506 * if it is possible for underlying windows to be seen behind the view. 23507 * 23508 * {@hide} 23509 */ 23510 public boolean gatherTransparentRegion(Region region) { 23511 final AttachInfo attachInfo = mAttachInfo; 23512 if (region != null && attachInfo != null) { 23513 final int pflags = mPrivateFlags; 23514 if ((pflags & PFLAG_SKIP_DRAW) == 0) { 23515 // The SKIP_DRAW flag IS NOT set, so this view draws. We need to 23516 // remove it from the transparent region. 23517 final int[] location = attachInfo.mTransparentLocation; 23518 getLocationInWindow(location); 23519 // When a view has Z value, then it will be better to leave some area below the view 23520 // for drawing shadow. The shadow outset is proportional to the Z value. Note that 23521 // the bottom part needs more offset than the left, top and right parts due to the 23522 // spot light effects. 23523 int shadowOffset = getZ() > 0 ? (int) getZ() : 0; 23524 region.op(location[0] - shadowOffset, location[1] - shadowOffset, 23525 location[0] + mRight - mLeft + shadowOffset, 23526 location[1] + mBottom - mTop + (shadowOffset * 3), Region.Op.DIFFERENCE); 23527 } else { 23528 if (mBackground != null && mBackground.getOpacity() != PixelFormat.TRANSPARENT) { 23529 // The SKIP_DRAW flag IS set and the background drawable exists, we remove 23530 // the background drawable's non-transparent parts from this transparent region. 23531 applyDrawableToTransparentRegion(mBackground, region); 23532 } 23533 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null 23534 && mForegroundInfo.mDrawable.getOpacity() != PixelFormat.TRANSPARENT) { 23535 // Similarly, we remove the foreground drawable's non-transparent parts. 23536 applyDrawableToTransparentRegion(mForegroundInfo.mDrawable, region); 23537 } 23538 if (mDefaultFocusHighlight != null 23539 && mDefaultFocusHighlight.getOpacity() != PixelFormat.TRANSPARENT) { 23540 // Similarly, we remove the default focus highlight's non-transparent parts. 23541 applyDrawableToTransparentRegion(mDefaultFocusHighlight, region); 23542 } 23543 } 23544 } 23545 return true; 23546 } 23547 23548 /** 23549 * Play a sound effect for this view. 23550 * 23551 * <p>The framework will play sound effects for some built in actions, such as 23552 * clicking, but you may wish to play these effects in your widget, 23553 * for instance, for internal navigation. 23554 * 23555 * <p>The sound effect will only be played if sound effects are enabled by the user, and 23556 * {@link #isSoundEffectsEnabled()} is true. 23557 * 23558 * @param soundConstant One of the constants defined in {@link SoundEffectConstants} 23559 */ 23560 public void playSoundEffect(int soundConstant) { 23561 if (mAttachInfo == null || mAttachInfo.mRootCallbacks == null || !isSoundEffectsEnabled()) { 23562 return; 23563 } 23564 mAttachInfo.mRootCallbacks.playSoundEffect(soundConstant); 23565 } 23566 23567 /** 23568 * BZZZTT!!1! 23569 * 23570 * <p>Provide haptic feedback to the user for this view. 23571 * 23572 * <p>The framework will provide haptic feedback for some built in actions, 23573 * such as long presses, but you may wish to provide feedback for your 23574 * own widget. 23575 * 23576 * <p>The feedback will only be performed if 23577 * {@link #isHapticFeedbackEnabled()} is true. 23578 * 23579 * @param feedbackConstant One of the constants defined in 23580 * {@link HapticFeedbackConstants} 23581 */ 23582 public boolean performHapticFeedback(int feedbackConstant) { 23583 return performHapticFeedback(feedbackConstant, 0); 23584 } 23585 23586 /** 23587 * BZZZTT!!1! 23588 * 23589 * <p>Like {@link #performHapticFeedback(int)}, with additional options. 23590 * 23591 * @param feedbackConstant One of the constants defined in 23592 * {@link HapticFeedbackConstants} 23593 * @param flags Additional flags as per {@link HapticFeedbackConstants}. 23594 */ 23595 public boolean performHapticFeedback(int feedbackConstant, int flags) { 23596 if (mAttachInfo == null) { 23597 return false; 23598 } 23599 //noinspection SimplifiableIfStatement 23600 if ((flags & HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING) == 0 23601 && !isHapticFeedbackEnabled()) { 23602 return false; 23603 } 23604 return mAttachInfo.mRootCallbacks.performHapticFeedback(feedbackConstant, 23605 (flags & HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING) != 0); 23606 } 23607 23608 /** 23609 * Request that the visibility of the status bar or other screen/window 23610 * decorations be changed. 23611 * 23612 * <p>This method is used to put the over device UI into temporary modes 23613 * where the user's attention is focused more on the application content, 23614 * by dimming or hiding surrounding system affordances. This is typically 23615 * used in conjunction with {@link Window#FEATURE_ACTION_BAR_OVERLAY 23616 * Window.FEATURE_ACTION_BAR_OVERLAY}, allowing the applications content 23617 * to be placed behind the action bar (and with these flags other system 23618 * affordances) so that smooth transitions between hiding and showing them 23619 * can be done. 23620 * 23621 * <p>Two representative examples of the use of system UI visibility is 23622 * implementing a content browsing application (like a magazine reader) 23623 * and a video playing application. 23624 * 23625 * <p>The first code shows a typical implementation of a View in a content 23626 * browsing application. In this implementation, the application goes 23627 * into a content-oriented mode by hiding the status bar and action bar, 23628 * and putting the navigation elements into lights out mode. The user can 23629 * then interact with content while in this mode. Such an application should 23630 * provide an easy way for the user to toggle out of the mode (such as to 23631 * check information in the status bar or access notifications). In the 23632 * implementation here, this is done simply by tapping on the content. 23633 * 23634 * {@sample development/samples/ApiDemos/src/com/example/android/apis/view/ContentBrowserActivity.java 23635 * content} 23636 * 23637 * <p>This second code sample shows a typical implementation of a View 23638 * in a video playing application. In this situation, while the video is 23639 * playing the application would like to go into a complete full-screen mode, 23640 * to use as much of the display as possible for the video. When in this state 23641 * the user can not interact with the application; the system intercepts 23642 * touching on the screen to pop the UI out of full screen mode. See 23643 * {@link #fitSystemWindows(Rect)} for a sample layout that goes with this code. 23644 * 23645 * {@sample development/samples/ApiDemos/src/com/example/android/apis/view/VideoPlayerActivity.java 23646 * content} 23647 * 23648 * @param visibility Bitwise-or of flags {@link #SYSTEM_UI_FLAG_LOW_PROFILE}, 23649 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, {@link #SYSTEM_UI_FLAG_FULLSCREEN}, 23650 * {@link #SYSTEM_UI_FLAG_LAYOUT_STABLE}, {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION}, 23651 * {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN}, {@link #SYSTEM_UI_FLAG_IMMERSIVE}, 23652 * and {@link #SYSTEM_UI_FLAG_IMMERSIVE_STICKY}. 23653 */ 23654 public void setSystemUiVisibility(int visibility) { 23655 if (visibility != mSystemUiVisibility) { 23656 mSystemUiVisibility = visibility; 23657 if (mParent != null && mAttachInfo != null && !mAttachInfo.mRecomputeGlobalAttributes) { 23658 mParent.recomputeViewAttributes(this); 23659 } 23660 } 23661 } 23662 23663 /** 23664 * Returns the last {@link #setSystemUiVisibility(int)} that this view has requested. 23665 * @return Bitwise-or of flags {@link #SYSTEM_UI_FLAG_LOW_PROFILE}, 23666 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, {@link #SYSTEM_UI_FLAG_FULLSCREEN}, 23667 * {@link #SYSTEM_UI_FLAG_LAYOUT_STABLE}, {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION}, 23668 * {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN}, {@link #SYSTEM_UI_FLAG_IMMERSIVE}, 23669 * and {@link #SYSTEM_UI_FLAG_IMMERSIVE_STICKY}. 23670 */ 23671 public int getSystemUiVisibility() { 23672 return mSystemUiVisibility; 23673 } 23674 23675 /** 23676 * Returns the current system UI visibility that is currently set for 23677 * the entire window. This is the combination of the 23678 * {@link #setSystemUiVisibility(int)} values supplied by all of the 23679 * views in the window. 23680 */ 23681 public int getWindowSystemUiVisibility() { 23682 return mAttachInfo != null ? mAttachInfo.mSystemUiVisibility : 0; 23683 } 23684 23685 /** 23686 * Override to find out when the window's requested system UI visibility 23687 * has changed, that is the value returned by {@link #getWindowSystemUiVisibility()}. 23688 * This is different from the callbacks received through 23689 * {@link #setOnSystemUiVisibilityChangeListener(OnSystemUiVisibilityChangeListener)} 23690 * in that this is only telling you about the local request of the window, 23691 * not the actual values applied by the system. 23692 */ 23693 public void onWindowSystemUiVisibilityChanged(int visible) { 23694 } 23695 23696 /** 23697 * Dispatch callbacks to {@link #onWindowSystemUiVisibilityChanged(int)} down 23698 * the view hierarchy. 23699 */ 23700 public void dispatchWindowSystemUiVisiblityChanged(int visible) { 23701 onWindowSystemUiVisibilityChanged(visible); 23702 } 23703 23704 /** 23705 * Set a listener to receive callbacks when the visibility of the system bar changes. 23706 * @param l The {@link OnSystemUiVisibilityChangeListener} to receive callbacks. 23707 */ 23708 public void setOnSystemUiVisibilityChangeListener(OnSystemUiVisibilityChangeListener l) { 23709 getListenerInfo().mOnSystemUiVisibilityChangeListener = l; 23710 if (mParent != null && mAttachInfo != null && !mAttachInfo.mRecomputeGlobalAttributes) { 23711 mParent.recomputeViewAttributes(this); 23712 } 23713 } 23714 23715 /** 23716 * Dispatch callbacks to {@link #setOnSystemUiVisibilityChangeListener} down 23717 * the view hierarchy. 23718 */ 23719 public void dispatchSystemUiVisibilityChanged(int visibility) { 23720 ListenerInfo li = mListenerInfo; 23721 if (li != null && li.mOnSystemUiVisibilityChangeListener != null) { 23722 li.mOnSystemUiVisibilityChangeListener.onSystemUiVisibilityChange( 23723 visibility & PUBLIC_STATUS_BAR_VISIBILITY_MASK); 23724 } 23725 } 23726 23727 boolean updateLocalSystemUiVisibility(int localValue, int localChanges) { 23728 int val = (mSystemUiVisibility&~localChanges) | (localValue&localChanges); 23729 if (val != mSystemUiVisibility) { 23730 setSystemUiVisibility(val); 23731 return true; 23732 } 23733 return false; 23734 } 23735 23736 /** @hide */ 23737 public void setDisabledSystemUiVisibility(int flags) { 23738 if (mAttachInfo != null) { 23739 if (mAttachInfo.mDisabledSystemUiVisibility != flags) { 23740 mAttachInfo.mDisabledSystemUiVisibility = flags; 23741 if (mParent != null) { 23742 mParent.recomputeViewAttributes(this); 23743 } 23744 } 23745 } 23746 } 23747 23748 /** 23749 * Creates an image that the system displays during the drag and drop 23750 * operation. This is called a "drag shadow". The default implementation 23751 * for a DragShadowBuilder based on a View returns an image that has exactly the same 23752 * appearance as the given View. The default also positions the center of the drag shadow 23753 * directly under the touch point. If no View is provided (the constructor with no parameters 23754 * is used), and {@link #onProvideShadowMetrics(Point,Point) onProvideShadowMetrics()} and 23755 * {@link #onDrawShadow(Canvas) onDrawShadow()} are not overridden, then the 23756 * default is an invisible drag shadow. 23757 * <p> 23758 * You are not required to use the View you provide to the constructor as the basis of the 23759 * drag shadow. The {@link #onDrawShadow(Canvas) onDrawShadow()} method allows you to draw 23760 * anything you want as the drag shadow. 23761 * </p> 23762 * <p> 23763 * You pass a DragShadowBuilder object to the system when you start the drag. The system 23764 * calls {@link #onProvideShadowMetrics(Point,Point) onProvideShadowMetrics()} to get the 23765 * size and position of the drag shadow. It uses this data to construct a 23766 * {@link android.graphics.Canvas} object, then it calls {@link #onDrawShadow(Canvas) onDrawShadow()} 23767 * so that your application can draw the shadow image in the Canvas. 23768 * </p> 23769 * 23770 * <div class="special reference"> 23771 * <h3>Developer Guides</h3> 23772 * <p>For a guide to implementing drag and drop features, read the 23773 * <a href="{@docRoot}guide/topics/ui/drag-drop.html">Drag and Drop</a> developer guide.</p> 23774 * </div> 23775 */ 23776 public static class DragShadowBuilder { 23777 private final WeakReference<View> mView; 23778 23779 /** 23780 * Constructs a shadow image builder based on a View. By default, the resulting drag 23781 * shadow will have the same appearance and dimensions as the View, with the touch point 23782 * over the center of the View. 23783 * @param view A View. Any View in scope can be used. 23784 */ 23785 public DragShadowBuilder(View view) { 23786 mView = new WeakReference<View>(view); 23787 } 23788 23789 /** 23790 * Construct a shadow builder object with no associated View. This 23791 * constructor variant is only useful when the {@link #onProvideShadowMetrics(Point, Point)} 23792 * and {@link #onDrawShadow(Canvas)} methods are also overridden in order 23793 * to supply the drag shadow's dimensions and appearance without 23794 * reference to any View object. 23795 */ 23796 public DragShadowBuilder() { 23797 mView = new WeakReference<View>(null); 23798 } 23799 23800 /** 23801 * Returns the View object that had been passed to the 23802 * {@link #View.DragShadowBuilder(View)} 23803 * constructor. If that View parameter was {@code null} or if the 23804 * {@link #View.DragShadowBuilder()} 23805 * constructor was used to instantiate the builder object, this method will return 23806 * null. 23807 * 23808 * @return The View object associate with this builder object. 23809 */ 23810 @SuppressWarnings({"JavadocReference"}) 23811 final public View getView() { 23812 return mView.get(); 23813 } 23814 23815 /** 23816 * Provides the metrics for the shadow image. These include the dimensions of 23817 * the shadow image, and the point within that shadow that should 23818 * be centered under the touch location while dragging. 23819 * <p> 23820 * The default implementation sets the dimensions of the shadow to be the 23821 * same as the dimensions of the View itself and centers the shadow under 23822 * the touch point. 23823 * </p> 23824 * 23825 * @param outShadowSize A {@link android.graphics.Point} containing the width and height 23826 * of the shadow image. Your application must set {@link android.graphics.Point#x} to the 23827 * desired width and must set {@link android.graphics.Point#y} to the desired height of the 23828 * image. 23829 * 23830 * @param outShadowTouchPoint A {@link android.graphics.Point} for the position within the 23831 * shadow image that should be underneath the touch point during the drag and drop 23832 * operation. Your application must set {@link android.graphics.Point#x} to the 23833 * X coordinate and {@link android.graphics.Point#y} to the Y coordinate of this position. 23834 */ 23835 public void onProvideShadowMetrics(Point outShadowSize, Point outShadowTouchPoint) { 23836 final View view = mView.get(); 23837 if (view != null) { 23838 outShadowSize.set(view.getWidth(), view.getHeight()); 23839 outShadowTouchPoint.set(outShadowSize.x / 2, outShadowSize.y / 2); 23840 } else { 23841 Log.e(View.VIEW_LOG_TAG, "Asked for drag thumb metrics but no view"); 23842 } 23843 } 23844 23845 /** 23846 * Draws the shadow image. The system creates the {@link android.graphics.Canvas} object 23847 * based on the dimensions it received from the 23848 * {@link #onProvideShadowMetrics(Point, Point)} callback. 23849 * 23850 * @param canvas A {@link android.graphics.Canvas} object in which to draw the shadow image. 23851 */ 23852 public void onDrawShadow(Canvas canvas) { 23853 final View view = mView.get(); 23854 if (view != null) { 23855 view.draw(canvas); 23856 } else { 23857 Log.e(View.VIEW_LOG_TAG, "Asked to draw drag shadow but no view"); 23858 } 23859 } 23860 } 23861 23862 /** 23863 * @deprecated Use {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, int) 23864 * startDragAndDrop()} for newer platform versions. 23865 */ 23866 @Deprecated 23867 public final boolean startDrag(ClipData data, DragShadowBuilder shadowBuilder, 23868 Object myLocalState, int flags) { 23869 return startDragAndDrop(data, shadowBuilder, myLocalState, flags); 23870 } 23871 23872 /** 23873 * Starts a drag and drop operation. When your application calls this method, it passes a 23874 * {@link android.view.View.DragShadowBuilder} object to the system. The 23875 * system calls this object's {@link DragShadowBuilder#onProvideShadowMetrics(Point, Point)} 23876 * to get metrics for the drag shadow, and then calls the object's 23877 * {@link DragShadowBuilder#onDrawShadow(Canvas)} to draw the drag shadow itself. 23878 * <p> 23879 * Once the system has the drag shadow, it begins the drag and drop operation by sending 23880 * drag events to all the View objects in your application that are currently visible. It does 23881 * this either by calling the View object's drag listener (an implementation of 23882 * {@link android.view.View.OnDragListener#onDrag(View,DragEvent) onDrag()} or by calling the 23883 * View object's {@link android.view.View#onDragEvent(DragEvent) onDragEvent()} method. 23884 * Both are passed a {@link android.view.DragEvent} object that has a 23885 * {@link android.view.DragEvent#getAction()} value of 23886 * {@link android.view.DragEvent#ACTION_DRAG_STARTED}. 23887 * </p> 23888 * <p> 23889 * Your application can invoke {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, 23890 * int) startDragAndDrop()} on any attached View object. The View object does not need to be 23891 * the one used in {@link android.view.View.DragShadowBuilder}, nor does it need to be related 23892 * to the View the user selected for dragging. 23893 * </p> 23894 * @param data A {@link android.content.ClipData} object pointing to the data to be 23895 * transferred by the drag and drop operation. 23896 * @param shadowBuilder A {@link android.view.View.DragShadowBuilder} object for building the 23897 * drag shadow. 23898 * @param myLocalState An {@link java.lang.Object} containing local data about the drag and 23899 * drop operation. When dispatching drag events to views in the same activity this object 23900 * will be available through {@link android.view.DragEvent#getLocalState()}. Views in other 23901 * activities will not have access to this data ({@link android.view.DragEvent#getLocalState()} 23902 * will return null). 23903 * <p> 23904 * myLocalState is a lightweight mechanism for the sending information from the dragged View 23905 * to the target Views. For example, it can contain flags that differentiate between a 23906 * a copy operation and a move operation. 23907 * </p> 23908 * @param flags Flags that control the drag and drop operation. This can be set to 0 for no 23909 * flags, or any combination of the following: 23910 * <ul> 23911 * <li>{@link #DRAG_FLAG_GLOBAL}</li> 23912 * <li>{@link #DRAG_FLAG_GLOBAL_PERSISTABLE_URI_PERMISSION}</li> 23913 * <li>{@link #DRAG_FLAG_GLOBAL_PREFIX_URI_PERMISSION}</li> 23914 * <li>{@link #DRAG_FLAG_GLOBAL_URI_READ}</li> 23915 * <li>{@link #DRAG_FLAG_GLOBAL_URI_WRITE}</li> 23916 * <li>{@link #DRAG_FLAG_OPAQUE}</li> 23917 * </ul> 23918 * @return {@code true} if the method completes successfully, or 23919 * {@code false} if it fails anywhere. Returning {@code false} means the system was unable to 23920 * do a drag, and so no drag operation is in progress. 23921 */ 23922 public final boolean startDragAndDrop(ClipData data, DragShadowBuilder shadowBuilder, 23923 Object myLocalState, int flags) { 23924 if (ViewDebug.DEBUG_DRAG) { 23925 Log.d(VIEW_LOG_TAG, "startDragAndDrop: data=" + data + " flags=" + flags); 23926 } 23927 if (mAttachInfo == null) { 23928 Log.w(VIEW_LOG_TAG, "startDragAndDrop called on a detached view."); 23929 return false; 23930 } 23931 23932 if (data != null) { 23933 data.prepareToLeaveProcess((flags & View.DRAG_FLAG_GLOBAL) != 0); 23934 } 23935 23936 Point shadowSize = new Point(); 23937 Point shadowTouchPoint = new Point(); 23938 shadowBuilder.onProvideShadowMetrics(shadowSize, shadowTouchPoint); 23939 23940 if ((shadowSize.x < 0) || (shadowSize.y < 0) 23941 || (shadowTouchPoint.x < 0) || (shadowTouchPoint.y < 0)) { 23942 throw new IllegalStateException("Drag shadow dimensions must not be negative"); 23943 } 23944 23945 // Create 1x1 surface when zero surface size is specified because SurfaceControl.Builder 23946 // does not accept zero size surface. 23947 if (shadowSize.x == 0 || shadowSize.y == 0) { 23948 if (!sAcceptZeroSizeDragShadow) { 23949 throw new IllegalStateException("Drag shadow dimensions must be positive"); 23950 } 23951 shadowSize.x = 1; 23952 shadowSize.y = 1; 23953 } 23954 23955 if (ViewDebug.DEBUG_DRAG) { 23956 Log.d(VIEW_LOG_TAG, "drag shadow: width=" + shadowSize.x + " height=" + shadowSize.y 23957 + " shadowX=" + shadowTouchPoint.x + " shadowY=" + shadowTouchPoint.y); 23958 } 23959 if (mAttachInfo.mDragSurface != null) { 23960 mAttachInfo.mDragSurface.release(); 23961 } 23962 mAttachInfo.mDragSurface = new Surface(); 23963 mAttachInfo.mDragToken = null; 23964 23965 final ViewRootImpl root = mAttachInfo.mViewRootImpl; 23966 final SurfaceSession session = new SurfaceSession(root.mSurface); 23967 final SurfaceControl surface = new SurfaceControl.Builder(session) 23968 .setName("drag surface") 23969 .setSize(shadowSize.x, shadowSize.y) 23970 .setFormat(PixelFormat.TRANSLUCENT) 23971 .build(); 23972 try { 23973 mAttachInfo.mDragSurface.copyFrom(surface); 23974 final Canvas canvas = mAttachInfo.mDragSurface.lockCanvas(null); 23975 try { 23976 canvas.drawColor(0, PorterDuff.Mode.CLEAR); 23977 shadowBuilder.onDrawShadow(canvas); 23978 } finally { 23979 mAttachInfo.mDragSurface.unlockCanvasAndPost(canvas); 23980 } 23981 23982 // Cache the local state object for delivery with DragEvents 23983 root.setLocalDragState(myLocalState); 23984 23985 // repurpose 'shadowSize' for the last touch point 23986 root.getLastTouchPoint(shadowSize); 23987 23988 mAttachInfo.mDragToken = mAttachInfo.mSession.performDrag( 23989 mAttachInfo.mWindow, flags, surface, root.getLastTouchSource(), 23990 shadowSize.x, shadowSize.y, shadowTouchPoint.x, shadowTouchPoint.y, data); 23991 if (ViewDebug.DEBUG_DRAG) { 23992 Log.d(VIEW_LOG_TAG, "performDrag returned " + mAttachInfo.mDragToken); 23993 } 23994 23995 return mAttachInfo.mDragToken != null; 23996 } catch (Exception e) { 23997 Log.e(VIEW_LOG_TAG, "Unable to initiate drag", e); 23998 return false; 23999 } finally { 24000 if (mAttachInfo.mDragToken == null) { 24001 mAttachInfo.mDragSurface.destroy(); 24002 mAttachInfo.mDragSurface = null; 24003 root.setLocalDragState(null); 24004 } 24005 session.kill(); 24006 } 24007 } 24008 24009 /** 24010 * Cancels an ongoing drag and drop operation. 24011 * <p> 24012 * A {@link android.view.DragEvent} object with 24013 * {@link android.view.DragEvent#getAction()} value of 24014 * {@link android.view.DragEvent#ACTION_DRAG_ENDED} and 24015 * {@link android.view.DragEvent#getResult()} value of {@code false} 24016 * will be sent to every 24017 * View that received {@link android.view.DragEvent#ACTION_DRAG_STARTED} 24018 * even if they are not currently visible. 24019 * </p> 24020 * <p> 24021 * This method can be called on any View in the same window as the View on which 24022 * {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, int) startDragAndDrop} 24023 * was called. 24024 * </p> 24025 */ 24026 public final void cancelDragAndDrop() { 24027 if (ViewDebug.DEBUG_DRAG) { 24028 Log.d(VIEW_LOG_TAG, "cancelDragAndDrop"); 24029 } 24030 if (mAttachInfo == null) { 24031 Log.w(VIEW_LOG_TAG, "cancelDragAndDrop called on a detached view."); 24032 return; 24033 } 24034 if (mAttachInfo.mDragToken != null) { 24035 try { 24036 mAttachInfo.mSession.cancelDragAndDrop(mAttachInfo.mDragToken); 24037 } catch (Exception e) { 24038 Log.e(VIEW_LOG_TAG, "Unable to cancel drag", e); 24039 } 24040 mAttachInfo.mDragToken = null; 24041 } else { 24042 Log.e(VIEW_LOG_TAG, "No active drag to cancel"); 24043 } 24044 } 24045 24046 /** 24047 * Updates the drag shadow for the ongoing drag and drop operation. 24048 * 24049 * @param shadowBuilder A {@link android.view.View.DragShadowBuilder} object for building the 24050 * new drag shadow. 24051 */ 24052 public final void updateDragShadow(DragShadowBuilder shadowBuilder) { 24053 if (ViewDebug.DEBUG_DRAG) { 24054 Log.d(VIEW_LOG_TAG, "updateDragShadow"); 24055 } 24056 if (mAttachInfo == null) { 24057 Log.w(VIEW_LOG_TAG, "updateDragShadow called on a detached view."); 24058 return; 24059 } 24060 if (mAttachInfo.mDragToken != null) { 24061 try { 24062 Canvas canvas = mAttachInfo.mDragSurface.lockCanvas(null); 24063 try { 24064 canvas.drawColor(0, PorterDuff.Mode.CLEAR); 24065 shadowBuilder.onDrawShadow(canvas); 24066 } finally { 24067 mAttachInfo.mDragSurface.unlockCanvasAndPost(canvas); 24068 } 24069 } catch (Exception e) { 24070 Log.e(VIEW_LOG_TAG, "Unable to update drag shadow", e); 24071 } 24072 } else { 24073 Log.e(VIEW_LOG_TAG, "No active drag"); 24074 } 24075 } 24076 24077 /** 24078 * Starts a move from {startX, startY}, the amount of the movement will be the offset 24079 * between {startX, startY} and the new cursor positon. 24080 * @param startX horizontal coordinate where the move started. 24081 * @param startY vertical coordinate where the move started. 24082 * @return whether moving was started successfully. 24083 * @hide 24084 */ 24085 public final boolean startMovingTask(float startX, float startY) { 24086 if (ViewDebug.DEBUG_POSITIONING) { 24087 Log.d(VIEW_LOG_TAG, "startMovingTask: {" + startX + "," + startY + "}"); 24088 } 24089 try { 24090 return mAttachInfo.mSession.startMovingTask(mAttachInfo.mWindow, startX, startY); 24091 } catch (RemoteException e) { 24092 Log.e(VIEW_LOG_TAG, "Unable to start moving", e); 24093 } 24094 return false; 24095 } 24096 24097 /** 24098 * Handles drag events sent by the system following a call to 24099 * {@link android.view.View#startDragAndDrop(ClipData,DragShadowBuilder,Object,int) 24100 * startDragAndDrop()}. 24101 *<p> 24102 * When the system calls this method, it passes a 24103 * {@link android.view.DragEvent} object. A call to 24104 * {@link android.view.DragEvent#getAction()} returns one of the action type constants defined 24105 * in DragEvent. The method uses these to determine what is happening in the drag and drop 24106 * operation. 24107 * @param event The {@link android.view.DragEvent} sent by the system. 24108 * The {@link android.view.DragEvent#getAction()} method returns an action type constant defined 24109 * in DragEvent, indicating the type of drag event represented by this object. 24110 * @return {@code true} if the method was successful, otherwise {@code false}. 24111 * <p> 24112 * The method should return {@code true} in response to an action type of 24113 * {@link android.view.DragEvent#ACTION_DRAG_STARTED} to receive drag events for the current 24114 * operation. 24115 * </p> 24116 * <p> 24117 * The method should also return {@code true} in response to an action type of 24118 * {@link android.view.DragEvent#ACTION_DROP} if it consumed the drop, or 24119 * {@code false} if it didn't. 24120 * </p> 24121 * <p> 24122 * For all other events, the return value is ignored. 24123 * </p> 24124 */ 24125 public boolean onDragEvent(DragEvent event) { 24126 return false; 24127 } 24128 24129 // Dispatches ACTION_DRAG_ENTERED and ACTION_DRAG_EXITED events for pre-Nougat apps. 24130 boolean dispatchDragEnterExitInPreN(DragEvent event) { 24131 return callDragEventHandler(event); 24132 } 24133 24134 /** 24135 * Detects if this View is enabled and has a drag event listener. 24136 * If both are true, then it calls the drag event listener with the 24137 * {@link android.view.DragEvent} it received. If the drag event listener returns 24138 * {@code true}, then dispatchDragEvent() returns {@code true}. 24139 * <p> 24140 * For all other cases, the method calls the 24141 * {@link android.view.View#onDragEvent(DragEvent) onDragEvent()} drag event handler 24142 * method and returns its result. 24143 * </p> 24144 * <p> 24145 * This ensures that a drag event is always consumed, even if the View does not have a drag 24146 * event listener. However, if the View has a listener and the listener returns true, then 24147 * onDragEvent() is not called. 24148 * </p> 24149 */ 24150 public boolean dispatchDragEvent(DragEvent event) { 24151 event.mEventHandlerWasCalled = true; 24152 if (event.mAction == DragEvent.ACTION_DRAG_LOCATION || 24153 event.mAction == DragEvent.ACTION_DROP) { 24154 // About to deliver an event with coordinates to this view. Notify that now this view 24155 // has drag focus. This will send exit/enter events as needed. 24156 getViewRootImpl().setDragFocus(this, event); 24157 } 24158 return callDragEventHandler(event); 24159 } 24160 24161 final boolean callDragEventHandler(DragEvent event) { 24162 final boolean result; 24163 24164 ListenerInfo li = mListenerInfo; 24165 //noinspection SimplifiableIfStatement 24166 if (li != null && li.mOnDragListener != null && (mViewFlags & ENABLED_MASK) == ENABLED 24167 && li.mOnDragListener.onDrag(this, event)) { 24168 result = true; 24169 } else { 24170 result = onDragEvent(event); 24171 } 24172 24173 switch (event.mAction) { 24174 case DragEvent.ACTION_DRAG_ENTERED: { 24175 mPrivateFlags2 |= View.PFLAG2_DRAG_HOVERED; 24176 refreshDrawableState(); 24177 } break; 24178 case DragEvent.ACTION_DRAG_EXITED: { 24179 mPrivateFlags2 &= ~View.PFLAG2_DRAG_HOVERED; 24180 refreshDrawableState(); 24181 } break; 24182 case DragEvent.ACTION_DRAG_ENDED: { 24183 mPrivateFlags2 &= ~View.DRAG_MASK; 24184 refreshDrawableState(); 24185 } break; 24186 } 24187 24188 return result; 24189 } 24190 24191 boolean canAcceptDrag() { 24192 return (mPrivateFlags2 & PFLAG2_DRAG_CAN_ACCEPT) != 0; 24193 } 24194 24195 /** 24196 * This needs to be a better API (NOT ON VIEW) before it is exposed. If 24197 * it is ever exposed at all. 24198 * @hide 24199 */ 24200 public void onCloseSystemDialogs(String reason) { 24201 } 24202 24203 /** 24204 * Given a Drawable whose bounds have been set to draw into this view, 24205 * update a Region being computed for 24206 * {@link #gatherTransparentRegion(android.graphics.Region)} so 24207 * that any non-transparent parts of the Drawable are removed from the 24208 * given transparent region. 24209 * 24210 * @param dr The Drawable whose transparency is to be applied to the region. 24211 * @param region A Region holding the current transparency information, 24212 * where any parts of the region that are set are considered to be 24213 * transparent. On return, this region will be modified to have the 24214 * transparency information reduced by the corresponding parts of the 24215 * Drawable that are not transparent. 24216 * {@hide} 24217 */ 24218 public void applyDrawableToTransparentRegion(Drawable dr, Region region) { 24219 if (DBG) { 24220 Log.i("View", "Getting transparent region for: " + this); 24221 } 24222 final Region r = dr.getTransparentRegion(); 24223 final Rect db = dr.getBounds(); 24224 final AttachInfo attachInfo = mAttachInfo; 24225 if (r != null && attachInfo != null) { 24226 final int w = getRight()-getLeft(); 24227 final int h = getBottom()-getTop(); 24228 if (db.left > 0) { 24229 //Log.i("VIEW", "Drawable left " + db.left + " > view 0"); 24230 r.op(0, 0, db.left, h, Region.Op.UNION); 24231 } 24232 if (db.right < w) { 24233 //Log.i("VIEW", "Drawable right " + db.right + " < view " + w); 24234 r.op(db.right, 0, w, h, Region.Op.UNION); 24235 } 24236 if (db.top > 0) { 24237 //Log.i("VIEW", "Drawable top " + db.top + " > view 0"); 24238 r.op(0, 0, w, db.top, Region.Op.UNION); 24239 } 24240 if (db.bottom < h) { 24241 //Log.i("VIEW", "Drawable bottom " + db.bottom + " < view " + h); 24242 r.op(0, db.bottom, w, h, Region.Op.UNION); 24243 } 24244 final int[] location = attachInfo.mTransparentLocation; 24245 getLocationInWindow(location); 24246 r.translate(location[0], location[1]); 24247 region.op(r, Region.Op.INTERSECT); 24248 } else { 24249 region.op(db, Region.Op.DIFFERENCE); 24250 } 24251 } 24252 24253 private void checkForLongClick(int delayOffset, float x, float y) { 24254 if ((mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE || (mViewFlags & TOOLTIP) == TOOLTIP) { 24255 mHasPerformedLongPress = false; 24256 24257 if (mPendingCheckForLongPress == null) { 24258 mPendingCheckForLongPress = new CheckForLongPress(); 24259 } 24260 mPendingCheckForLongPress.setAnchor(x, y); 24261 mPendingCheckForLongPress.rememberWindowAttachCount(); 24262 mPendingCheckForLongPress.rememberPressedState(); 24263 postDelayed(mPendingCheckForLongPress, 24264 ViewConfiguration.getLongPressTimeout() - delayOffset); 24265 } 24266 } 24267 24268 /** 24269 * Inflate a view from an XML resource. This convenience method wraps the {@link 24270 * LayoutInflater} class, which provides a full range of options for view inflation. 24271 * 24272 * @param context The Context object for your activity or application. 24273 * @param resource The resource ID to inflate 24274 * @param root A view group that will be the parent. Used to properly inflate the 24275 * layout_* parameters. 24276 * @see LayoutInflater 24277 */ 24278 public static View inflate(Context context, @LayoutRes int resource, ViewGroup root) { 24279 LayoutInflater factory = LayoutInflater.from(context); 24280 return factory.inflate(resource, root); 24281 } 24282 24283 /** 24284 * Scroll the view with standard behavior for scrolling beyond the normal 24285 * content boundaries. Views that call this method should override 24286 * {@link #onOverScrolled(int, int, boolean, boolean)} to respond to the 24287 * results of an over-scroll operation. 24288 * 24289 * Views can use this method to handle any touch or fling-based scrolling. 24290 * 24291 * @param deltaX Change in X in pixels 24292 * @param deltaY Change in Y in pixels 24293 * @param scrollX Current X scroll value in pixels before applying deltaX 24294 * @param scrollY Current Y scroll value in pixels before applying deltaY 24295 * @param scrollRangeX Maximum content scroll range along the X axis 24296 * @param scrollRangeY Maximum content scroll range along the Y axis 24297 * @param maxOverScrollX Number of pixels to overscroll by in either direction 24298 * along the X axis. 24299 * @param maxOverScrollY Number of pixels to overscroll by in either direction 24300 * along the Y axis. 24301 * @param isTouchEvent true if this scroll operation is the result of a touch event. 24302 * @return true if scrolling was clamped to an over-scroll boundary along either 24303 * axis, false otherwise. 24304 */ 24305 @SuppressWarnings({"UnusedParameters"}) 24306 protected boolean overScrollBy(int deltaX, int deltaY, 24307 int scrollX, int scrollY, 24308 int scrollRangeX, int scrollRangeY, 24309 int maxOverScrollX, int maxOverScrollY, 24310 boolean isTouchEvent) { 24311 final int overScrollMode = mOverScrollMode; 24312 final boolean canScrollHorizontal = 24313 computeHorizontalScrollRange() > computeHorizontalScrollExtent(); 24314 final boolean canScrollVertical = 24315 computeVerticalScrollRange() > computeVerticalScrollExtent(); 24316 final boolean overScrollHorizontal = overScrollMode == OVER_SCROLL_ALWAYS || 24317 (overScrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && canScrollHorizontal); 24318 final boolean overScrollVertical = overScrollMode == OVER_SCROLL_ALWAYS || 24319 (overScrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && canScrollVertical); 24320 24321 int newScrollX = scrollX + deltaX; 24322 if (!overScrollHorizontal) { 24323 maxOverScrollX = 0; 24324 } 24325 24326 int newScrollY = scrollY + deltaY; 24327 if (!overScrollVertical) { 24328 maxOverScrollY = 0; 24329 } 24330 24331 // Clamp values if at the limits and record 24332 final int left = -maxOverScrollX; 24333 final int right = maxOverScrollX + scrollRangeX; 24334 final int top = -maxOverScrollY; 24335 final int bottom = maxOverScrollY + scrollRangeY; 24336 24337 boolean clampedX = false; 24338 if (newScrollX > right) { 24339 newScrollX = right; 24340 clampedX = true; 24341 } else if (newScrollX < left) { 24342 newScrollX = left; 24343 clampedX = true; 24344 } 24345 24346 boolean clampedY = false; 24347 if (newScrollY > bottom) { 24348 newScrollY = bottom; 24349 clampedY = true; 24350 } else if (newScrollY < top) { 24351 newScrollY = top; 24352 clampedY = true; 24353 } 24354 24355 onOverScrolled(newScrollX, newScrollY, clampedX, clampedY); 24356 24357 return clampedX || clampedY; 24358 } 24359 24360 /** 24361 * Called by {@link #overScrollBy(int, int, int, int, int, int, int, int, boolean)} to 24362 * respond to the results of an over-scroll operation. 24363 * 24364 * @param scrollX New X scroll value in pixels 24365 * @param scrollY New Y scroll value in pixels 24366 * @param clampedX True if scrollX was clamped to an over-scroll boundary 24367 * @param clampedY True if scrollY was clamped to an over-scroll boundary 24368 */ 24369 protected void onOverScrolled(int scrollX, int scrollY, 24370 boolean clampedX, boolean clampedY) { 24371 // Intentionally empty. 24372 } 24373 24374 /** 24375 * Returns the over-scroll mode for this view. The result will be 24376 * one of {@link #OVER_SCROLL_ALWAYS} (default), {@link #OVER_SCROLL_IF_CONTENT_SCROLLS} 24377 * (allow over-scrolling only if the view content is larger than the container), 24378 * or {@link #OVER_SCROLL_NEVER}. 24379 * 24380 * @return This view's over-scroll mode. 24381 */ 24382 public int getOverScrollMode() { 24383 return mOverScrollMode; 24384 } 24385 24386 /** 24387 * Set the over-scroll mode for this view. Valid over-scroll modes are 24388 * {@link #OVER_SCROLL_ALWAYS} (default), {@link #OVER_SCROLL_IF_CONTENT_SCROLLS} 24389 * (allow over-scrolling only if the view content is larger than the container), 24390 * or {@link #OVER_SCROLL_NEVER}. 24391 * 24392 * Setting the over-scroll mode of a view will have an effect only if the 24393 * view is capable of scrolling. 24394 * 24395 * @param overScrollMode The new over-scroll mode for this view. 24396 */ 24397 public void setOverScrollMode(int overScrollMode) { 24398 if (overScrollMode != OVER_SCROLL_ALWAYS && 24399 overScrollMode != OVER_SCROLL_IF_CONTENT_SCROLLS && 24400 overScrollMode != OVER_SCROLL_NEVER) { 24401 throw new IllegalArgumentException("Invalid overscroll mode " + overScrollMode); 24402 } 24403 mOverScrollMode = overScrollMode; 24404 } 24405 24406 /** 24407 * Enable or disable nested scrolling for this view. 24408 * 24409 * <p>If this property is set to true the view will be permitted to initiate nested 24410 * scrolling operations with a compatible parent view in the current hierarchy. If this 24411 * view does not implement nested scrolling this will have no effect. Disabling nested scrolling 24412 * while a nested scroll is in progress has the effect of {@link #stopNestedScroll() stopping} 24413 * the nested scroll.</p> 24414 * 24415 * @param enabled true to enable nested scrolling, false to disable 24416 * 24417 * @see #isNestedScrollingEnabled() 24418 */ 24419 public void setNestedScrollingEnabled(boolean enabled) { 24420 if (enabled) { 24421 mPrivateFlags3 |= PFLAG3_NESTED_SCROLLING_ENABLED; 24422 } else { 24423 stopNestedScroll(); 24424 mPrivateFlags3 &= ~PFLAG3_NESTED_SCROLLING_ENABLED; 24425 } 24426 } 24427 24428 /** 24429 * Returns true if nested scrolling is enabled for this view. 24430 * 24431 * <p>If nested scrolling is enabled and this View class implementation supports it, 24432 * this view will act as a nested scrolling child view when applicable, forwarding data 24433 * about the scroll operation in progress to a compatible and cooperating nested scrolling 24434 * parent.</p> 24435 * 24436 * @return true if nested scrolling is enabled 24437 * 24438 * @see #setNestedScrollingEnabled(boolean) 24439 */ 24440 public boolean isNestedScrollingEnabled() { 24441 return (mPrivateFlags3 & PFLAG3_NESTED_SCROLLING_ENABLED) == 24442 PFLAG3_NESTED_SCROLLING_ENABLED; 24443 } 24444 24445 /** 24446 * Begin a nestable scroll operation along the given axes. 24447 * 24448 * <p>A view starting a nested scroll promises to abide by the following contract:</p> 24449 * 24450 * <p>The view will call startNestedScroll upon initiating a scroll operation. In the case 24451 * of a touch scroll this corresponds to the initial {@link MotionEvent#ACTION_DOWN}. 24452 * In the case of touch scrolling the nested scroll will be terminated automatically in 24453 * the same manner as {@link ViewParent#requestDisallowInterceptTouchEvent(boolean)}. 24454 * In the event of programmatic scrolling the caller must explicitly call 24455 * {@link #stopNestedScroll()} to indicate the end of the nested scroll.</p> 24456 * 24457 * <p>If <code>startNestedScroll</code> returns true, a cooperative parent was found. 24458 * If it returns false the caller may ignore the rest of this contract until the next scroll. 24459 * Calling startNestedScroll while a nested scroll is already in progress will return true.</p> 24460 * 24461 * <p>At each incremental step of the scroll the caller should invoke 24462 * {@link #dispatchNestedPreScroll(int, int, int[], int[]) dispatchNestedPreScroll} 24463 * once it has calculated the requested scrolling delta. If it returns true the nested scrolling 24464 * parent at least partially consumed the scroll and the caller should adjust the amount it 24465 * scrolls by.</p> 24466 * 24467 * <p>After applying the remainder of the scroll delta the caller should invoke 24468 * {@link #dispatchNestedScroll(int, int, int, int, int[]) dispatchNestedScroll}, passing 24469 * both the delta consumed and the delta unconsumed. A nested scrolling parent may treat 24470 * these values differently. See {@link ViewParent#onNestedScroll(View, int, int, int, int)}. 24471 * </p> 24472 * 24473 * @param axes Flags consisting of a combination of {@link #SCROLL_AXIS_HORIZONTAL} and/or 24474 * {@link #SCROLL_AXIS_VERTICAL}. 24475 * @return true if a cooperative parent was found and nested scrolling has been enabled for 24476 * the current gesture. 24477 * 24478 * @see #stopNestedScroll() 24479 * @see #dispatchNestedPreScroll(int, int, int[], int[]) 24480 * @see #dispatchNestedScroll(int, int, int, int, int[]) 24481 */ 24482 public boolean startNestedScroll(int axes) { 24483 if (hasNestedScrollingParent()) { 24484 // Already in progress 24485 return true; 24486 } 24487 if (isNestedScrollingEnabled()) { 24488 ViewParent p = getParent(); 24489 View child = this; 24490 while (p != null) { 24491 try { 24492 if (p.onStartNestedScroll(child, this, axes)) { 24493 mNestedScrollingParent = p; 24494 p.onNestedScrollAccepted(child, this, axes); 24495 return true; 24496 } 24497 } catch (AbstractMethodError e) { 24498 Log.e(VIEW_LOG_TAG, "ViewParent " + p + " does not implement interface " + 24499 "method onStartNestedScroll", e); 24500 // Allow the search upward to continue 24501 } 24502 if (p instanceof View) { 24503 child = (View) p; 24504 } 24505 p = p.getParent(); 24506 } 24507 } 24508 return false; 24509 } 24510 24511 /** 24512 * Stop a nested scroll in progress. 24513 * 24514 * <p>Calling this method when a nested scroll is not currently in progress is harmless.</p> 24515 * 24516 * @see #startNestedScroll(int) 24517 */ 24518 public void stopNestedScroll() { 24519 if (mNestedScrollingParent != null) { 24520 mNestedScrollingParent.onStopNestedScroll(this); 24521 mNestedScrollingParent = null; 24522 } 24523 } 24524 24525 /** 24526 * Returns true if this view has a nested scrolling parent. 24527 * 24528 * <p>The presence of a nested scrolling parent indicates that this view has initiated 24529 * a nested scroll and it was accepted by an ancestor view further up the view hierarchy.</p> 24530 * 24531 * @return whether this view has a nested scrolling parent 24532 */ 24533 public boolean hasNestedScrollingParent() { 24534 return mNestedScrollingParent != null; 24535 } 24536 24537 /** 24538 * Dispatch one step of a nested scroll in progress. 24539 * 24540 * <p>Implementations of views that support nested scrolling should call this to report 24541 * info about a scroll in progress to the current nested scrolling parent. If a nested scroll 24542 * is not currently in progress or nested scrolling is not 24543 * {@link #isNestedScrollingEnabled() enabled} for this view this method does nothing.</p> 24544 * 24545 * <p>Compatible View implementations should also call 24546 * {@link #dispatchNestedPreScroll(int, int, int[], int[]) dispatchNestedPreScroll} before 24547 * consuming a component of the scroll event themselves.</p> 24548 * 24549 * @param dxConsumed Horizontal distance in pixels consumed by this view during this scroll step 24550 * @param dyConsumed Vertical distance in pixels consumed by this view during this scroll step 24551 * @param dxUnconsumed Horizontal scroll distance in pixels not consumed by this view 24552 * @param dyUnconsumed Horizontal scroll distance in pixels not consumed by this view 24553 * @param offsetInWindow Optional. If not null, on return this will contain the offset 24554 * in local view coordinates of this view from before this operation 24555 * to after it completes. View implementations may use this to adjust 24556 * expected input coordinate tracking. 24557 * @return true if the event was dispatched, false if it could not be dispatched. 24558 * @see #dispatchNestedPreScroll(int, int, int[], int[]) 24559 */ 24560 public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed, 24561 int dxUnconsumed, int dyUnconsumed, @Nullable @Size(2) int[] offsetInWindow) { 24562 if (isNestedScrollingEnabled() && mNestedScrollingParent != null) { 24563 if (dxConsumed != 0 || dyConsumed != 0 || dxUnconsumed != 0 || dyUnconsumed != 0) { 24564 int startX = 0; 24565 int startY = 0; 24566 if (offsetInWindow != null) { 24567 getLocationInWindow(offsetInWindow); 24568 startX = offsetInWindow[0]; 24569 startY = offsetInWindow[1]; 24570 } 24571 24572 mNestedScrollingParent.onNestedScroll(this, dxConsumed, dyConsumed, 24573 dxUnconsumed, dyUnconsumed); 24574 24575 if (offsetInWindow != null) { 24576 getLocationInWindow(offsetInWindow); 24577 offsetInWindow[0] -= startX; 24578 offsetInWindow[1] -= startY; 24579 } 24580 return true; 24581 } else if (offsetInWindow != null) { 24582 // No motion, no dispatch. Keep offsetInWindow up to date. 24583 offsetInWindow[0] = 0; 24584 offsetInWindow[1] = 0; 24585 } 24586 } 24587 return false; 24588 } 24589 24590 /** 24591 * Dispatch one step of a nested scroll in progress before this view consumes any portion of it. 24592 * 24593 * <p>Nested pre-scroll events are to nested scroll events what touch intercept is to touch. 24594 * <code>dispatchNestedPreScroll</code> offers an opportunity for the parent view in a nested 24595 * scrolling operation to consume some or all of the scroll operation before the child view 24596 * consumes it.</p> 24597 * 24598 * @param dx Horizontal scroll distance in pixels 24599 * @param dy Vertical scroll distance in pixels 24600 * @param consumed Output. If not null, consumed[0] will contain the consumed component of dx 24601 * and consumed[1] the consumed dy. 24602 * @param offsetInWindow Optional. If not null, on return this will contain the offset 24603 * in local view coordinates of this view from before this operation 24604 * to after it completes. View implementations may use this to adjust 24605 * expected input coordinate tracking. 24606 * @return true if the parent consumed some or all of the scroll delta 24607 * @see #dispatchNestedScroll(int, int, int, int, int[]) 24608 */ 24609 public boolean dispatchNestedPreScroll(int dx, int dy, 24610 @Nullable @Size(2) int[] consumed, @Nullable @Size(2) int[] offsetInWindow) { 24611 if (isNestedScrollingEnabled() && mNestedScrollingParent != null) { 24612 if (dx != 0 || dy != 0) { 24613 int startX = 0; 24614 int startY = 0; 24615 if (offsetInWindow != null) { 24616 getLocationInWindow(offsetInWindow); 24617 startX = offsetInWindow[0]; 24618 startY = offsetInWindow[1]; 24619 } 24620 24621 if (consumed == null) { 24622 if (mTempNestedScrollConsumed == null) { 24623 mTempNestedScrollConsumed = new int[2]; 24624 } 24625 consumed = mTempNestedScrollConsumed; 24626 } 24627 consumed[0] = 0; 24628 consumed[1] = 0; 24629 mNestedScrollingParent.onNestedPreScroll(this, dx, dy, consumed); 24630 24631 if (offsetInWindow != null) { 24632 getLocationInWindow(offsetInWindow); 24633 offsetInWindow[0] -= startX; 24634 offsetInWindow[1] -= startY; 24635 } 24636 return consumed[0] != 0 || consumed[1] != 0; 24637 } else if (offsetInWindow != null) { 24638 offsetInWindow[0] = 0; 24639 offsetInWindow[1] = 0; 24640 } 24641 } 24642 return false; 24643 } 24644 24645 /** 24646 * Dispatch a fling to a nested scrolling parent. 24647 * 24648 * <p>This method should be used to indicate that a nested scrolling child has detected 24649 * suitable conditions for a fling. Generally this means that a touch scroll has ended with a 24650 * {@link VelocityTracker velocity} in the direction of scrolling that meets or exceeds 24651 * the {@link ViewConfiguration#getScaledMinimumFlingVelocity() minimum fling velocity} 24652 * along a scrollable axis.</p> 24653 * 24654 * <p>If a nested scrolling child view would normally fling but it is at the edge of 24655 * its own content, it can use this method to delegate the fling to its nested scrolling 24656 * parent instead. The parent may optionally consume the fling or observe a child fling.</p> 24657 * 24658 * @param velocityX Horizontal fling velocity in pixels per second 24659 * @param velocityY Vertical fling velocity in pixels per second 24660 * @param consumed true if the child consumed the fling, false otherwise 24661 * @return true if the nested scrolling parent consumed or otherwise reacted to the fling 24662 */ 24663 public boolean dispatchNestedFling(float velocityX, float velocityY, boolean consumed) { 24664 if (isNestedScrollingEnabled() && mNestedScrollingParent != null) { 24665 return mNestedScrollingParent.onNestedFling(this, velocityX, velocityY, consumed); 24666 } 24667 return false; 24668 } 24669 24670 /** 24671 * Dispatch a fling to a nested scrolling parent before it is processed by this view. 24672 * 24673 * <p>Nested pre-fling events are to nested fling events what touch intercept is to touch 24674 * and what nested pre-scroll is to nested scroll. <code>dispatchNestedPreFling</code> 24675 * offsets an opportunity for the parent view in a nested fling to fully consume the fling 24676 * before the child view consumes it. If this method returns <code>true</code>, a nested 24677 * parent view consumed the fling and this view should not scroll as a result.</p> 24678 * 24679 * <p>For a better user experience, only one view in a nested scrolling chain should consume 24680 * the fling at a time. If a parent view consumed the fling this method will return false. 24681 * Custom view implementations should account for this in two ways:</p> 24682 * 24683 * <ul> 24684 * <li>If a custom view is paged and needs to settle to a fixed page-point, do not 24685 * call <code>dispatchNestedPreFling</code>; consume the fling and settle to a valid 24686 * position regardless.</li> 24687 * <li>If a nested parent does consume the fling, this view should not scroll at all, 24688 * even to settle back to a valid idle position.</li> 24689 * </ul> 24690 * 24691 * <p>Views should also not offer fling velocities to nested parent views along an axis 24692 * where scrolling is not currently supported; a {@link android.widget.ScrollView ScrollView} 24693 * should not offer a horizontal fling velocity to its parents since scrolling along that 24694 * axis is not permitted and carrying velocity along that motion does not make sense.</p> 24695 * 24696 * @param velocityX Horizontal fling velocity in pixels per second 24697 * @param velocityY Vertical fling velocity in pixels per second 24698 * @return true if a nested scrolling parent consumed the fling 24699 */ 24700 public boolean dispatchNestedPreFling(float velocityX, float velocityY) { 24701 if (isNestedScrollingEnabled() && mNestedScrollingParent != null) { 24702 return mNestedScrollingParent.onNestedPreFling(this, velocityX, velocityY); 24703 } 24704 return false; 24705 } 24706 24707 /** 24708 * Gets a scale factor that determines the distance the view should scroll 24709 * vertically in response to {@link MotionEvent#ACTION_SCROLL}. 24710 * @return The vertical scroll scale factor. 24711 * @hide 24712 */ 24713 protected float getVerticalScrollFactor() { 24714 if (mVerticalScrollFactor == 0) { 24715 TypedValue outValue = new TypedValue(); 24716 if (!mContext.getTheme().resolveAttribute( 24717 com.android.internal.R.attr.listPreferredItemHeight, outValue, true)) { 24718 throw new IllegalStateException( 24719 "Expected theme to define listPreferredItemHeight."); 24720 } 24721 mVerticalScrollFactor = outValue.getDimension( 24722 mContext.getResources().getDisplayMetrics()); 24723 } 24724 return mVerticalScrollFactor; 24725 } 24726 24727 /** 24728 * Gets a scale factor that determines the distance the view should scroll 24729 * horizontally in response to {@link MotionEvent#ACTION_SCROLL}. 24730 * @return The horizontal scroll scale factor. 24731 * @hide 24732 */ 24733 protected float getHorizontalScrollFactor() { 24734 // TODO: Should use something else. 24735 return getVerticalScrollFactor(); 24736 } 24737 24738 /** 24739 * Return the value specifying the text direction or policy that was set with 24740 * {@link #setTextDirection(int)}. 24741 * 24742 * @return the defined text direction. It can be one of: 24743 * 24744 * {@link #TEXT_DIRECTION_INHERIT}, 24745 * {@link #TEXT_DIRECTION_FIRST_STRONG}, 24746 * {@link #TEXT_DIRECTION_ANY_RTL}, 24747 * {@link #TEXT_DIRECTION_LTR}, 24748 * {@link #TEXT_DIRECTION_RTL}, 24749 * {@link #TEXT_DIRECTION_LOCALE}, 24750 * {@link #TEXT_DIRECTION_FIRST_STRONG_LTR}, 24751 * {@link #TEXT_DIRECTION_FIRST_STRONG_RTL} 24752 * 24753 * @attr ref android.R.styleable#View_textDirection 24754 * 24755 * @hide 24756 */ 24757 @ViewDebug.ExportedProperty(category = "text", mapping = { 24758 @ViewDebug.IntToString(from = TEXT_DIRECTION_INHERIT, to = "INHERIT"), 24759 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG, to = "FIRST_STRONG"), 24760 @ViewDebug.IntToString(from = TEXT_DIRECTION_ANY_RTL, to = "ANY_RTL"), 24761 @ViewDebug.IntToString(from = TEXT_DIRECTION_LTR, to = "LTR"), 24762 @ViewDebug.IntToString(from = TEXT_DIRECTION_RTL, to = "RTL"), 24763 @ViewDebug.IntToString(from = TEXT_DIRECTION_LOCALE, to = "LOCALE"), 24764 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_LTR, to = "FIRST_STRONG_LTR"), 24765 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_RTL, to = "FIRST_STRONG_RTL") 24766 }) 24767 public int getRawTextDirection() { 24768 return (mPrivateFlags2 & PFLAG2_TEXT_DIRECTION_MASK) >> PFLAG2_TEXT_DIRECTION_MASK_SHIFT; 24769 } 24770 24771 /** 24772 * Set the text direction. 24773 * 24774 * @param textDirection the direction to set. Should be one of: 24775 * 24776 * {@link #TEXT_DIRECTION_INHERIT}, 24777 * {@link #TEXT_DIRECTION_FIRST_STRONG}, 24778 * {@link #TEXT_DIRECTION_ANY_RTL}, 24779 * {@link #TEXT_DIRECTION_LTR}, 24780 * {@link #TEXT_DIRECTION_RTL}, 24781 * {@link #TEXT_DIRECTION_LOCALE} 24782 * {@link #TEXT_DIRECTION_FIRST_STRONG_LTR}, 24783 * {@link #TEXT_DIRECTION_FIRST_STRONG_RTL}, 24784 * 24785 * Resolution will be done if the value is set to TEXT_DIRECTION_INHERIT. The resolution 24786 * proceeds up the parent chain of the view to get the value. If there is no parent, then it will 24787 * return the default {@link #TEXT_DIRECTION_FIRST_STRONG}. 24788 * 24789 * @attr ref android.R.styleable#View_textDirection 24790 */ 24791 public void setTextDirection(int textDirection) { 24792 if (getRawTextDirection() != textDirection) { 24793 // Reset the current text direction and the resolved one 24794 mPrivateFlags2 &= ~PFLAG2_TEXT_DIRECTION_MASK; 24795 resetResolvedTextDirection(); 24796 // Set the new text direction 24797 mPrivateFlags2 |= ((textDirection << PFLAG2_TEXT_DIRECTION_MASK_SHIFT) & PFLAG2_TEXT_DIRECTION_MASK); 24798 // Do resolution 24799 resolveTextDirection(); 24800 // Notify change 24801 onRtlPropertiesChanged(getLayoutDirection()); 24802 // Refresh 24803 requestLayout(); 24804 invalidate(true); 24805 } 24806 } 24807 24808 /** 24809 * Return the resolved text direction. 24810 * 24811 * @return the resolved text direction. Returns one of: 24812 * 24813 * {@link #TEXT_DIRECTION_FIRST_STRONG}, 24814 * {@link #TEXT_DIRECTION_ANY_RTL}, 24815 * {@link #TEXT_DIRECTION_LTR}, 24816 * {@link #TEXT_DIRECTION_RTL}, 24817 * {@link #TEXT_DIRECTION_LOCALE}, 24818 * {@link #TEXT_DIRECTION_FIRST_STRONG_LTR}, 24819 * {@link #TEXT_DIRECTION_FIRST_STRONG_RTL} 24820 * 24821 * @attr ref android.R.styleable#View_textDirection 24822 */ 24823 @ViewDebug.ExportedProperty(category = "text", mapping = { 24824 @ViewDebug.IntToString(from = TEXT_DIRECTION_INHERIT, to = "INHERIT"), 24825 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG, to = "FIRST_STRONG"), 24826 @ViewDebug.IntToString(from = TEXT_DIRECTION_ANY_RTL, to = "ANY_RTL"), 24827 @ViewDebug.IntToString(from = TEXT_DIRECTION_LTR, to = "LTR"), 24828 @ViewDebug.IntToString(from = TEXT_DIRECTION_RTL, to = "RTL"), 24829 @ViewDebug.IntToString(from = TEXT_DIRECTION_LOCALE, to = "LOCALE"), 24830 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_LTR, to = "FIRST_STRONG_LTR"), 24831 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_RTL, to = "FIRST_STRONG_RTL") 24832 }) 24833 public int getTextDirection() { 24834 return (mPrivateFlags2 & PFLAG2_TEXT_DIRECTION_RESOLVED_MASK) >> PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT; 24835 } 24836 24837 /** 24838 * Resolve the text direction. 24839 * 24840 * @return true if resolution has been done, false otherwise. 24841 * 24842 * @hide 24843 */ 24844 public boolean resolveTextDirection() { 24845 // Reset any previous text direction resolution 24846 mPrivateFlags2 &= ~(PFLAG2_TEXT_DIRECTION_RESOLVED | PFLAG2_TEXT_DIRECTION_RESOLVED_MASK); 24847 24848 if (hasRtlSupport()) { 24849 // Set resolved text direction flag depending on text direction flag 24850 final int textDirection = getRawTextDirection(); 24851 switch(textDirection) { 24852 case TEXT_DIRECTION_INHERIT: 24853 if (!canResolveTextDirection()) { 24854 // We cannot do the resolution if there is no parent, so use the default one 24855 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 24856 // Resolution will need to happen again later 24857 return false; 24858 } 24859 24860 // Parent has not yet resolved, so we still return the default 24861 try { 24862 if (!mParent.isTextDirectionResolved()) { 24863 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 24864 // Resolution will need to happen again later 24865 return false; 24866 } 24867 } catch (AbstractMethodError e) { 24868 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 24869 " does not fully implement ViewParent", e); 24870 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED | 24871 PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 24872 return true; 24873 } 24874 24875 // Set current resolved direction to the same value as the parent's one 24876 int parentResolvedDirection; 24877 try { 24878 parentResolvedDirection = mParent.getTextDirection(); 24879 } catch (AbstractMethodError e) { 24880 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 24881 " does not fully implement ViewParent", e); 24882 parentResolvedDirection = TEXT_DIRECTION_LTR; 24883 } 24884 switch (parentResolvedDirection) { 24885 case TEXT_DIRECTION_FIRST_STRONG: 24886 case TEXT_DIRECTION_ANY_RTL: 24887 case TEXT_DIRECTION_LTR: 24888 case TEXT_DIRECTION_RTL: 24889 case TEXT_DIRECTION_LOCALE: 24890 case TEXT_DIRECTION_FIRST_STRONG_LTR: 24891 case TEXT_DIRECTION_FIRST_STRONG_RTL: 24892 mPrivateFlags2 |= 24893 (parentResolvedDirection << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT); 24894 break; 24895 default: 24896 // Default resolved direction is "first strong" heuristic 24897 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 24898 } 24899 break; 24900 case TEXT_DIRECTION_FIRST_STRONG: 24901 case TEXT_DIRECTION_ANY_RTL: 24902 case TEXT_DIRECTION_LTR: 24903 case TEXT_DIRECTION_RTL: 24904 case TEXT_DIRECTION_LOCALE: 24905 case TEXT_DIRECTION_FIRST_STRONG_LTR: 24906 case TEXT_DIRECTION_FIRST_STRONG_RTL: 24907 // Resolved direction is the same as text direction 24908 mPrivateFlags2 |= (textDirection << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT); 24909 break; 24910 default: 24911 // Default resolved direction is "first strong" heuristic 24912 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 24913 } 24914 } else { 24915 // Default resolved direction is "first strong" heuristic 24916 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 24917 } 24918 24919 // Set to resolved 24920 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED; 24921 return true; 24922 } 24923 24924 /** 24925 * Check if text direction resolution can be done. 24926 * 24927 * @return true if text direction resolution can be done otherwise return false. 24928 */ 24929 public boolean canResolveTextDirection() { 24930 switch (getRawTextDirection()) { 24931 case TEXT_DIRECTION_INHERIT: 24932 if (mParent != null) { 24933 try { 24934 return mParent.canResolveTextDirection(); 24935 } catch (AbstractMethodError e) { 24936 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 24937 " does not fully implement ViewParent", e); 24938 } 24939 } 24940 return false; 24941 24942 default: 24943 return true; 24944 } 24945 } 24946 24947 /** 24948 * Reset resolved text direction. Text direction will be resolved during a call to 24949 * {@link #onMeasure(int, int)}. 24950 * 24951 * @hide 24952 */ 24953 public void resetResolvedTextDirection() { 24954 // Reset any previous text direction resolution 24955 mPrivateFlags2 &= ~(PFLAG2_TEXT_DIRECTION_RESOLVED | PFLAG2_TEXT_DIRECTION_RESOLVED_MASK); 24956 // Set to default value 24957 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 24958 } 24959 24960 /** 24961 * @return true if text direction is inherited. 24962 * 24963 * @hide 24964 */ 24965 public boolean isTextDirectionInherited() { 24966 return (getRawTextDirection() == TEXT_DIRECTION_INHERIT); 24967 } 24968 24969 /** 24970 * @return true if text direction is resolved. 24971 */ 24972 public boolean isTextDirectionResolved() { 24973 return (mPrivateFlags2 & PFLAG2_TEXT_DIRECTION_RESOLVED) == PFLAG2_TEXT_DIRECTION_RESOLVED; 24974 } 24975 24976 /** 24977 * Return the value specifying the text alignment or policy that was set with 24978 * {@link #setTextAlignment(int)}. 24979 * 24980 * @return the defined text alignment. It can be one of: 24981 * 24982 * {@link #TEXT_ALIGNMENT_INHERIT}, 24983 * {@link #TEXT_ALIGNMENT_GRAVITY}, 24984 * {@link #TEXT_ALIGNMENT_CENTER}, 24985 * {@link #TEXT_ALIGNMENT_TEXT_START}, 24986 * {@link #TEXT_ALIGNMENT_TEXT_END}, 24987 * {@link #TEXT_ALIGNMENT_VIEW_START}, 24988 * {@link #TEXT_ALIGNMENT_VIEW_END} 24989 * 24990 * @attr ref android.R.styleable#View_textAlignment 24991 * 24992 * @hide 24993 */ 24994 @ViewDebug.ExportedProperty(category = "text", mapping = { 24995 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_INHERIT, to = "INHERIT"), 24996 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_GRAVITY, to = "GRAVITY"), 24997 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_TEXT_START, to = "TEXT_START"), 24998 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_TEXT_END, to = "TEXT_END"), 24999 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_CENTER, to = "CENTER"), 25000 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_START, to = "VIEW_START"), 25001 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_END, to = "VIEW_END") 25002 }) 25003 @TextAlignment 25004 public int getRawTextAlignment() { 25005 return (mPrivateFlags2 & PFLAG2_TEXT_ALIGNMENT_MASK) >> PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT; 25006 } 25007 25008 /** 25009 * Set the text alignment. 25010 * 25011 * @param textAlignment The text alignment to set. Should be one of 25012 * 25013 * {@link #TEXT_ALIGNMENT_INHERIT}, 25014 * {@link #TEXT_ALIGNMENT_GRAVITY}, 25015 * {@link #TEXT_ALIGNMENT_CENTER}, 25016 * {@link #TEXT_ALIGNMENT_TEXT_START}, 25017 * {@link #TEXT_ALIGNMENT_TEXT_END}, 25018 * {@link #TEXT_ALIGNMENT_VIEW_START}, 25019 * {@link #TEXT_ALIGNMENT_VIEW_END} 25020 * 25021 * Resolution will be done if the value is set to TEXT_ALIGNMENT_INHERIT. The resolution 25022 * proceeds up the parent chain of the view to get the value. If there is no parent, then it 25023 * will return the default {@link #TEXT_ALIGNMENT_GRAVITY}. 25024 * 25025 * @attr ref android.R.styleable#View_textAlignment 25026 */ 25027 public void setTextAlignment(@TextAlignment int textAlignment) { 25028 if (textAlignment != getRawTextAlignment()) { 25029 // Reset the current and resolved text alignment 25030 mPrivateFlags2 &= ~PFLAG2_TEXT_ALIGNMENT_MASK; 25031 resetResolvedTextAlignment(); 25032 // Set the new text alignment 25033 mPrivateFlags2 |= 25034 ((textAlignment << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT) & PFLAG2_TEXT_ALIGNMENT_MASK); 25035 // Do resolution 25036 resolveTextAlignment(); 25037 // Notify change 25038 onRtlPropertiesChanged(getLayoutDirection()); 25039 // Refresh 25040 requestLayout(); 25041 invalidate(true); 25042 } 25043 } 25044 25045 /** 25046 * Return the resolved text alignment. 25047 * 25048 * @return the resolved text alignment. Returns one of: 25049 * 25050 * {@link #TEXT_ALIGNMENT_GRAVITY}, 25051 * {@link #TEXT_ALIGNMENT_CENTER}, 25052 * {@link #TEXT_ALIGNMENT_TEXT_START}, 25053 * {@link #TEXT_ALIGNMENT_TEXT_END}, 25054 * {@link #TEXT_ALIGNMENT_VIEW_START}, 25055 * {@link #TEXT_ALIGNMENT_VIEW_END} 25056 * 25057 * @attr ref android.R.styleable#View_textAlignment 25058 */ 25059 @ViewDebug.ExportedProperty(category = "text", mapping = { 25060 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_INHERIT, to = "INHERIT"), 25061 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_GRAVITY, to = "GRAVITY"), 25062 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_TEXT_START, to = "TEXT_START"), 25063 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_TEXT_END, to = "TEXT_END"), 25064 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_CENTER, to = "CENTER"), 25065 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_START, to = "VIEW_START"), 25066 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_END, to = "VIEW_END") 25067 }) 25068 @TextAlignment 25069 public int getTextAlignment() { 25070 return (mPrivateFlags2 & PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK) >> 25071 PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT; 25072 } 25073 25074 /** 25075 * Resolve the text alignment. 25076 * 25077 * @return true if resolution has been done, false otherwise. 25078 * 25079 * @hide 25080 */ 25081 public boolean resolveTextAlignment() { 25082 // Reset any previous text alignment resolution 25083 mPrivateFlags2 &= ~(PFLAG2_TEXT_ALIGNMENT_RESOLVED | PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK); 25084 25085 if (hasRtlSupport()) { 25086 // Set resolved text alignment flag depending on text alignment flag 25087 final int textAlignment = getRawTextAlignment(); 25088 switch (textAlignment) { 25089 case TEXT_ALIGNMENT_INHERIT: 25090 // Check if we can resolve the text alignment 25091 if (!canResolveTextAlignment()) { 25092 // We cannot do the resolution if there is no parent so use the default 25093 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 25094 // Resolution will need to happen again later 25095 return false; 25096 } 25097 25098 // Parent has not yet resolved, so we still return the default 25099 try { 25100 if (!mParent.isTextAlignmentResolved()) { 25101 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 25102 // Resolution will need to happen again later 25103 return false; 25104 } 25105 } catch (AbstractMethodError e) { 25106 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 25107 " does not fully implement ViewParent", e); 25108 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED | 25109 PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 25110 return true; 25111 } 25112 25113 int parentResolvedTextAlignment; 25114 try { 25115 parentResolvedTextAlignment = mParent.getTextAlignment(); 25116 } catch (AbstractMethodError e) { 25117 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 25118 " does not fully implement ViewParent", e); 25119 parentResolvedTextAlignment = TEXT_ALIGNMENT_GRAVITY; 25120 } 25121 switch (parentResolvedTextAlignment) { 25122 case TEXT_ALIGNMENT_GRAVITY: 25123 case TEXT_ALIGNMENT_TEXT_START: 25124 case TEXT_ALIGNMENT_TEXT_END: 25125 case TEXT_ALIGNMENT_CENTER: 25126 case TEXT_ALIGNMENT_VIEW_START: 25127 case TEXT_ALIGNMENT_VIEW_END: 25128 // Resolved text alignment is the same as the parent resolved 25129 // text alignment 25130 mPrivateFlags2 |= 25131 (parentResolvedTextAlignment << PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT); 25132 break; 25133 default: 25134 // Use default resolved text alignment 25135 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 25136 } 25137 break; 25138 case TEXT_ALIGNMENT_GRAVITY: 25139 case TEXT_ALIGNMENT_TEXT_START: 25140 case TEXT_ALIGNMENT_TEXT_END: 25141 case TEXT_ALIGNMENT_CENTER: 25142 case TEXT_ALIGNMENT_VIEW_START: 25143 case TEXT_ALIGNMENT_VIEW_END: 25144 // Resolved text alignment is the same as text alignment 25145 mPrivateFlags2 |= (textAlignment << PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT); 25146 break; 25147 default: 25148 // Use default resolved text alignment 25149 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 25150 } 25151 } else { 25152 // Use default resolved text alignment 25153 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 25154 } 25155 25156 // Set the resolved 25157 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED; 25158 return true; 25159 } 25160 25161 /** 25162 * Check if text alignment resolution can be done. 25163 * 25164 * @return true if text alignment resolution can be done otherwise return false. 25165 */ 25166 public boolean canResolveTextAlignment() { 25167 switch (getRawTextAlignment()) { 25168 case TEXT_DIRECTION_INHERIT: 25169 if (mParent != null) { 25170 try { 25171 return mParent.canResolveTextAlignment(); 25172 } catch (AbstractMethodError e) { 25173 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 25174 " does not fully implement ViewParent", e); 25175 } 25176 } 25177 return false; 25178 25179 default: 25180 return true; 25181 } 25182 } 25183 25184 /** 25185 * Reset resolved text alignment. Text alignment will be resolved during a call to 25186 * {@link #onMeasure(int, int)}. 25187 * 25188 * @hide 25189 */ 25190 public void resetResolvedTextAlignment() { 25191 // Reset any previous text alignment resolution 25192 mPrivateFlags2 &= ~(PFLAG2_TEXT_ALIGNMENT_RESOLVED | PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK); 25193 // Set to default 25194 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 25195 } 25196 25197 /** 25198 * @return true if text alignment is inherited. 25199 * 25200 * @hide 25201 */ 25202 public boolean isTextAlignmentInherited() { 25203 return (getRawTextAlignment() == TEXT_ALIGNMENT_INHERIT); 25204 } 25205 25206 /** 25207 * @return true if text alignment is resolved. 25208 */ 25209 public boolean isTextAlignmentResolved() { 25210 return (mPrivateFlags2 & PFLAG2_TEXT_ALIGNMENT_RESOLVED) == PFLAG2_TEXT_ALIGNMENT_RESOLVED; 25211 } 25212 25213 /** 25214 * Generate a value suitable for use in {@link #setId(int)}. 25215 * This value will not collide with ID values generated at build time by aapt for R.id. 25216 * 25217 * @return a generated ID value 25218 */ 25219 public static int generateViewId() { 25220 for (;;) { 25221 final int result = sNextGeneratedId.get(); 25222 // aapt-generated IDs have the high byte nonzero; clamp to the range under that. 25223 int newValue = result + 1; 25224 if (newValue > 0x00FFFFFF) newValue = 1; // Roll over to 1, not 0. 25225 if (sNextGeneratedId.compareAndSet(result, newValue)) { 25226 return result; 25227 } 25228 } 25229 } 25230 25231 private static boolean isViewIdGenerated(int id) { 25232 return (id & 0xFF000000) == 0 && (id & 0x00FFFFFF) != 0; 25233 } 25234 25235 /** 25236 * Gets the Views in the hierarchy affected by entering and exiting Activity Scene transitions. 25237 * @param transitioningViews This View will be added to transitioningViews if it is VISIBLE and 25238 * a normal View or a ViewGroup with 25239 * {@link android.view.ViewGroup#isTransitionGroup()} true. 25240 * @hide 25241 */ 25242 public void captureTransitioningViews(List<View> transitioningViews) { 25243 if (getVisibility() == View.VISIBLE) { 25244 transitioningViews.add(this); 25245 } 25246 } 25247 25248 /** 25249 * Adds all Views that have {@link #getTransitionName()} non-null to namedElements. 25250 * @param namedElements Will contain all Views in the hierarchy having a transitionName. 25251 * @hide 25252 */ 25253 public void findNamedViews(Map<String, View> namedElements) { 25254 if (getVisibility() == VISIBLE || mGhostView != null) { 25255 String transitionName = getTransitionName(); 25256 if (transitionName != null) { 25257 namedElements.put(transitionName, this); 25258 } 25259 } 25260 } 25261 25262 /** 25263 * Returns the pointer icon for the motion event, or null if it doesn't specify the icon. 25264 * The default implementation does not care the location or event types, but some subclasses 25265 * may use it (such as WebViews). 25266 * @param event The MotionEvent from a mouse 25267 * @param pointerIndex The index of the pointer for which to retrieve the {@link PointerIcon}. 25268 * This will be between 0 and {@link MotionEvent#getPointerCount()}. 25269 * @see PointerIcon 25270 */ 25271 public PointerIcon onResolvePointerIcon(MotionEvent event, int pointerIndex) { 25272 final float x = event.getX(pointerIndex); 25273 final float y = event.getY(pointerIndex); 25274 if (isDraggingScrollBar() || isOnScrollbarThumb(x, y)) { 25275 return PointerIcon.getSystemIcon(mContext, PointerIcon.TYPE_ARROW); 25276 } 25277 return mPointerIcon; 25278 } 25279 25280 /** 25281 * Set the pointer icon for the current view. 25282 * Passing {@code null} will restore the pointer icon to its default value. 25283 * @param pointerIcon A PointerIcon instance which will be shown when the mouse hovers. 25284 */ 25285 public void setPointerIcon(PointerIcon pointerIcon) { 25286 mPointerIcon = pointerIcon; 25287 if (mAttachInfo == null || mAttachInfo.mHandlingPointerEvent) { 25288 return; 25289 } 25290 try { 25291 mAttachInfo.mSession.updatePointerIcon(mAttachInfo.mWindow); 25292 } catch (RemoteException e) { 25293 } 25294 } 25295 25296 /** 25297 * Gets the pointer icon for the current view. 25298 */ 25299 public PointerIcon getPointerIcon() { 25300 return mPointerIcon; 25301 } 25302 25303 /** 25304 * Checks pointer capture status. 25305 * 25306 * @return true if the view has pointer capture. 25307 * @see #requestPointerCapture() 25308 * @see #hasPointerCapture() 25309 */ 25310 public boolean hasPointerCapture() { 25311 final ViewRootImpl viewRootImpl = getViewRootImpl(); 25312 if (viewRootImpl == null) { 25313 return false; 25314 } 25315 return viewRootImpl.hasPointerCapture(); 25316 } 25317 25318 /** 25319 * Requests pointer capture mode. 25320 * <p> 25321 * When the window has pointer capture, the mouse pointer icon will disappear and will not 25322 * change its position. Further mouse will be dispatched with the source 25323 * {@link InputDevice#SOURCE_MOUSE_RELATIVE}, and relative position changes will be available 25324 * through {@link MotionEvent#getX} and {@link MotionEvent#getY}. Non-mouse events 25325 * (touchscreens, or stylus) will not be affected. 25326 * <p> 25327 * If the window already has pointer capture, this call does nothing. 25328 * <p> 25329 * The capture may be released through {@link #releasePointerCapture()}, or will be lost 25330 * automatically when the window loses focus. 25331 * 25332 * @see #releasePointerCapture() 25333 * @see #hasPointerCapture() 25334 */ 25335 public void requestPointerCapture() { 25336 final ViewRootImpl viewRootImpl = getViewRootImpl(); 25337 if (viewRootImpl != null) { 25338 viewRootImpl.requestPointerCapture(true); 25339 } 25340 } 25341 25342 25343 /** 25344 * Releases the pointer capture. 25345 * <p> 25346 * If the window does not have pointer capture, this call will do nothing. 25347 * @see #requestPointerCapture() 25348 * @see #hasPointerCapture() 25349 */ 25350 public void releasePointerCapture() { 25351 final ViewRootImpl viewRootImpl = getViewRootImpl(); 25352 if (viewRootImpl != null) { 25353 viewRootImpl.requestPointerCapture(false); 25354 } 25355 } 25356 25357 /** 25358 * Called when the window has just acquired or lost pointer capture. 25359 * 25360 * @param hasCapture True if the view now has pointerCapture, false otherwise. 25361 */ 25362 @CallSuper 25363 public void onPointerCaptureChange(boolean hasCapture) { 25364 } 25365 25366 /** 25367 * @see #onPointerCaptureChange 25368 */ 25369 public void dispatchPointerCaptureChanged(boolean hasCapture) { 25370 onPointerCaptureChange(hasCapture); 25371 } 25372 25373 /** 25374 * Implement this method to handle captured pointer events 25375 * 25376 * @param event The captured pointer event. 25377 * @return True if the event was handled, false otherwise. 25378 * @see #requestPointerCapture() 25379 */ 25380 public boolean onCapturedPointerEvent(MotionEvent event) { 25381 return false; 25382 } 25383 25384 /** 25385 * Interface definition for a callback to be invoked when a captured pointer event 25386 * is being dispatched this view. The callback will be invoked before the event is 25387 * given to the view. 25388 */ 25389 public interface OnCapturedPointerListener { 25390 /** 25391 * Called when a captured pointer event is dispatched to a view. 25392 * @param view The view this event has been dispatched to. 25393 * @param event The captured event. 25394 * @return True if the listener has consumed the event, false otherwise. 25395 */ 25396 boolean onCapturedPointer(View view, MotionEvent event); 25397 } 25398 25399 /** 25400 * Set a listener to receive callbacks when the pointer capture state of a view changes. 25401 * @param l The {@link OnCapturedPointerListener} to receive callbacks. 25402 */ 25403 public void setOnCapturedPointerListener(OnCapturedPointerListener l) { 25404 getListenerInfo().mOnCapturedPointerListener = l; 25405 } 25406 25407 // Properties 25408 // 25409 /** 25410 * A Property wrapper around the <code>alpha</code> functionality handled by the 25411 * {@link View#setAlpha(float)} and {@link View#getAlpha()} methods. 25412 */ 25413 public static final Property<View, Float> ALPHA = new FloatProperty<View>("alpha") { 25414 @Override 25415 public void setValue(View object, float value) { 25416 object.setAlpha(value); 25417 } 25418 25419 @Override 25420 public Float get(View object) { 25421 return object.getAlpha(); 25422 } 25423 }; 25424 25425 /** 25426 * A Property wrapper around the <code>translationX</code> functionality handled by the 25427 * {@link View#setTranslationX(float)} and {@link View#getTranslationX()} methods. 25428 */ 25429 public static final Property<View, Float> TRANSLATION_X = new FloatProperty<View>("translationX") { 25430 @Override 25431 public void setValue(View object, float value) { 25432 object.setTranslationX(value); 25433 } 25434 25435 @Override 25436 public Float get(View object) { 25437 return object.getTranslationX(); 25438 } 25439 }; 25440 25441 /** 25442 * A Property wrapper around the <code>translationY</code> functionality handled by the 25443 * {@link View#setTranslationY(float)} and {@link View#getTranslationY()} methods. 25444 */ 25445 public static final Property<View, Float> TRANSLATION_Y = new FloatProperty<View>("translationY") { 25446 @Override 25447 public void setValue(View object, float value) { 25448 object.setTranslationY(value); 25449 } 25450 25451 @Override 25452 public Float get(View object) { 25453 return object.getTranslationY(); 25454 } 25455 }; 25456 25457 /** 25458 * A Property wrapper around the <code>translationZ</code> functionality handled by the 25459 * {@link View#setTranslationZ(float)} and {@link View#getTranslationZ()} methods. 25460 */ 25461 public static final Property<View, Float> TRANSLATION_Z = new FloatProperty<View>("translationZ") { 25462 @Override 25463 public void setValue(View object, float value) { 25464 object.setTranslationZ(value); 25465 } 25466 25467 @Override 25468 public Float get(View object) { 25469 return object.getTranslationZ(); 25470 } 25471 }; 25472 25473 /** 25474 * A Property wrapper around the <code>x</code> functionality handled by the 25475 * {@link View#setX(float)} and {@link View#getX()} methods. 25476 */ 25477 public static final Property<View, Float> X = new FloatProperty<View>("x") { 25478 @Override 25479 public void setValue(View object, float value) { 25480 object.setX(value); 25481 } 25482 25483 @Override 25484 public Float get(View object) { 25485 return object.getX(); 25486 } 25487 }; 25488 25489 /** 25490 * A Property wrapper around the <code>y</code> functionality handled by the 25491 * {@link View#setY(float)} and {@link View#getY()} methods. 25492 */ 25493 public static final Property<View, Float> Y = new FloatProperty<View>("y") { 25494 @Override 25495 public void setValue(View object, float value) { 25496 object.setY(value); 25497 } 25498 25499 @Override 25500 public Float get(View object) { 25501 return object.getY(); 25502 } 25503 }; 25504 25505 /** 25506 * A Property wrapper around the <code>z</code> functionality handled by the 25507 * {@link View#setZ(float)} and {@link View#getZ()} methods. 25508 */ 25509 public static final Property<View, Float> Z = new FloatProperty<View>("z") { 25510 @Override 25511 public void setValue(View object, float value) { 25512 object.setZ(value); 25513 } 25514 25515 @Override 25516 public Float get(View object) { 25517 return object.getZ(); 25518 } 25519 }; 25520 25521 /** 25522 * A Property wrapper around the <code>rotation</code> functionality handled by the 25523 * {@link View#setRotation(float)} and {@link View#getRotation()} methods. 25524 */ 25525 public static final Property<View, Float> ROTATION = new FloatProperty<View>("rotation") { 25526 @Override 25527 public void setValue(View object, float value) { 25528 object.setRotation(value); 25529 } 25530 25531 @Override 25532 public Float get(View object) { 25533 return object.getRotation(); 25534 } 25535 }; 25536 25537 /** 25538 * A Property wrapper around the <code>rotationX</code> functionality handled by the 25539 * {@link View#setRotationX(float)} and {@link View#getRotationX()} methods. 25540 */ 25541 public static final Property<View, Float> ROTATION_X = new FloatProperty<View>("rotationX") { 25542 @Override 25543 public void setValue(View object, float value) { 25544 object.setRotationX(value); 25545 } 25546 25547 @Override 25548 public Float get(View object) { 25549 return object.getRotationX(); 25550 } 25551 }; 25552 25553 /** 25554 * A Property wrapper around the <code>rotationY</code> functionality handled by the 25555 * {@link View#setRotationY(float)} and {@link View#getRotationY()} methods. 25556 */ 25557 public static final Property<View, Float> ROTATION_Y = new FloatProperty<View>("rotationY") { 25558 @Override 25559 public void setValue(View object, float value) { 25560 object.setRotationY(value); 25561 } 25562 25563 @Override 25564 public Float get(View object) { 25565 return object.getRotationY(); 25566 } 25567 }; 25568 25569 /** 25570 * A Property wrapper around the <code>scaleX</code> functionality handled by the 25571 * {@link View#setScaleX(float)} and {@link View#getScaleX()} methods. 25572 */ 25573 public static final Property<View, Float> SCALE_X = new FloatProperty<View>("scaleX") { 25574 @Override 25575 public void setValue(View object, float value) { 25576 object.setScaleX(value); 25577 } 25578 25579 @Override 25580 public Float get(View object) { 25581 return object.getScaleX(); 25582 } 25583 }; 25584 25585 /** 25586 * A Property wrapper around the <code>scaleY</code> functionality handled by the 25587 * {@link View#setScaleY(float)} and {@link View#getScaleY()} methods. 25588 */ 25589 public static final Property<View, Float> SCALE_Y = new FloatProperty<View>("scaleY") { 25590 @Override 25591 public void setValue(View object, float value) { 25592 object.setScaleY(value); 25593 } 25594 25595 @Override 25596 public Float get(View object) { 25597 return object.getScaleY(); 25598 } 25599 }; 25600 25601 /** 25602 * A MeasureSpec encapsulates the layout requirements passed from parent to child. 25603 * Each MeasureSpec represents a requirement for either the width or the height. 25604 * A MeasureSpec is comprised of a size and a mode. There are three possible 25605 * modes: 25606 * <dl> 25607 * <dt>UNSPECIFIED</dt> 25608 * <dd> 25609 * The parent has not imposed any constraint on the child. It can be whatever size 25610 * it wants. 25611 * </dd> 25612 * 25613 * <dt>EXACTLY</dt> 25614 * <dd> 25615 * The parent has determined an exact size for the child. The child is going to be 25616 * given those bounds regardless of how big it wants to be. 25617 * </dd> 25618 * 25619 * <dt>AT_MOST</dt> 25620 * <dd> 25621 * The child can be as large as it wants up to the specified size. 25622 * </dd> 25623 * </dl> 25624 * 25625 * MeasureSpecs are implemented as ints to reduce object allocation. This class 25626 * is provided to pack and unpack the <size, mode> tuple into the int. 25627 */ 25628 public static class MeasureSpec { 25629 private static final int MODE_SHIFT = 30; 25630 private static final int MODE_MASK = 0x3 << MODE_SHIFT; 25631 25632 /** @hide */ 25633 @IntDef({UNSPECIFIED, EXACTLY, AT_MOST}) 25634 @Retention(RetentionPolicy.SOURCE) 25635 public @interface MeasureSpecMode {} 25636 25637 /** 25638 * Measure specification mode: The parent has not imposed any constraint 25639 * on the child. It can be whatever size it wants. 25640 */ 25641 public static final int UNSPECIFIED = 0 << MODE_SHIFT; 25642 25643 /** 25644 * Measure specification mode: The parent has determined an exact size 25645 * for the child. The child is going to be given those bounds regardless 25646 * of how big it wants to be. 25647 */ 25648 public static final int EXACTLY = 1 << MODE_SHIFT; 25649 25650 /** 25651 * Measure specification mode: The child can be as large as it wants up 25652 * to the specified size. 25653 */ 25654 public static final int AT_MOST = 2 << MODE_SHIFT; 25655 25656 /** 25657 * Creates a measure specification based on the supplied size and mode. 25658 * 25659 * The mode must always be one of the following: 25660 * <ul> 25661 * <li>{@link android.view.View.MeasureSpec#UNSPECIFIED}</li> 25662 * <li>{@link android.view.View.MeasureSpec#EXACTLY}</li> 25663 * <li>{@link android.view.View.MeasureSpec#AT_MOST}</li> 25664 * </ul> 25665 * 25666 * <p><strong>Note:</strong> On API level 17 and lower, makeMeasureSpec's 25667 * implementation was such that the order of arguments did not matter 25668 * and overflow in either value could impact the resulting MeasureSpec. 25669 * {@link android.widget.RelativeLayout} was affected by this bug. 25670 * Apps targeting API levels greater than 17 will get the fixed, more strict 25671 * behavior.</p> 25672 * 25673 * @param size the size of the measure specification 25674 * @param mode the mode of the measure specification 25675 * @return the measure specification based on size and mode 25676 */ 25677 public static int makeMeasureSpec(@IntRange(from = 0, to = (1 << MeasureSpec.MODE_SHIFT) - 1) int size, 25678 @MeasureSpecMode int mode) { 25679 if (sUseBrokenMakeMeasureSpec) { 25680 return size + mode; 25681 } else { 25682 return (size & ~MODE_MASK) | (mode & MODE_MASK); 25683 } 25684 } 25685 25686 /** 25687 * Like {@link #makeMeasureSpec(int, int)}, but any spec with a mode of UNSPECIFIED 25688 * will automatically get a size of 0. Older apps expect this. 25689 * 25690 * @hide internal use only for compatibility with system widgets and older apps 25691 */ 25692 public static int makeSafeMeasureSpec(int size, int mode) { 25693 if (sUseZeroUnspecifiedMeasureSpec && mode == UNSPECIFIED) { 25694 return 0; 25695 } 25696 return makeMeasureSpec(size, mode); 25697 } 25698 25699 /** 25700 * Extracts the mode from the supplied measure specification. 25701 * 25702 * @param measureSpec the measure specification to extract the mode from 25703 * @return {@link android.view.View.MeasureSpec#UNSPECIFIED}, 25704 * {@link android.view.View.MeasureSpec#AT_MOST} or 25705 * {@link android.view.View.MeasureSpec#EXACTLY} 25706 */ 25707 @MeasureSpecMode 25708 public static int getMode(int measureSpec) { 25709 //noinspection ResourceType 25710 return (measureSpec & MODE_MASK); 25711 } 25712 25713 /** 25714 * Extracts the size from the supplied measure specification. 25715 * 25716 * @param measureSpec the measure specification to extract the size from 25717 * @return the size in pixels defined in the supplied measure specification 25718 */ 25719 public static int getSize(int measureSpec) { 25720 return (measureSpec & ~MODE_MASK); 25721 } 25722 25723 static int adjust(int measureSpec, int delta) { 25724 final int mode = getMode(measureSpec); 25725 int size = getSize(measureSpec); 25726 if (mode == UNSPECIFIED) { 25727 // No need to adjust size for UNSPECIFIED mode. 25728 return makeMeasureSpec(size, UNSPECIFIED); 25729 } 25730 size += delta; 25731 if (size < 0) { 25732 Log.e(VIEW_LOG_TAG, "MeasureSpec.adjust: new size would be negative! (" + size + 25733 ") spec: " + toString(measureSpec) + " delta: " + delta); 25734 size = 0; 25735 } 25736 return makeMeasureSpec(size, mode); 25737 } 25738 25739 /** 25740 * Returns a String representation of the specified measure 25741 * specification. 25742 * 25743 * @param measureSpec the measure specification to convert to a String 25744 * @return a String with the following format: "MeasureSpec: MODE SIZE" 25745 */ 25746 public static String toString(int measureSpec) { 25747 int mode = getMode(measureSpec); 25748 int size = getSize(measureSpec); 25749 25750 StringBuilder sb = new StringBuilder("MeasureSpec: "); 25751 25752 if (mode == UNSPECIFIED) 25753 sb.append("UNSPECIFIED "); 25754 else if (mode == EXACTLY) 25755 sb.append("EXACTLY "); 25756 else if (mode == AT_MOST) 25757 sb.append("AT_MOST "); 25758 else 25759 sb.append(mode).append(" "); 25760 25761 sb.append(size); 25762 return sb.toString(); 25763 } 25764 } 25765 25766 private final class CheckForLongPress implements Runnable { 25767 private int mOriginalWindowAttachCount; 25768 private float mX; 25769 private float mY; 25770 private boolean mOriginalPressedState; 25771 25772 @Override 25773 public void run() { 25774 if ((mOriginalPressedState == isPressed()) && (mParent != null) 25775 && mOriginalWindowAttachCount == mWindowAttachCount) { 25776 if (performLongClick(mX, mY)) { 25777 mHasPerformedLongPress = true; 25778 } 25779 } 25780 } 25781 25782 public void setAnchor(float x, float y) { 25783 mX = x; 25784 mY = y; 25785 } 25786 25787 public void rememberWindowAttachCount() { 25788 mOriginalWindowAttachCount = mWindowAttachCount; 25789 } 25790 25791 public void rememberPressedState() { 25792 mOriginalPressedState = isPressed(); 25793 } 25794 } 25795 25796 private final class CheckForTap implements Runnable { 25797 public float x; 25798 public float y; 25799 25800 @Override 25801 public void run() { 25802 mPrivateFlags &= ~PFLAG_PREPRESSED; 25803 setPressed(true, x, y); 25804 checkForLongClick(ViewConfiguration.getTapTimeout(), x, y); 25805 } 25806 } 25807 25808 private final class PerformClick implements Runnable { 25809 @Override 25810 public void run() { 25811 performClickInternal(); 25812 } 25813 } 25814 25815 /** 25816 * This method returns a ViewPropertyAnimator object, which can be used to animate 25817 * specific properties on this View. 25818 * 25819 * @return ViewPropertyAnimator The ViewPropertyAnimator associated with this View. 25820 */ 25821 public ViewPropertyAnimator animate() { 25822 if (mAnimator == null) { 25823 mAnimator = new ViewPropertyAnimator(this); 25824 } 25825 return mAnimator; 25826 } 25827 25828 /** 25829 * Sets the name of the View to be used to identify Views in Transitions. 25830 * Names should be unique in the View hierarchy. 25831 * 25832 * @param transitionName The name of the View to uniquely identify it for Transitions. 25833 */ 25834 public final void setTransitionName(String transitionName) { 25835 mTransitionName = transitionName; 25836 } 25837 25838 /** 25839 * Returns the name of the View to be used to identify Views in Transitions. 25840 * Names should be unique in the View hierarchy. 25841 * 25842 * <p>This returns null if the View has not been given a name.</p> 25843 * 25844 * @return The name used of the View to be used to identify Views in Transitions or null 25845 * if no name has been given. 25846 */ 25847 @ViewDebug.ExportedProperty 25848 public String getTransitionName() { 25849 return mTransitionName; 25850 } 25851 25852 /** 25853 * @hide 25854 */ 25855 public void requestKeyboardShortcuts(List<KeyboardShortcutGroup> data, int deviceId) { 25856 // Do nothing. 25857 } 25858 25859 /** 25860 * Interface definition for a callback to be invoked when a hardware key event is 25861 * dispatched to this view. The callback will be invoked before the key event is 25862 * given to the view. This is only useful for hardware keyboards; a software input 25863 * method has no obligation to trigger this listener. 25864 */ 25865 public interface OnKeyListener { 25866 /** 25867 * Called when a hardware key is dispatched to a view. This allows listeners to 25868 * get a chance to respond before the target view. 25869 * <p>Key presses in software keyboards will generally NOT trigger this method, 25870 * although some may elect to do so in some situations. Do not assume a 25871 * software input method has to be key-based; even if it is, it may use key presses 25872 * in a different way than you expect, so there is no way to reliably catch soft 25873 * input key presses. 25874 * 25875 * @param v The view the key has been dispatched to. 25876 * @param keyCode The code for the physical key that was pressed 25877 * @param event The KeyEvent object containing full information about 25878 * the event. 25879 * @return True if the listener has consumed the event, false otherwise. 25880 */ 25881 boolean onKey(View v, int keyCode, KeyEvent event); 25882 } 25883 25884 /** 25885 * Interface definition for a callback to be invoked when a hardware key event is 25886 * dispatched to this view during the fallback phase. This means no view in the hierarchy 25887 * has handled this event. 25888 */ 25889 public interface OnKeyFallbackListener { 25890 /** 25891 * Called when a hardware key is dispatched to a view in the fallback phase. This allows 25892 * listeners to respond to events after the view hierarchy has had a chance to respond. 25893 * <p>Key presses in software keyboards will generally NOT trigger this method, 25894 * although some may elect to do so in some situations. Do not assume a 25895 * software input method has to be key-based; even if it is, it may use key presses 25896 * in a different way than you expect, so there is no way to reliably catch soft 25897 * input key presses. 25898 * 25899 * @param v The view the key has been dispatched to. 25900 * @param event The KeyEvent object containing full information about 25901 * the event. 25902 * @return True if the listener has consumed the event, false otherwise. 25903 */ 25904 boolean onKeyFallback(View v, KeyEvent event); 25905 } 25906 25907 /** 25908 * Interface definition for a callback to be invoked when a touch event is 25909 * dispatched to this view. The callback will be invoked before the touch 25910 * event is given to the view. 25911 */ 25912 public interface OnTouchListener { 25913 /** 25914 * Called when a touch event is dispatched to a view. This allows listeners to 25915 * get a chance to respond before the target view. 25916 * 25917 * @param v The view the touch event has been dispatched to. 25918 * @param event The MotionEvent object containing full information about 25919 * the event. 25920 * @return True if the listener has consumed the event, false otherwise. 25921 */ 25922 boolean onTouch(View v, MotionEvent event); 25923 } 25924 25925 /** 25926 * Interface definition for a callback to be invoked when a hover event is 25927 * dispatched to this view. The callback will be invoked before the hover 25928 * event is given to the view. 25929 */ 25930 public interface OnHoverListener { 25931 /** 25932 * Called when a hover event is dispatched to a view. This allows listeners to 25933 * get a chance to respond before the target view. 25934 * 25935 * @param v The view the hover event has been dispatched to. 25936 * @param event The MotionEvent object containing full information about 25937 * the event. 25938 * @return True if the listener has consumed the event, false otherwise. 25939 */ 25940 boolean onHover(View v, MotionEvent event); 25941 } 25942 25943 /** 25944 * Interface definition for a callback to be invoked when a generic motion event is 25945 * dispatched to this view. The callback will be invoked before the generic motion 25946 * event is given to the view. 25947 */ 25948 public interface OnGenericMotionListener { 25949 /** 25950 * Called when a generic motion event is dispatched to a view. This allows listeners to 25951 * get a chance to respond before the target view. 25952 * 25953 * @param v The view the generic motion event has been dispatched to. 25954 * @param event The MotionEvent object containing full information about 25955 * the event. 25956 * @return True if the listener has consumed the event, false otherwise. 25957 */ 25958 boolean onGenericMotion(View v, MotionEvent event); 25959 } 25960 25961 /** 25962 * Interface definition for a callback to be invoked when a view has been clicked and held. 25963 */ 25964 public interface OnLongClickListener { 25965 /** 25966 * Called when a view has been clicked and held. 25967 * 25968 * @param v The view that was clicked and held. 25969 * 25970 * @return true if the callback consumed the long click, false otherwise. 25971 */ 25972 boolean onLongClick(View v); 25973 } 25974 25975 /** 25976 * Interface definition for a callback to be invoked when a drag is being dispatched 25977 * to this view. The callback will be invoked before the hosting view's own 25978 * onDrag(event) method. If the listener wants to fall back to the hosting view's 25979 * onDrag(event) behavior, it should return 'false' from this callback. 25980 * 25981 * <div class="special reference"> 25982 * <h3>Developer Guides</h3> 25983 * <p>For a guide to implementing drag and drop features, read the 25984 * <a href="{@docRoot}guide/topics/ui/drag-drop.html">Drag and Drop</a> developer guide.</p> 25985 * </div> 25986 */ 25987 public interface OnDragListener { 25988 /** 25989 * Called when a drag event is dispatched to a view. This allows listeners 25990 * to get a chance to override base View behavior. 25991 * 25992 * @param v The View that received the drag event. 25993 * @param event The {@link android.view.DragEvent} object for the drag event. 25994 * @return {@code true} if the drag event was handled successfully, or {@code false} 25995 * if the drag event was not handled. Note that {@code false} will trigger the View 25996 * to call its {@link #onDragEvent(DragEvent) onDragEvent()} handler. 25997 */ 25998 boolean onDrag(View v, DragEvent event); 25999 } 26000 26001 /** 26002 * Interface definition for a callback to be invoked when the focus state of 26003 * a view changed. 26004 */ 26005 public interface OnFocusChangeListener { 26006 /** 26007 * Called when the focus state of a view has changed. 26008 * 26009 * @param v The view whose state has changed. 26010 * @param hasFocus The new focus state of v. 26011 */ 26012 void onFocusChange(View v, boolean hasFocus); 26013 } 26014 26015 /** 26016 * Interface definition for a callback to be invoked when a view is clicked. 26017 */ 26018 public interface OnClickListener { 26019 /** 26020 * Called when a view has been clicked. 26021 * 26022 * @param v The view that was clicked. 26023 */ 26024 void onClick(View v); 26025 } 26026 26027 /** 26028 * Interface definition for a callback to be invoked when a view is context clicked. 26029 */ 26030 public interface OnContextClickListener { 26031 /** 26032 * Called when a view is context clicked. 26033 * 26034 * @param v The view that has been context clicked. 26035 * @return true if the callback consumed the context click, false otherwise. 26036 */ 26037 boolean onContextClick(View v); 26038 } 26039 26040 /** 26041 * Interface definition for a callback to be invoked when the context menu 26042 * for this view is being built. 26043 */ 26044 public interface OnCreateContextMenuListener { 26045 /** 26046 * Called when the context menu for this view is being built. It is not 26047 * safe to hold onto the menu after this method returns. 26048 * 26049 * @param menu The context menu that is being built 26050 * @param v The view for which the context menu is being built 26051 * @param menuInfo Extra information about the item for which the 26052 * context menu should be shown. This information will vary 26053 * depending on the class of v. 26054 */ 26055 void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo); 26056 } 26057 26058 /** 26059 * Interface definition for a callback to be invoked when the status bar changes 26060 * visibility. This reports <strong>global</strong> changes to the system UI 26061 * state, not what the application is requesting. 26062 * 26063 * @see View#setOnSystemUiVisibilityChangeListener(android.view.View.OnSystemUiVisibilityChangeListener) 26064 */ 26065 public interface OnSystemUiVisibilityChangeListener { 26066 /** 26067 * Called when the status bar changes visibility because of a call to 26068 * {@link View#setSystemUiVisibility(int)}. 26069 * 26070 * @param visibility Bitwise-or of flags {@link #SYSTEM_UI_FLAG_LOW_PROFILE}, 26071 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, and {@link #SYSTEM_UI_FLAG_FULLSCREEN}. 26072 * This tells you the <strong>global</strong> state of these UI visibility 26073 * flags, not what your app is currently applying. 26074 */ 26075 public void onSystemUiVisibilityChange(int visibility); 26076 } 26077 26078 /** 26079 * Interface definition for a callback to be invoked when this view is attached 26080 * or detached from its window. 26081 */ 26082 public interface OnAttachStateChangeListener { 26083 /** 26084 * Called when the view is attached to a window. 26085 * @param v The view that was attached 26086 */ 26087 public void onViewAttachedToWindow(View v); 26088 /** 26089 * Called when the view is detached from a window. 26090 * @param v The view that was detached 26091 */ 26092 public void onViewDetachedFromWindow(View v); 26093 } 26094 26095 /** 26096 * Listener for applying window insets on a view in a custom way. 26097 * 26098 * <p>Apps may choose to implement this interface if they want to apply custom policy 26099 * to the way that window insets are treated for a view. If an OnApplyWindowInsetsListener 26100 * is set, its 26101 * {@link OnApplyWindowInsetsListener#onApplyWindowInsets(View, WindowInsets) onApplyWindowInsets} 26102 * method will be called instead of the View's own 26103 * {@link #onApplyWindowInsets(WindowInsets) onApplyWindowInsets} method. The listener 26104 * may optionally call the parameter View's <code>onApplyWindowInsets</code> method to apply 26105 * the View's normal behavior as part of its own.</p> 26106 */ 26107 public interface OnApplyWindowInsetsListener { 26108 /** 26109 * When {@link View#setOnApplyWindowInsetsListener(View.OnApplyWindowInsetsListener) set} 26110 * on a View, this listener method will be called instead of the view's own 26111 * {@link View#onApplyWindowInsets(WindowInsets) onApplyWindowInsets} method. 26112 * 26113 * @param v The view applying window insets 26114 * @param insets The insets to apply 26115 * @return The insets supplied, minus any insets that were consumed 26116 */ 26117 public WindowInsets onApplyWindowInsets(View v, WindowInsets insets); 26118 } 26119 26120 private final class UnsetPressedState implements Runnable { 26121 @Override 26122 public void run() { 26123 setPressed(false); 26124 } 26125 } 26126 26127 /** 26128 * When a view becomes invisible checks if autofill considers the view invisible too. This 26129 * happens after the regular removal operation to make sure the operation is finished by the 26130 * time this is called. 26131 */ 26132 private static class VisibilityChangeForAutofillHandler extends Handler { 26133 private final AutofillManager mAfm; 26134 private final View mView; 26135 26136 private VisibilityChangeForAutofillHandler(@NonNull AutofillManager afm, 26137 @NonNull View view) { 26138 mAfm = afm; 26139 mView = view; 26140 } 26141 26142 @Override 26143 public void handleMessage(Message msg) { 26144 mAfm.notifyViewVisibilityChanged(mView, mView.isShown()); 26145 } 26146 } 26147 26148 /** 26149 * Base class for derived classes that want to save and restore their own 26150 * state in {@link android.view.View#onSaveInstanceState()}. 26151 */ 26152 public static class BaseSavedState extends AbsSavedState { 26153 static final int START_ACTIVITY_REQUESTED_WHO_SAVED = 0b1; 26154 static final int IS_AUTOFILLED = 0b10; 26155 static final int AUTOFILL_ID = 0b100; 26156 26157 // Flags that describe what data in this state is valid 26158 int mSavedData; 26159 String mStartActivityRequestWhoSaved; 26160 boolean mIsAutofilled; 26161 int mAutofillViewId; 26162 26163 /** 26164 * Constructor used when reading from a parcel. Reads the state of the superclass. 26165 * 26166 * @param source parcel to read from 26167 */ 26168 public BaseSavedState(Parcel source) { 26169 this(source, null); 26170 } 26171 26172 /** 26173 * Constructor used when reading from a parcel using a given class loader. 26174 * Reads the state of the superclass. 26175 * 26176 * @param source parcel to read from 26177 * @param loader ClassLoader to use for reading 26178 */ 26179 public BaseSavedState(Parcel source, ClassLoader loader) { 26180 super(source, loader); 26181 mSavedData = source.readInt(); 26182 mStartActivityRequestWhoSaved = source.readString(); 26183 mIsAutofilled = source.readBoolean(); 26184 mAutofillViewId = source.readInt(); 26185 } 26186 26187 /** 26188 * Constructor called by derived classes when creating their SavedState objects 26189 * 26190 * @param superState The state of the superclass of this view 26191 */ 26192 public BaseSavedState(Parcelable superState) { 26193 super(superState); 26194 } 26195 26196 @Override 26197 public void writeToParcel(Parcel out, int flags) { 26198 super.writeToParcel(out, flags); 26199 26200 out.writeInt(mSavedData); 26201 out.writeString(mStartActivityRequestWhoSaved); 26202 out.writeBoolean(mIsAutofilled); 26203 out.writeInt(mAutofillViewId); 26204 } 26205 26206 public static final Parcelable.Creator<BaseSavedState> CREATOR 26207 = new Parcelable.ClassLoaderCreator<BaseSavedState>() { 26208 @Override 26209 public BaseSavedState createFromParcel(Parcel in) { 26210 return new BaseSavedState(in); 26211 } 26212 26213 @Override 26214 public BaseSavedState createFromParcel(Parcel in, ClassLoader loader) { 26215 return new BaseSavedState(in, loader); 26216 } 26217 26218 @Override 26219 public BaseSavedState[] newArray(int size) { 26220 return new BaseSavedState[size]; 26221 } 26222 }; 26223 } 26224 26225 /** 26226 * A set of information given to a view when it is attached to its parent 26227 * window. 26228 */ 26229 final static class AttachInfo { 26230 interface Callbacks { 26231 void playSoundEffect(int effectId); 26232 boolean performHapticFeedback(int effectId, boolean always); 26233 } 26234 26235 /** 26236 * InvalidateInfo is used to post invalidate(int, int, int, int) messages 26237 * to a Handler. This class contains the target (View) to invalidate and 26238 * the coordinates of the dirty rectangle. 26239 * 26240 * For performance purposes, this class also implements a pool of up to 26241 * POOL_LIMIT objects that get reused. This reduces memory allocations 26242 * whenever possible. 26243 */ 26244 static class InvalidateInfo { 26245 private static final int POOL_LIMIT = 10; 26246 26247 private static final SynchronizedPool<InvalidateInfo> sPool = 26248 new SynchronizedPool<InvalidateInfo>(POOL_LIMIT); 26249 26250 View target; 26251 26252 int left; 26253 int top; 26254 int right; 26255 int bottom; 26256 26257 public static InvalidateInfo obtain() { 26258 InvalidateInfo instance = sPool.acquire(); 26259 return (instance != null) ? instance : new InvalidateInfo(); 26260 } 26261 26262 public void recycle() { 26263 target = null; 26264 sPool.release(this); 26265 } 26266 } 26267 26268 final IWindowSession mSession; 26269 26270 final IWindow mWindow; 26271 26272 final IBinder mWindowToken; 26273 26274 Display mDisplay; 26275 26276 final Callbacks mRootCallbacks; 26277 26278 IWindowId mIWindowId; 26279 WindowId mWindowId; 26280 26281 /** 26282 * The top view of the hierarchy. 26283 */ 26284 View mRootView; 26285 26286 IBinder mPanelParentWindowToken; 26287 26288 boolean mHardwareAccelerated; 26289 boolean mHardwareAccelerationRequested; 26290 ThreadedRenderer mThreadedRenderer; 26291 List<RenderNode> mPendingAnimatingRenderNodes; 26292 26293 /** 26294 * The state of the display to which the window is attached, as reported 26295 * by {@link Display#getState()}. Note that the display state constants 26296 * declared by {@link Display} do not exactly line up with the screen state 26297 * constants declared by {@link View} (there are more display states than 26298 * screen states). 26299 */ 26300 int mDisplayState = Display.STATE_UNKNOWN; 26301 26302 /** 26303 * Scale factor used by the compatibility mode 26304 */ 26305 float mApplicationScale; 26306 26307 /** 26308 * Indicates whether the application is in compatibility mode 26309 */ 26310 boolean mScalingRequired; 26311 26312 /** 26313 * Left position of this view's window 26314 */ 26315 int mWindowLeft; 26316 26317 /** 26318 * Top position of this view's window 26319 */ 26320 int mWindowTop; 26321 26322 /** 26323 * Indicates whether views need to use 32-bit drawing caches 26324 */ 26325 boolean mUse32BitDrawingCache; 26326 26327 /** 26328 * For windows that are full-screen but using insets to layout inside 26329 * of the screen areas, these are the current insets to appear inside 26330 * the overscan area of the display. 26331 */ 26332 final Rect mOverscanInsets = new Rect(); 26333 26334 /** 26335 * For windows that are full-screen but using insets to layout inside 26336 * of the screen decorations, these are the current insets for the 26337 * content of the window. 26338 */ 26339 final Rect mContentInsets = new Rect(); 26340 26341 /** 26342 * For windows that are full-screen but using insets to layout inside 26343 * of the screen decorations, these are the current insets for the 26344 * actual visible parts of the window. 26345 */ 26346 final Rect mVisibleInsets = new Rect(); 26347 26348 /** 26349 * For windows that are full-screen but using insets to layout inside 26350 * of the screen decorations, these are the current insets for the 26351 * stable system windows. 26352 */ 26353 final Rect mStableInsets = new Rect(); 26354 26355 final DisplayCutout.ParcelableWrapper mDisplayCutout = 26356 new DisplayCutout.ParcelableWrapper(DisplayCutout.NO_CUTOUT); 26357 26358 /** 26359 * For windows that include areas that are not covered by real surface these are the outsets 26360 * for real surface. 26361 */ 26362 final Rect mOutsets = new Rect(); 26363 26364 /** 26365 * In multi-window we force show the navigation bar. Because we don't want that the surface 26366 * size changes in this mode, we instead have a flag whether the navigation bar size should 26367 * always be consumed, so the app is treated like there is no virtual navigation bar at all. 26368 */ 26369 boolean mAlwaysConsumeNavBar; 26370 26371 /** 26372 * The internal insets given by this window. This value is 26373 * supplied by the client (through 26374 * {@link ViewTreeObserver.OnComputeInternalInsetsListener}) and will 26375 * be given to the window manager when changed to be used in laying 26376 * out windows behind it. 26377 */ 26378 final ViewTreeObserver.InternalInsetsInfo mGivenInternalInsets 26379 = new ViewTreeObserver.InternalInsetsInfo(); 26380 26381 /** 26382 * Set to true when mGivenInternalInsets is non-empty. 26383 */ 26384 boolean mHasNonEmptyGivenInternalInsets; 26385 26386 /** 26387 * All views in the window's hierarchy that serve as scroll containers, 26388 * used to determine if the window can be resized or must be panned 26389 * to adjust for a soft input area. 26390 */ 26391 final ArrayList<View> mScrollContainers = new ArrayList<View>(); 26392 26393 final KeyEvent.DispatcherState mKeyDispatchState 26394 = new KeyEvent.DispatcherState(); 26395 26396 /** 26397 * Indicates whether the view's window currently has the focus. 26398 */ 26399 boolean mHasWindowFocus; 26400 26401 /** 26402 * The current visibility of the window. 26403 */ 26404 int mWindowVisibility; 26405 26406 /** 26407 * Indicates the time at which drawing started to occur. 26408 */ 26409 long mDrawingTime; 26410 26411 /** 26412 * Indicates whether or not ignoring the DIRTY_MASK flags. 26413 */ 26414 boolean mIgnoreDirtyState; 26415 26416 /** 26417 * This flag tracks when the mIgnoreDirtyState flag is set during draw(), 26418 * to avoid clearing that flag prematurely. 26419 */ 26420 boolean mSetIgnoreDirtyState = false; 26421 26422 /** 26423 * Indicates whether the view's window is currently in touch mode. 26424 */ 26425 boolean mInTouchMode; 26426 26427 /** 26428 * Indicates whether the view has requested unbuffered input dispatching for the current 26429 * event stream. 26430 */ 26431 boolean mUnbufferedDispatchRequested; 26432 26433 /** 26434 * Indicates that ViewAncestor should trigger a global layout change 26435 * the next time it performs a traversal 26436 */ 26437 boolean mRecomputeGlobalAttributes; 26438 26439 /** 26440 * Always report new attributes at next traversal. 26441 */ 26442 boolean mForceReportNewAttributes; 26443 26444 /** 26445 * Set during a traveral if any views want to keep the screen on. 26446 */ 26447 boolean mKeepScreenOn; 26448 26449 /** 26450 * Set during a traveral if the light center needs to be updated. 26451 */ 26452 boolean mNeedsUpdateLightCenter; 26453 26454 /** 26455 * Bitwise-or of all of the values that views have passed to setSystemUiVisibility(). 26456 */ 26457 int mSystemUiVisibility; 26458 26459 /** 26460 * Hack to force certain system UI visibility flags to be cleared. 26461 */ 26462 int mDisabledSystemUiVisibility; 26463 26464 /** 26465 * Last global system UI visibility reported by the window manager. 26466 */ 26467 int mGlobalSystemUiVisibility = -1; 26468 26469 /** 26470 * True if a view in this hierarchy has an OnSystemUiVisibilityChangeListener 26471 * attached. 26472 */ 26473 boolean mHasSystemUiListeners; 26474 26475 /** 26476 * Set if the window has requested to extend into the overscan region 26477 * via WindowManager.LayoutParams.FLAG_LAYOUT_IN_OVERSCAN. 26478 */ 26479 boolean mOverscanRequested; 26480 26481 /** 26482 * Set if the visibility of any views has changed. 26483 */ 26484 boolean mViewVisibilityChanged; 26485 26486 /** 26487 * Set to true if a view has been scrolled. 26488 */ 26489 boolean mViewScrollChanged; 26490 26491 /** 26492 * Set to true if a pointer event is currently being handled. 26493 */ 26494 boolean mHandlingPointerEvent; 26495 26496 /** 26497 * Global to the view hierarchy used as a temporary for dealing with 26498 * x/y points in the transparent region computations. 26499 */ 26500 final int[] mTransparentLocation = new int[2]; 26501 26502 /** 26503 * Global to the view hierarchy used as a temporary for dealing with 26504 * x/y points in the ViewGroup.invalidateChild implementation. 26505 */ 26506 final int[] mInvalidateChildLocation = new int[2]; 26507 26508 /** 26509 * Global to the view hierarchy used as a temporary for dealing with 26510 * computing absolute on-screen location. 26511 */ 26512 final int[] mTmpLocation = new int[2]; 26513 26514 /** 26515 * Global to the view hierarchy used as a temporary for dealing with 26516 * x/y location when view is transformed. 26517 */ 26518 final float[] mTmpTransformLocation = new float[2]; 26519 26520 /** 26521 * The view tree observer used to dispatch global events like 26522 * layout, pre-draw, touch mode change, etc. 26523 */ 26524 final ViewTreeObserver mTreeObserver; 26525 26526 /** 26527 * A Canvas used by the view hierarchy to perform bitmap caching. 26528 */ 26529 Canvas mCanvas; 26530 26531 /** 26532 * The view root impl. 26533 */ 26534 final ViewRootImpl mViewRootImpl; 26535 26536 /** 26537 * A Handler supplied by a view's {@link android.view.ViewRootImpl}. This 26538 * handler can be used to pump events in the UI events queue. 26539 */ 26540 final Handler mHandler; 26541 26542 /** 26543 * Temporary for use in computing invalidate rectangles while 26544 * calling up the hierarchy. 26545 */ 26546 final Rect mTmpInvalRect = new Rect(); 26547 26548 /** 26549 * Temporary for use in computing hit areas with transformed views 26550 */ 26551 final RectF mTmpTransformRect = new RectF(); 26552 26553 /** 26554 * Temporary for use in computing hit areas with transformed views 26555 */ 26556 final RectF mTmpTransformRect1 = new RectF(); 26557 26558 /** 26559 * Temporary list of rectanges. 26560 */ 26561 final List<RectF> mTmpRectList = new ArrayList<>(); 26562 26563 /** 26564 * Temporary for use in transforming invalidation rect 26565 */ 26566 final Matrix mTmpMatrix = new Matrix(); 26567 26568 /** 26569 * Temporary for use in transforming invalidation rect 26570 */ 26571 final Transformation mTmpTransformation = new Transformation(); 26572 26573 /** 26574 * Temporary for use in querying outlines from OutlineProviders 26575 */ 26576 final Outline mTmpOutline = new Outline(); 26577 26578 /** 26579 * Temporary list for use in collecting focusable descendents of a view. 26580 */ 26581 final ArrayList<View> mTempArrayList = new ArrayList<View>(24); 26582 26583 /** 26584 * The id of the window for accessibility purposes. 26585 */ 26586 int mAccessibilityWindowId = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID; 26587 26588 /** 26589 * Flags related to accessibility processing. 26590 * 26591 * @see AccessibilityNodeInfo#FLAG_INCLUDE_NOT_IMPORTANT_VIEWS 26592 * @see AccessibilityNodeInfo#FLAG_REPORT_VIEW_IDS 26593 */ 26594 int mAccessibilityFetchFlags; 26595 26596 /** 26597 * The drawable for highlighting accessibility focus. 26598 */ 26599 Drawable mAccessibilityFocusDrawable; 26600 26601 /** 26602 * The drawable for highlighting autofilled views. 26603 * 26604 * @see #isAutofilled() 26605 */ 26606 Drawable mAutofilledDrawable; 26607 26608 /** 26609 * Show where the margins, bounds and layout bounds are for each view. 26610 */ 26611 boolean mDebugLayout = SystemProperties.getBoolean(DEBUG_LAYOUT_PROPERTY, false); 26612 26613 /** 26614 * Point used to compute visible regions. 26615 */ 26616 final Point mPoint = new Point(); 26617 26618 /** 26619 * Used to track which View originated a requestLayout() call, used when 26620 * requestLayout() is called during layout. 26621 */ 26622 View mViewRequestingLayout; 26623 26624 /** 26625 * Used to track views that need (at least) a partial relayout at their current size 26626 * during the next traversal. 26627 */ 26628 List<View> mPartialLayoutViews = new ArrayList<>(); 26629 26630 /** 26631 * Swapped with mPartialLayoutViews during layout to avoid concurrent 26632 * modification. Lazily assigned during ViewRootImpl layout. 26633 */ 26634 List<View> mEmptyPartialLayoutViews; 26635 26636 /** 26637 * Used to track the identity of the current drag operation. 26638 */ 26639 IBinder mDragToken; 26640 26641 /** 26642 * The drag shadow surface for the current drag operation. 26643 */ 26644 public Surface mDragSurface; 26645 26646 26647 /** 26648 * The view that currently has a tooltip displayed. 26649 */ 26650 View mTooltipHost; 26651 26652 /** 26653 * Creates a new set of attachment information with the specified 26654 * events handler and thread. 26655 * 26656 * @param handler the events handler the view must use 26657 */ 26658 AttachInfo(IWindowSession session, IWindow window, Display display, 26659 ViewRootImpl viewRootImpl, Handler handler, Callbacks effectPlayer, 26660 Context context) { 26661 mSession = session; 26662 mWindow = window; 26663 mWindowToken = window.asBinder(); 26664 mDisplay = display; 26665 mViewRootImpl = viewRootImpl; 26666 mHandler = handler; 26667 mRootCallbacks = effectPlayer; 26668 mTreeObserver = new ViewTreeObserver(context); 26669 } 26670 } 26671 26672 /** 26673 * <p>ScrollabilityCache holds various fields used by a View when scrolling 26674 * is supported. This avoids keeping too many unused fields in most 26675 * instances of View.</p> 26676 */ 26677 private static class ScrollabilityCache implements Runnable { 26678 26679 /** 26680 * Scrollbars are not visible 26681 */ 26682 public static final int OFF = 0; 26683 26684 /** 26685 * Scrollbars are visible 26686 */ 26687 public static final int ON = 1; 26688 26689 /** 26690 * Scrollbars are fading away 26691 */ 26692 public static final int FADING = 2; 26693 26694 public boolean fadeScrollBars; 26695 26696 public int fadingEdgeLength; 26697 public int scrollBarDefaultDelayBeforeFade; 26698 public int scrollBarFadeDuration; 26699 26700 public int scrollBarSize; 26701 public int scrollBarMinTouchTarget; 26702 public ScrollBarDrawable scrollBar; 26703 public float[] interpolatorValues; 26704 public View host; 26705 26706 public final Paint paint; 26707 public final Matrix matrix; 26708 public Shader shader; 26709 26710 public final Interpolator scrollBarInterpolator = new Interpolator(1, 2); 26711 26712 private static final float[] OPAQUE = { 255 }; 26713 private static final float[] TRANSPARENT = { 0.0f }; 26714 26715 /** 26716 * When fading should start. This time moves into the future every time 26717 * a new scroll happens. Measured based on SystemClock.uptimeMillis() 26718 */ 26719 public long fadeStartTime; 26720 26721 26722 /** 26723 * The current state of the scrollbars: ON, OFF, or FADING 26724 */ 26725 public int state = OFF; 26726 26727 private int mLastColor; 26728 26729 public final Rect mScrollBarBounds = new Rect(); 26730 public final Rect mScrollBarTouchBounds = new Rect(); 26731 26732 public static final int NOT_DRAGGING = 0; 26733 public static final int DRAGGING_VERTICAL_SCROLL_BAR = 1; 26734 public static final int DRAGGING_HORIZONTAL_SCROLL_BAR = 2; 26735 public int mScrollBarDraggingState = NOT_DRAGGING; 26736 26737 public float mScrollBarDraggingPos = 0; 26738 26739 public ScrollabilityCache(ViewConfiguration configuration, View host) { 26740 fadingEdgeLength = configuration.getScaledFadingEdgeLength(); 26741 scrollBarSize = configuration.getScaledScrollBarSize(); 26742 scrollBarMinTouchTarget = configuration.getScaledMinScrollbarTouchTarget(); 26743 scrollBarDefaultDelayBeforeFade = ViewConfiguration.getScrollDefaultDelay(); 26744 scrollBarFadeDuration = ViewConfiguration.getScrollBarFadeDuration(); 26745 26746 paint = new Paint(); 26747 matrix = new Matrix(); 26748 // use use a height of 1, and then wack the matrix each time we 26749 // actually use it. 26750 shader = new LinearGradient(0, 0, 0, 1, 0xFF000000, 0, Shader.TileMode.CLAMP); 26751 paint.setShader(shader); 26752 paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); 26753 26754 this.host = host; 26755 } 26756 26757 public void setFadeColor(int color) { 26758 if (color != mLastColor) { 26759 mLastColor = color; 26760 26761 if (color != 0) { 26762 shader = new LinearGradient(0, 0, 0, 1, color | 0xFF000000, 26763 color & 0x00FFFFFF, Shader.TileMode.CLAMP); 26764 paint.setShader(shader); 26765 // Restore the default transfer mode (src_over) 26766 paint.setXfermode(null); 26767 } else { 26768 shader = new LinearGradient(0, 0, 0, 1, 0xFF000000, 0, Shader.TileMode.CLAMP); 26769 paint.setShader(shader); 26770 paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); 26771 } 26772 } 26773 } 26774 26775 public void run() { 26776 long now = AnimationUtils.currentAnimationTimeMillis(); 26777 if (now >= fadeStartTime) { 26778 26779 // the animation fades the scrollbars out by changing 26780 // the opacity (alpha) from fully opaque to fully 26781 // transparent 26782 int nextFrame = (int) now; 26783 int framesCount = 0; 26784 26785 Interpolator interpolator = scrollBarInterpolator; 26786 26787 // Start opaque 26788 interpolator.setKeyFrame(framesCount++, nextFrame, OPAQUE); 26789 26790 // End transparent 26791 nextFrame += scrollBarFadeDuration; 26792 interpolator.setKeyFrame(framesCount, nextFrame, TRANSPARENT); 26793 26794 state = FADING; 26795 26796 // Kick off the fade animation 26797 host.invalidate(true); 26798 } 26799 } 26800 } 26801 26802 /** 26803 * Resuable callback for sending 26804 * {@link AccessibilityEvent#TYPE_VIEW_SCROLLED} accessibility event. 26805 */ 26806 private class SendViewScrolledAccessibilityEvent implements Runnable { 26807 public volatile boolean mIsPending; 26808 public int mDeltaX; 26809 public int mDeltaY; 26810 26811 public void post(int dx, int dy) { 26812 mDeltaX += dx; 26813 mDeltaY += dy; 26814 if (!mIsPending) { 26815 mIsPending = true; 26816 postDelayed(this, ViewConfiguration.getSendRecurringAccessibilityEventsInterval()); 26817 } 26818 } 26819 26820 @Override 26821 public void run() { 26822 if (AccessibilityManager.getInstance(mContext).isEnabled()) { 26823 AccessibilityEvent event = AccessibilityEvent.obtain( 26824 AccessibilityEvent.TYPE_VIEW_SCROLLED); 26825 event.setScrollDeltaX(mDeltaX); 26826 event.setScrollDeltaY(mDeltaY); 26827 sendAccessibilityEventUnchecked(event); 26828 } 26829 reset(); 26830 } 26831 26832 private void reset() { 26833 mIsPending = false; 26834 mDeltaX = 0; 26835 mDeltaY = 0; 26836 } 26837 } 26838 26839 /** 26840 * Remove the pending callback for sending a 26841 * {@link AccessibilityEvent#TYPE_VIEW_SCROLLED} accessibility event. 26842 */ 26843 private void cancel(@Nullable SendViewScrolledAccessibilityEvent callback) { 26844 if (callback == null || !callback.mIsPending) return; 26845 removeCallbacks(callback); 26846 callback.reset(); 26847 } 26848 26849 /** 26850 * <p> 26851 * This class represents a delegate that can be registered in a {@link View} 26852 * to enhance accessibility support via composition rather via inheritance. 26853 * It is specifically targeted to widget developers that extend basic View 26854 * classes i.e. classes in package android.view, that would like their 26855 * applications to be backwards compatible. 26856 * </p> 26857 * <div class="special reference"> 26858 * <h3>Developer Guides</h3> 26859 * <p>For more information about making applications accessible, read the 26860 * <a href="{@docRoot}guide/topics/ui/accessibility/index.html">Accessibility</a> 26861 * developer guide.</p> 26862 * </div> 26863 * <p> 26864 * A scenario in which a developer would like to use an accessibility delegate 26865 * is overriding a method introduced in a later API version than the minimal API 26866 * version supported by the application. For example, the method 26867 * {@link View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} is not available 26868 * in API version 4 when the accessibility APIs were first introduced. If a 26869 * developer would like his application to run on API version 4 devices (assuming 26870 * all other APIs used by the application are version 4 or lower) and take advantage 26871 * of this method, instead of overriding the method which would break the application's 26872 * backwards compatibility, he can override the corresponding method in this 26873 * delegate and register the delegate in the target View if the API version of 26874 * the system is high enough, i.e. the API version is the same as or higher than the API 26875 * version that introduced 26876 * {@link View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)}. 26877 * </p> 26878 * <p> 26879 * Here is an example implementation: 26880 * </p> 26881 * <code><pre><p> 26882 * if (Build.VERSION.SDK_INT >= 14) { 26883 * // If the API version is equal of higher than the version in 26884 * // which onInitializeAccessibilityNodeInfo was introduced we 26885 * // register a delegate with a customized implementation. 26886 * View view = findViewById(R.id.view_id); 26887 * view.setAccessibilityDelegate(new AccessibilityDelegate() { 26888 * public void onInitializeAccessibilityNodeInfo(View host, 26889 * AccessibilityNodeInfo info) { 26890 * // Let the default implementation populate the info. 26891 * super.onInitializeAccessibilityNodeInfo(host, info); 26892 * // Set some other information. 26893 * info.setEnabled(host.isEnabled()); 26894 * } 26895 * }); 26896 * } 26897 * </code></pre></p> 26898 * <p> 26899 * This delegate contains methods that correspond to the accessibility methods 26900 * in View. If a delegate has been specified the implementation in View hands 26901 * off handling to the corresponding method in this delegate. The default 26902 * implementation the delegate methods behaves exactly as the corresponding 26903 * method in View for the case of no accessibility delegate been set. Hence, 26904 * to customize the behavior of a View method, clients can override only the 26905 * corresponding delegate method without altering the behavior of the rest 26906 * accessibility related methods of the host view. 26907 * </p> 26908 * <p> 26909 * <strong>Note:</strong> On platform versions prior to 26910 * {@link android.os.Build.VERSION_CODES#M API 23}, delegate methods on 26911 * views in the {@code android.widget.*} package are called <i>before</i> 26912 * host methods. This prevents certain properties such as class name from 26913 * being modified by overriding 26914 * {@link AccessibilityDelegate#onInitializeAccessibilityNodeInfo(View, AccessibilityNodeInfo)}, 26915 * as any changes will be overwritten by the host class. 26916 * <p> 26917 * Starting in {@link android.os.Build.VERSION_CODES#M API 23}, delegate 26918 * methods are called <i>after</i> host methods, which all properties to be 26919 * modified without being overwritten by the host class. 26920 */ 26921 public static class AccessibilityDelegate { 26922 26923 /** 26924 * Sends an accessibility event of the given type. If accessibility is not 26925 * enabled this method has no effect. 26926 * <p> 26927 * The default implementation behaves as {@link View#sendAccessibilityEvent(int) 26928 * View#sendAccessibilityEvent(int)} for the case of no accessibility delegate 26929 * been set. 26930 * </p> 26931 * 26932 * @param host The View hosting the delegate. 26933 * @param eventType The type of the event to send. 26934 * 26935 * @see View#sendAccessibilityEvent(int) View#sendAccessibilityEvent(int) 26936 */ 26937 public void sendAccessibilityEvent(View host, int eventType) { 26938 host.sendAccessibilityEventInternal(eventType); 26939 } 26940 26941 /** 26942 * Performs the specified accessibility action on the view. For 26943 * possible accessibility actions look at {@link AccessibilityNodeInfo}. 26944 * <p> 26945 * The default implementation behaves as 26946 * {@link View#performAccessibilityAction(int, Bundle) 26947 * View#performAccessibilityAction(int, Bundle)} for the case of 26948 * no accessibility delegate been set. 26949 * </p> 26950 * 26951 * @param action The action to perform. 26952 * @return Whether the action was performed. 26953 * 26954 * @see View#performAccessibilityAction(int, Bundle) 26955 * View#performAccessibilityAction(int, Bundle) 26956 */ 26957 public boolean performAccessibilityAction(View host, int action, Bundle args) { 26958 return host.performAccessibilityActionInternal(action, args); 26959 } 26960 26961 /** 26962 * Sends an accessibility event. This method behaves exactly as 26963 * {@link #sendAccessibilityEvent(View, int)} but takes as an argument an 26964 * empty {@link AccessibilityEvent} and does not perform a check whether 26965 * accessibility is enabled. 26966 * <p> 26967 * The default implementation behaves as 26968 * {@link View#sendAccessibilityEventUnchecked(AccessibilityEvent) 26969 * View#sendAccessibilityEventUnchecked(AccessibilityEvent)} for 26970 * the case of no accessibility delegate been set. 26971 * </p> 26972 * 26973 * @param host The View hosting the delegate. 26974 * @param event The event to send. 26975 * 26976 * @see View#sendAccessibilityEventUnchecked(AccessibilityEvent) 26977 * View#sendAccessibilityEventUnchecked(AccessibilityEvent) 26978 */ 26979 public void sendAccessibilityEventUnchecked(View host, AccessibilityEvent event) { 26980 host.sendAccessibilityEventUncheckedInternal(event); 26981 } 26982 26983 /** 26984 * Dispatches an {@link AccessibilityEvent} to the host {@link View} first and then 26985 * to its children for adding their text content to the event. 26986 * <p> 26987 * The default implementation behaves as 26988 * {@link View#dispatchPopulateAccessibilityEvent(AccessibilityEvent) 26989 * View#dispatchPopulateAccessibilityEvent(AccessibilityEvent)} for 26990 * the case of no accessibility delegate been set. 26991 * </p> 26992 * 26993 * @param host The View hosting the delegate. 26994 * @param event The event. 26995 * @return True if the event population was completed. 26996 * 26997 * @see View#dispatchPopulateAccessibilityEvent(AccessibilityEvent) 26998 * View#dispatchPopulateAccessibilityEvent(AccessibilityEvent) 26999 */ 27000 public boolean dispatchPopulateAccessibilityEvent(View host, AccessibilityEvent event) { 27001 return host.dispatchPopulateAccessibilityEventInternal(event); 27002 } 27003 27004 /** 27005 * Gives a chance to the host View to populate the accessibility event with its 27006 * text content. 27007 * <p> 27008 * The default implementation behaves as 27009 * {@link View#onPopulateAccessibilityEvent(AccessibilityEvent) 27010 * View#onPopulateAccessibilityEvent(AccessibilityEvent)} for 27011 * the case of no accessibility delegate been set. 27012 * </p> 27013 * 27014 * @param host The View hosting the delegate. 27015 * @param event The accessibility event which to populate. 27016 * 27017 * @see View#onPopulateAccessibilityEvent(AccessibilityEvent) 27018 * View#onPopulateAccessibilityEvent(AccessibilityEvent) 27019 */ 27020 public void onPopulateAccessibilityEvent(View host, AccessibilityEvent event) { 27021 host.onPopulateAccessibilityEventInternal(event); 27022 } 27023 27024 /** 27025 * Initializes an {@link AccessibilityEvent} with information about the 27026 * the host View which is the event source. 27027 * <p> 27028 * The default implementation behaves as 27029 * {@link View#onInitializeAccessibilityEvent(AccessibilityEvent) 27030 * View#onInitializeAccessibilityEvent(AccessibilityEvent)} for 27031 * the case of no accessibility delegate been set. 27032 * </p> 27033 * 27034 * @param host The View hosting the delegate. 27035 * @param event The event to initialize. 27036 * 27037 * @see View#onInitializeAccessibilityEvent(AccessibilityEvent) 27038 * View#onInitializeAccessibilityEvent(AccessibilityEvent) 27039 */ 27040 public void onInitializeAccessibilityEvent(View host, AccessibilityEvent event) { 27041 host.onInitializeAccessibilityEventInternal(event); 27042 } 27043 27044 /** 27045 * Initializes an {@link AccessibilityNodeInfo} with information about the host view. 27046 * <p> 27047 * The default implementation behaves as 27048 * {@link View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo) 27049 * View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} for 27050 * the case of no accessibility delegate been set. 27051 * </p> 27052 * 27053 * @param host The View hosting the delegate. 27054 * @param info The instance to initialize. 27055 * 27056 * @see View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo) 27057 * View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo) 27058 */ 27059 public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) { 27060 host.onInitializeAccessibilityNodeInfoInternal(info); 27061 } 27062 27063 /** 27064 * Adds extra data to an {@link AccessibilityNodeInfo} based on an explicit request for the 27065 * additional data. 27066 * <p> 27067 * This method only needs to be implemented if the View offers to provide additional data. 27068 * </p> 27069 * <p> 27070 * The default implementation behaves as 27071 * {@link View#addExtraDataToAccessibilityNodeInfo(AccessibilityNodeInfo, String, Bundle) 27072 * for the case where no accessibility delegate is set. 27073 * </p> 27074 * 27075 * @param host The View hosting the delegate. Never {@code null}. 27076 * @param info The info to which to add the extra data. Never {@code null}. 27077 * @param extraDataKey A key specifying the type of extra data to add to the info. The 27078 * extra data should be added to the {@link Bundle} returned by 27079 * the info's {@link AccessibilityNodeInfo#getExtras} method. Never 27080 * {@code null}. 27081 * @param arguments A {@link Bundle} holding any arguments relevant for this request. 27082 * May be {@code null} if the if the service provided no arguments. 27083 * 27084 * @see AccessibilityNodeInfo#setExtraAvailableData 27085 */ 27086 public void addExtraDataToAccessibilityNodeInfo(@NonNull View host, 27087 @NonNull AccessibilityNodeInfo info, @NonNull String extraDataKey, 27088 @Nullable Bundle arguments) { 27089 host.addExtraDataToAccessibilityNodeInfo(info, extraDataKey, arguments); 27090 } 27091 27092 /** 27093 * Called when a child of the host View has requested sending an 27094 * {@link AccessibilityEvent} and gives an opportunity to the parent (the host) 27095 * to augment the event. 27096 * <p> 27097 * The default implementation behaves as 27098 * {@link ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent) 27099 * ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent)} for 27100 * the case of no accessibility delegate been set. 27101 * </p> 27102 * 27103 * @param host The View hosting the delegate. 27104 * @param child The child which requests sending the event. 27105 * @param event The event to be sent. 27106 * @return True if the event should be sent 27107 * 27108 * @see ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent) 27109 * ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent) 27110 */ 27111 public boolean onRequestSendAccessibilityEvent(ViewGroup host, View child, 27112 AccessibilityEvent event) { 27113 return host.onRequestSendAccessibilityEventInternal(child, event); 27114 } 27115 27116 /** 27117 * Gets the provider for managing a virtual view hierarchy rooted at this View 27118 * and reported to {@link android.accessibilityservice.AccessibilityService}s 27119 * that explore the window content. 27120 * <p> 27121 * The default implementation behaves as 27122 * {@link View#getAccessibilityNodeProvider() View#getAccessibilityNodeProvider()} for 27123 * the case of no accessibility delegate been set. 27124 * </p> 27125 * 27126 * @return The provider. 27127 * 27128 * @see AccessibilityNodeProvider 27129 */ 27130 public AccessibilityNodeProvider getAccessibilityNodeProvider(View host) { 27131 return null; 27132 } 27133 27134 /** 27135 * Returns an {@link AccessibilityNodeInfo} representing the host view from the 27136 * point of view of an {@link android.accessibilityservice.AccessibilityService}. 27137 * This method is responsible for obtaining an accessibility node info from a 27138 * pool of reusable instances and calling 27139 * {@link #onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} on the host 27140 * view to initialize the former. 27141 * <p> 27142 * <strong>Note:</strong> The client is responsible for recycling the obtained 27143 * instance by calling {@link AccessibilityNodeInfo#recycle()} to minimize object 27144 * creation. 27145 * </p> 27146 * <p> 27147 * The default implementation behaves as 27148 * {@link View#createAccessibilityNodeInfo() View#createAccessibilityNodeInfo()} for 27149 * the case of no accessibility delegate been set. 27150 * </p> 27151 * @return A populated {@link AccessibilityNodeInfo}. 27152 * 27153 * @see AccessibilityNodeInfo 27154 * 27155 * @hide 27156 */ 27157 public AccessibilityNodeInfo createAccessibilityNodeInfo(View host) { 27158 return host.createAccessibilityNodeInfoInternal(); 27159 } 27160 } 27161 27162 private static class MatchIdPredicate implements Predicate<View> { 27163 public int mId; 27164 27165 @Override 27166 public boolean test(View view) { 27167 return (view.mID == mId); 27168 } 27169 } 27170 27171 private static class MatchLabelForPredicate implements Predicate<View> { 27172 private int mLabeledId; 27173 27174 @Override 27175 public boolean test(View view) { 27176 return (view.mLabelForId == mLabeledId); 27177 } 27178 } 27179 27180 /** 27181 * Dump all private flags in readable format, useful for documentation and 27182 * sanity checking. 27183 */ 27184 private static void dumpFlags() { 27185 final HashMap<String, String> found = Maps.newHashMap(); 27186 try { 27187 for (Field field : View.class.getDeclaredFields()) { 27188 final int modifiers = field.getModifiers(); 27189 if (Modifier.isStatic(modifiers) && Modifier.isFinal(modifiers)) { 27190 if (field.getType().equals(int.class)) { 27191 final int value = field.getInt(null); 27192 dumpFlag(found, field.getName(), value); 27193 } else if (field.getType().equals(int[].class)) { 27194 final int[] values = (int[]) field.get(null); 27195 for (int i = 0; i < values.length; i++) { 27196 dumpFlag(found, field.getName() + "[" + i + "]", values[i]); 27197 } 27198 } 27199 } 27200 } 27201 } catch (IllegalAccessException e) { 27202 throw new RuntimeException(e); 27203 } 27204 27205 final ArrayList<String> keys = Lists.newArrayList(); 27206 keys.addAll(found.keySet()); 27207 Collections.sort(keys); 27208 for (String key : keys) { 27209 Log.d(VIEW_LOG_TAG, found.get(key)); 27210 } 27211 } 27212 27213 private static void dumpFlag(HashMap<String, String> found, String name, int value) { 27214 // Sort flags by prefix, then by bits, always keeping unique keys 27215 final String bits = String.format("%32s", Integer.toBinaryString(value)).replace('0', ' '); 27216 final int prefix = name.indexOf('_'); 27217 final String key = (prefix > 0 ? name.substring(0, prefix) : name) + bits + name; 27218 final String output = bits + " " + name; 27219 found.put(key, output); 27220 } 27221 27222 /** {@hide} */ 27223 public void encode(@NonNull ViewHierarchyEncoder stream) { 27224 stream.beginObject(this); 27225 encodeProperties(stream); 27226 stream.endObject(); 27227 } 27228 27229 /** {@hide} */ 27230 @CallSuper 27231 protected void encodeProperties(@NonNull ViewHierarchyEncoder stream) { 27232 Object resolveId = ViewDebug.resolveId(getContext(), mID); 27233 if (resolveId instanceof String) { 27234 stream.addProperty("id", (String) resolveId); 27235 } else { 27236 stream.addProperty("id", mID); 27237 } 27238 27239 stream.addProperty("misc:transformation.alpha", 27240 mTransformationInfo != null ? mTransformationInfo.mAlpha : 0); 27241 stream.addProperty("misc:transitionName", getTransitionName()); 27242 27243 // layout 27244 stream.addProperty("layout:left", mLeft); 27245 stream.addProperty("layout:right", mRight); 27246 stream.addProperty("layout:top", mTop); 27247 stream.addProperty("layout:bottom", mBottom); 27248 stream.addProperty("layout:width", getWidth()); 27249 stream.addProperty("layout:height", getHeight()); 27250 stream.addProperty("layout:layoutDirection", getLayoutDirection()); 27251 stream.addProperty("layout:layoutRtl", isLayoutRtl()); 27252 stream.addProperty("layout:hasTransientState", hasTransientState()); 27253 stream.addProperty("layout:baseline", getBaseline()); 27254 27255 // layout params 27256 ViewGroup.LayoutParams layoutParams = getLayoutParams(); 27257 if (layoutParams != null) { 27258 stream.addPropertyKey("layoutParams"); 27259 layoutParams.encode(stream); 27260 } 27261 27262 // scrolling 27263 stream.addProperty("scrolling:scrollX", mScrollX); 27264 stream.addProperty("scrolling:scrollY", mScrollY); 27265 27266 // padding 27267 stream.addProperty("padding:paddingLeft", mPaddingLeft); 27268 stream.addProperty("padding:paddingRight", mPaddingRight); 27269 stream.addProperty("padding:paddingTop", mPaddingTop); 27270 stream.addProperty("padding:paddingBottom", mPaddingBottom); 27271 stream.addProperty("padding:userPaddingRight", mUserPaddingRight); 27272 stream.addProperty("padding:userPaddingLeft", mUserPaddingLeft); 27273 stream.addProperty("padding:userPaddingBottom", mUserPaddingBottom); 27274 stream.addProperty("padding:userPaddingStart", mUserPaddingStart); 27275 stream.addProperty("padding:userPaddingEnd", mUserPaddingEnd); 27276 27277 // measurement 27278 stream.addProperty("measurement:minHeight", mMinHeight); 27279 stream.addProperty("measurement:minWidth", mMinWidth); 27280 stream.addProperty("measurement:measuredWidth", mMeasuredWidth); 27281 stream.addProperty("measurement:measuredHeight", mMeasuredHeight); 27282 27283 // drawing 27284 stream.addProperty("drawing:elevation", getElevation()); 27285 stream.addProperty("drawing:translationX", getTranslationX()); 27286 stream.addProperty("drawing:translationY", getTranslationY()); 27287 stream.addProperty("drawing:translationZ", getTranslationZ()); 27288 stream.addProperty("drawing:rotation", getRotation()); 27289 stream.addProperty("drawing:rotationX", getRotationX()); 27290 stream.addProperty("drawing:rotationY", getRotationY()); 27291 stream.addProperty("drawing:scaleX", getScaleX()); 27292 stream.addProperty("drawing:scaleY", getScaleY()); 27293 stream.addProperty("drawing:pivotX", getPivotX()); 27294 stream.addProperty("drawing:pivotY", getPivotY()); 27295 stream.addProperty("drawing:clipBounds", 27296 mClipBounds == null ? null : mClipBounds.toString()); 27297 stream.addProperty("drawing:opaque", isOpaque()); 27298 stream.addProperty("drawing:alpha", getAlpha()); 27299 stream.addProperty("drawing:transitionAlpha", getTransitionAlpha()); 27300 stream.addProperty("drawing:shadow", hasShadow()); 27301 stream.addProperty("drawing:solidColor", getSolidColor()); 27302 stream.addProperty("drawing:layerType", mLayerType); 27303 stream.addProperty("drawing:willNotDraw", willNotDraw()); 27304 stream.addProperty("drawing:hardwareAccelerated", isHardwareAccelerated()); 27305 stream.addProperty("drawing:willNotCacheDrawing", willNotCacheDrawing()); 27306 stream.addProperty("drawing:drawingCacheEnabled", isDrawingCacheEnabled()); 27307 stream.addProperty("drawing:overlappingRendering", hasOverlappingRendering()); 27308 stream.addProperty("drawing:outlineAmbientShadowColor", getOutlineAmbientShadowColor()); 27309 stream.addProperty("drawing:outlineSpotShadowColor", getOutlineSpotShadowColor()); 27310 27311 // focus 27312 stream.addProperty("focus:hasFocus", hasFocus()); 27313 stream.addProperty("focus:isFocused", isFocused()); 27314 stream.addProperty("focus:focusable", getFocusable()); 27315 stream.addProperty("focus:isFocusable", isFocusable()); 27316 stream.addProperty("focus:isFocusableInTouchMode", isFocusableInTouchMode()); 27317 27318 stream.addProperty("misc:clickable", isClickable()); 27319 stream.addProperty("misc:pressed", isPressed()); 27320 stream.addProperty("misc:selected", isSelected()); 27321 stream.addProperty("misc:touchMode", isInTouchMode()); 27322 stream.addProperty("misc:hovered", isHovered()); 27323 stream.addProperty("misc:activated", isActivated()); 27324 27325 stream.addProperty("misc:visibility", getVisibility()); 27326 stream.addProperty("misc:fitsSystemWindows", getFitsSystemWindows()); 27327 stream.addProperty("misc:filterTouchesWhenObscured", getFilterTouchesWhenObscured()); 27328 27329 stream.addProperty("misc:enabled", isEnabled()); 27330 stream.addProperty("misc:soundEffectsEnabled", isSoundEffectsEnabled()); 27331 stream.addProperty("misc:hapticFeedbackEnabled", isHapticFeedbackEnabled()); 27332 27333 // theme attributes 27334 Resources.Theme theme = getContext().getTheme(); 27335 if (theme != null) { 27336 stream.addPropertyKey("theme"); 27337 theme.encode(stream); 27338 } 27339 27340 // view attribute information 27341 int n = mAttributes != null ? mAttributes.length : 0; 27342 stream.addProperty("meta:__attrCount__", n/2); 27343 for (int i = 0; i < n; i += 2) { 27344 stream.addProperty("meta:__attr__" + mAttributes[i], mAttributes[i+1]); 27345 } 27346 27347 stream.addProperty("misc:scrollBarStyle", getScrollBarStyle()); 27348 27349 // text 27350 stream.addProperty("text:textDirection", getTextDirection()); 27351 stream.addProperty("text:textAlignment", getTextAlignment()); 27352 27353 // accessibility 27354 CharSequence contentDescription = getContentDescription(); 27355 stream.addProperty("accessibility:contentDescription", 27356 contentDescription == null ? "" : contentDescription.toString()); 27357 stream.addProperty("accessibility:labelFor", getLabelFor()); 27358 stream.addProperty("accessibility:importantForAccessibility", getImportantForAccessibility()); 27359 } 27360 27361 /** 27362 * Determine if this view is rendered on a round wearable device and is the main view 27363 * on the screen. 27364 */ 27365 boolean shouldDrawRoundScrollbar() { 27366 if (!mResources.getConfiguration().isScreenRound() || mAttachInfo == null) { 27367 return false; 27368 } 27369 27370 final View rootView = getRootView(); 27371 final WindowInsets insets = getRootWindowInsets(); 27372 27373 int height = getHeight(); 27374 int width = getWidth(); 27375 int displayHeight = rootView.getHeight(); 27376 int displayWidth = rootView.getWidth(); 27377 27378 if (height != displayHeight || width != displayWidth) { 27379 return false; 27380 } 27381 27382 getLocationInWindow(mAttachInfo.mTmpLocation); 27383 return mAttachInfo.mTmpLocation[0] == insets.getStableInsetLeft() 27384 && mAttachInfo.mTmpLocation[1] == insets.getStableInsetTop(); 27385 } 27386 27387 /** 27388 * Sets the tooltip text which will be displayed in a small popup next to the view. 27389 * <p> 27390 * The tooltip will be displayed: 27391 * <ul> 27392 * <li>On long click, unless it is handled otherwise (by OnLongClickListener or a context 27393 * menu). </li> 27394 * <li>On hover, after a brief delay since the pointer has stopped moving </li> 27395 * </ul> 27396 * <p> 27397 * <strong>Note:</strong> Do not override this method, as it will have no 27398 * effect on the text displayed in the tooltip. 27399 * 27400 * @param tooltipText the tooltip text, or null if no tooltip is required 27401 * @see #getTooltipText() 27402 * @attr ref android.R.styleable#View_tooltipText 27403 */ 27404 public void setTooltipText(@Nullable CharSequence tooltipText) { 27405 if (TextUtils.isEmpty(tooltipText)) { 27406 setFlags(0, TOOLTIP); 27407 hideTooltip(); 27408 mTooltipInfo = null; 27409 } else { 27410 setFlags(TOOLTIP, TOOLTIP); 27411 if (mTooltipInfo == null) { 27412 mTooltipInfo = new TooltipInfo(); 27413 mTooltipInfo.mShowTooltipRunnable = this::showHoverTooltip; 27414 mTooltipInfo.mHideTooltipRunnable = this::hideTooltip; 27415 mTooltipInfo.mHoverSlop = ViewConfiguration.get(mContext).getScaledHoverSlop(); 27416 mTooltipInfo.clearAnchorPos(); 27417 } 27418 mTooltipInfo.mTooltipText = tooltipText; 27419 } 27420 } 27421 27422 /** 27423 * @hide Binary compatibility stub. To be removed when we finalize O APIs. 27424 */ 27425 public void setTooltip(@Nullable CharSequence tooltipText) { 27426 setTooltipText(tooltipText); 27427 } 27428 27429 /** 27430 * Returns the view's tooltip text. 27431 * 27432 * <strong>Note:</strong> Do not override this method, as it will have no 27433 * effect on the text displayed in the tooltip. You must call 27434 * {@link #setTooltipText(CharSequence)} to modify the tooltip text. 27435 * 27436 * @return the tooltip text 27437 * @see #setTooltipText(CharSequence) 27438 * @attr ref android.R.styleable#View_tooltipText 27439 */ 27440 @Nullable 27441 public CharSequence getTooltipText() { 27442 return mTooltipInfo != null ? mTooltipInfo.mTooltipText : null; 27443 } 27444 27445 /** 27446 * @hide Binary compatibility stub. To be removed when we finalize O APIs. 27447 */ 27448 @Nullable 27449 public CharSequence getTooltip() { 27450 return getTooltipText(); 27451 } 27452 27453 private boolean showTooltip(int x, int y, boolean fromLongClick) { 27454 if (mAttachInfo == null || mTooltipInfo == null) { 27455 return false; 27456 } 27457 if (fromLongClick && (mViewFlags & ENABLED_MASK) != ENABLED) { 27458 return false; 27459 } 27460 if (TextUtils.isEmpty(mTooltipInfo.mTooltipText)) { 27461 return false; 27462 } 27463 hideTooltip(); 27464 mTooltipInfo.mTooltipFromLongClick = fromLongClick; 27465 mTooltipInfo.mTooltipPopup = new TooltipPopup(getContext()); 27466 final boolean fromTouch = (mPrivateFlags3 & PFLAG3_FINGER_DOWN) == PFLAG3_FINGER_DOWN; 27467 mTooltipInfo.mTooltipPopup.show(this, x, y, fromTouch, mTooltipInfo.mTooltipText); 27468 mAttachInfo.mTooltipHost = this; 27469 // The available accessibility actions have changed 27470 notifyViewAccessibilityStateChangedIfNeeded(CONTENT_CHANGE_TYPE_UNDEFINED); 27471 return true; 27472 } 27473 27474 void hideTooltip() { 27475 if (mTooltipInfo == null) { 27476 return; 27477 } 27478 removeCallbacks(mTooltipInfo.mShowTooltipRunnable); 27479 if (mTooltipInfo.mTooltipPopup == null) { 27480 return; 27481 } 27482 mTooltipInfo.mTooltipPopup.hide(); 27483 mTooltipInfo.mTooltipPopup = null; 27484 mTooltipInfo.mTooltipFromLongClick = false; 27485 mTooltipInfo.clearAnchorPos(); 27486 if (mAttachInfo != null) { 27487 mAttachInfo.mTooltipHost = null; 27488 } 27489 // The available accessibility actions have changed 27490 notifyViewAccessibilityStateChangedIfNeeded(CONTENT_CHANGE_TYPE_UNDEFINED); 27491 } 27492 27493 private boolean showLongClickTooltip(int x, int y) { 27494 removeCallbacks(mTooltipInfo.mShowTooltipRunnable); 27495 removeCallbacks(mTooltipInfo.mHideTooltipRunnable); 27496 return showTooltip(x, y, true); 27497 } 27498 27499 private boolean showHoverTooltip() { 27500 return showTooltip(mTooltipInfo.mAnchorX, mTooltipInfo.mAnchorY, false); 27501 } 27502 27503 boolean dispatchTooltipHoverEvent(MotionEvent event) { 27504 if (mTooltipInfo == null) { 27505 return false; 27506 } 27507 switch(event.getAction()) { 27508 case MotionEvent.ACTION_HOVER_MOVE: 27509 if ((mViewFlags & TOOLTIP) != TOOLTIP) { 27510 break; 27511 } 27512 if (!mTooltipInfo.mTooltipFromLongClick && mTooltipInfo.updateAnchorPos(event)) { 27513 if (mTooltipInfo.mTooltipPopup == null) { 27514 // Schedule showing the tooltip after a timeout. 27515 removeCallbacks(mTooltipInfo.mShowTooltipRunnable); 27516 postDelayed(mTooltipInfo.mShowTooltipRunnable, 27517 ViewConfiguration.getHoverTooltipShowTimeout()); 27518 } 27519 27520 // Hide hover-triggered tooltip after a period of inactivity. 27521 // Match the timeout used by NativeInputManager to hide the mouse pointer 27522 // (depends on SYSTEM_UI_FLAG_LOW_PROFILE being set). 27523 final int timeout; 27524 if ((getWindowSystemUiVisibility() & SYSTEM_UI_FLAG_LOW_PROFILE) 27525 == SYSTEM_UI_FLAG_LOW_PROFILE) { 27526 timeout = ViewConfiguration.getHoverTooltipHideShortTimeout(); 27527 } else { 27528 timeout = ViewConfiguration.getHoverTooltipHideTimeout(); 27529 } 27530 removeCallbacks(mTooltipInfo.mHideTooltipRunnable); 27531 postDelayed(mTooltipInfo.mHideTooltipRunnable, timeout); 27532 } 27533 return true; 27534 27535 case MotionEvent.ACTION_HOVER_EXIT: 27536 mTooltipInfo.clearAnchorPos(); 27537 if (!mTooltipInfo.mTooltipFromLongClick) { 27538 hideTooltip(); 27539 } 27540 break; 27541 } 27542 return false; 27543 } 27544 27545 void handleTooltipKey(KeyEvent event) { 27546 switch (event.getAction()) { 27547 case KeyEvent.ACTION_DOWN: 27548 if (event.getRepeatCount() == 0) { 27549 hideTooltip(); 27550 } 27551 break; 27552 27553 case KeyEvent.ACTION_UP: 27554 handleTooltipUp(); 27555 break; 27556 } 27557 } 27558 27559 private void handleTooltipUp() { 27560 if (mTooltipInfo == null || mTooltipInfo.mTooltipPopup == null) { 27561 return; 27562 } 27563 removeCallbacks(mTooltipInfo.mHideTooltipRunnable); 27564 postDelayed(mTooltipInfo.mHideTooltipRunnable, 27565 ViewConfiguration.getLongPressTooltipHideTimeout()); 27566 } 27567 27568 private int getFocusableAttribute(TypedArray attributes) { 27569 TypedValue val = new TypedValue(); 27570 if (attributes.getValue(com.android.internal.R.styleable.View_focusable, val)) { 27571 if (val.type == TypedValue.TYPE_INT_BOOLEAN) { 27572 return (val.data == 0 ? NOT_FOCUSABLE : FOCUSABLE); 27573 } else { 27574 return val.data; 27575 } 27576 } else { 27577 return FOCUSABLE_AUTO; 27578 } 27579 } 27580 27581 /** 27582 * @return The content view of the tooltip popup currently being shown, or null if the tooltip 27583 * is not showing. 27584 * @hide 27585 */ 27586 @TestApi 27587 public View getTooltipView() { 27588 if (mTooltipInfo == null || mTooltipInfo.mTooltipPopup == null) { 27589 return null; 27590 } 27591 return mTooltipInfo.mTooltipPopup.getContentView(); 27592 } 27593 27594 /** 27595 * Allows this view to handle {@link KeyEvent}s which weren't handled by normal dispatch. This 27596 * occurs after the normal view hierarchy dispatch, but before the window callback. By default, 27597 * this will dispatch into all the listeners registered via 27598 * {@link #addKeyFallbackListener(OnKeyFallbackListener)} in last-in-first-out order (most 27599 * recently added will receive events first). 27600 * 27601 * @param event A not-previously-handled event. 27602 * @return {@code true} if the event was handled, {@code false} otherwise. 27603 * @see #addKeyFallbackListener 27604 */ 27605 public boolean onKeyFallback(@NonNull KeyEvent event) { 27606 if (mListenerInfo != null && mListenerInfo.mKeyFallbackListeners != null) { 27607 for (int i = mListenerInfo.mKeyFallbackListeners.size() - 1; i >= 0; --i) { 27608 if (mListenerInfo.mKeyFallbackListeners.get(i).onKeyFallback(this, event)) { 27609 return true; 27610 } 27611 } 27612 } 27613 return false; 27614 } 27615 27616 /** 27617 * Adds a listener which will receive unhandled {@link KeyEvent}s. 27618 * @param listener the receiver of fallback {@link KeyEvent}s. 27619 * @see #onKeyFallback(KeyEvent) 27620 */ 27621 public void addKeyFallbackListener(OnKeyFallbackListener listener) { 27622 ArrayList<OnKeyFallbackListener> fallbacks = getListenerInfo().mKeyFallbackListeners; 27623 if (fallbacks == null) { 27624 fallbacks = new ArrayList<>(); 27625 getListenerInfo().mKeyFallbackListeners = fallbacks; 27626 } 27627 fallbacks.add(listener); 27628 } 27629 27630 /** 27631 * Removes a listener which will receive unhandled {@link KeyEvent}s. 27632 * @param listener the receiver of fallback {@link KeyEvent}s. 27633 * @see #onKeyFallback(KeyEvent) 27634 */ 27635 public void removeKeyFallbackListener(OnKeyFallbackListener listener) { 27636 if (mListenerInfo != null) { 27637 if (mListenerInfo.mKeyFallbackListeners != null) { 27638 mListenerInfo.mKeyFallbackListeners.remove(listener); 27639 if (mListenerInfo.mKeyFallbackListeners.isEmpty()) { 27640 mListenerInfo.mKeyFallbackListeners = null; 27641 } 27642 } 27643 } 27644 } 27645} 27646