View.java revision 99b254be5cc8ac800206480113dc09e4e19b6eb1
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 java.lang.Math.max; 20 21import android.animation.AnimatorInflater; 22import android.animation.StateListAnimator; 23import android.annotation.CallSuper; 24import android.annotation.ColorInt; 25import android.annotation.DrawableRes; 26import android.annotation.FloatRange; 27import android.annotation.IdRes; 28import android.annotation.IntDef; 29import android.annotation.IntRange; 30import android.annotation.LayoutRes; 31import android.annotation.NonNull; 32import android.annotation.Nullable; 33import android.annotation.Size; 34import android.annotation.TestApi; 35import android.annotation.UiThread; 36import android.content.ClipData; 37import android.content.Context; 38import android.content.ContextWrapper; 39import android.content.Intent; 40import android.content.res.ColorStateList; 41import android.content.res.Configuration; 42import android.content.res.Resources; 43import android.content.res.TypedArray; 44import android.graphics.Bitmap; 45import android.graphics.Canvas; 46import android.graphics.Color; 47import android.graphics.Insets; 48import android.graphics.Interpolator; 49import android.graphics.LinearGradient; 50import android.graphics.Matrix; 51import android.graphics.Outline; 52import android.graphics.Paint; 53import android.graphics.PixelFormat; 54import android.graphics.Point; 55import android.graphics.PorterDuff; 56import android.graphics.PorterDuffXfermode; 57import android.graphics.Rect; 58import android.graphics.RectF; 59import android.graphics.Region; 60import android.graphics.Shader; 61import android.graphics.drawable.ColorDrawable; 62import android.graphics.drawable.Drawable; 63import android.hardware.display.DisplayManagerGlobal; 64import android.net.Uri; 65import android.os.Build; 66import android.os.Bundle; 67import android.os.Handler; 68import android.os.IBinder; 69import android.os.Message; 70import android.os.Parcel; 71import android.os.Parcelable; 72import android.os.RemoteException; 73import android.os.SystemClock; 74import android.os.SystemProperties; 75import android.os.Trace; 76import android.text.TextUtils; 77import android.util.AttributeSet; 78import android.util.FloatProperty; 79import android.util.LayoutDirection; 80import android.util.Log; 81import android.util.LongSparseLongArray; 82import android.util.Pools.SynchronizedPool; 83import android.util.Property; 84import android.util.SparseArray; 85import android.util.StateSet; 86import android.util.SuperNotCalledException; 87import android.util.TypedValue; 88import android.view.AccessibilityIterators.CharacterTextSegmentIterator; 89import android.view.AccessibilityIterators.ParagraphTextSegmentIterator; 90import android.view.AccessibilityIterators.TextSegmentIterator; 91import android.view.AccessibilityIterators.WordTextSegmentIterator; 92import android.view.ContextMenu.ContextMenuInfo; 93import android.view.accessibility.AccessibilityEvent; 94import android.view.accessibility.AccessibilityEventSource; 95import android.view.accessibility.AccessibilityManager; 96import android.view.accessibility.AccessibilityNodeInfo; 97import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction; 98import android.view.accessibility.AccessibilityNodeProvider; 99import android.view.accessibility.AccessibilityWindowInfo; 100import android.view.animation.Animation; 101import android.view.animation.AnimationUtils; 102import android.view.animation.Transformation; 103import android.view.autofill.AutofillId; 104import android.view.autofill.AutofillManager; 105import android.view.autofill.AutofillValue; 106import android.view.inputmethod.EditorInfo; 107import android.view.inputmethod.InputConnection; 108import android.view.inputmethod.InputMethodManager; 109import android.widget.Checkable; 110import android.widget.FrameLayout; 111import android.widget.ScrollBarDrawable; 112 113import com.android.internal.R; 114import com.android.internal.view.TooltipPopup; 115import com.android.internal.view.menu.MenuBuilder; 116import com.android.internal.widget.ScrollBarUtils; 117 118import com.google.android.collect.Lists; 119import com.google.android.collect.Maps; 120 121import java.lang.annotation.Retention; 122import java.lang.annotation.RetentionPolicy; 123import java.lang.ref.WeakReference; 124import java.lang.reflect.Field; 125import java.lang.reflect.InvocationTargetException; 126import java.lang.reflect.Method; 127import java.lang.reflect.Modifier; 128import java.util.ArrayList; 129import java.util.Arrays; 130import java.util.Collection; 131import java.util.Collections; 132import java.util.HashMap; 133import java.util.List; 134import java.util.Locale; 135import java.util.Map; 136import java.util.concurrent.CopyOnWriteArrayList; 137import java.util.concurrent.atomic.AtomicInteger; 138import java.util.function.Predicate; 139 140/** 141 * <p> 142 * This class represents the basic building block for user interface components. A View 143 * occupies a rectangular area on the screen and is responsible for drawing and 144 * event handling. View is the base class for <em>widgets</em>, which are 145 * used to create interactive UI components (buttons, text fields, etc.). The 146 * {@link android.view.ViewGroup} subclass is the base class for <em>layouts</em>, which 147 * are invisible containers that hold other Views (or other ViewGroups) and define 148 * their layout properties. 149 * </p> 150 * 151 * <div class="special reference"> 152 * <h3>Developer Guides</h3> 153 * <p>For information about using this class to develop your application's user interface, 154 * read the <a href="{@docRoot}guide/topics/ui/index.html">User Interface</a> developer guide. 155 * </div> 156 * 157 * <a name="Using"></a> 158 * <h3>Using Views</h3> 159 * <p> 160 * All of the views in a window are arranged in a single tree. You can add views 161 * either from code or by specifying a tree of views in one or more XML layout 162 * files. There are many specialized subclasses of views that act as controls or 163 * are capable of displaying text, images, or other content. 164 * </p> 165 * <p> 166 * Once you have created a tree of views, there are typically a few types of 167 * common operations you may wish to perform: 168 * <ul> 169 * <li><strong>Set properties:</strong> for example setting the text of a 170 * {@link android.widget.TextView}. The available properties and the methods 171 * that set them will vary among the different subclasses of views. Note that 172 * properties that are known at build time can be set in the XML layout 173 * files.</li> 174 * <li><strong>Set focus:</strong> The framework will handle moving focus in 175 * response to user input. To force focus to a specific view, call 176 * {@link #requestFocus}.</li> 177 * <li><strong>Set up listeners:</strong> Views allow clients to set listeners 178 * that will be notified when something interesting happens to the view. For 179 * example, all views will let you set a listener to be notified when the view 180 * gains or loses focus. You can register such a listener using 181 * {@link #setOnFocusChangeListener(android.view.View.OnFocusChangeListener)}. 182 * Other view subclasses offer more specialized listeners. For example, a Button 183 * exposes a listener to notify clients when the button is clicked.</li> 184 * <li><strong>Set visibility:</strong> You can hide or show views using 185 * {@link #setVisibility(int)}.</li> 186 * </ul> 187 * </p> 188 * <p><em> 189 * Note: The Android framework is responsible for measuring, laying out and 190 * drawing views. You should not call methods that perform these actions on 191 * views yourself unless you are actually implementing a 192 * {@link android.view.ViewGroup}. 193 * </em></p> 194 * 195 * <a name="Lifecycle"></a> 196 * <h3>Implementing a Custom View</h3> 197 * 198 * <p> 199 * To implement a custom view, you will usually begin by providing overrides for 200 * some of the standard methods that the framework calls on all views. You do 201 * not need to override all of these methods. In fact, you can start by just 202 * overriding {@link #onDraw(android.graphics.Canvas)}. 203 * <table border="2" width="85%" align="center" cellpadding="5"> 204 * <thead> 205 * <tr><th>Category</th> <th>Methods</th> <th>Description</th></tr> 206 * </thead> 207 * 208 * <tbody> 209 * <tr> 210 * <td rowspan="2">Creation</td> 211 * <td>Constructors</td> 212 * <td>There is a form of the constructor that are called when the view 213 * is created from code and a form that is called when the view is 214 * inflated from a layout file. The second form should parse and apply 215 * any attributes defined in the layout file. 216 * </td> 217 * </tr> 218 * <tr> 219 * <td><code>{@link #onFinishInflate()}</code></td> 220 * <td>Called after a view and all of its children has been inflated 221 * from XML.</td> 222 * </tr> 223 * 224 * <tr> 225 * <td rowspan="3">Layout</td> 226 * <td><code>{@link #onMeasure(int, int)}</code></td> 227 * <td>Called to determine the size requirements for this view and all 228 * of its children. 229 * </td> 230 * </tr> 231 * <tr> 232 * <td><code>{@link #onLayout(boolean, int, int, int, int)}</code></td> 233 * <td>Called when this view should assign a size and position to all 234 * of its children. 235 * </td> 236 * </tr> 237 * <tr> 238 * <td><code>{@link #onSizeChanged(int, int, int, int)}</code></td> 239 * <td>Called when the size of this view has changed. 240 * </td> 241 * </tr> 242 * 243 * <tr> 244 * <td>Drawing</td> 245 * <td><code>{@link #onDraw(android.graphics.Canvas)}</code></td> 246 * <td>Called when the view should render its content. 247 * </td> 248 * </tr> 249 * 250 * <tr> 251 * <td rowspan="4">Event processing</td> 252 * <td><code>{@link #onKeyDown(int, KeyEvent)}</code></td> 253 * <td>Called when a new hardware key event occurs. 254 * </td> 255 * </tr> 256 * <tr> 257 * <td><code>{@link #onKeyUp(int, KeyEvent)}</code></td> 258 * <td>Called when a hardware key up event occurs. 259 * </td> 260 * </tr> 261 * <tr> 262 * <td><code>{@link #onTrackballEvent(MotionEvent)}</code></td> 263 * <td>Called when a trackball motion event occurs. 264 * </td> 265 * </tr> 266 * <tr> 267 * <td><code>{@link #onTouchEvent(MotionEvent)}</code></td> 268 * <td>Called when a touch screen motion event occurs. 269 * </td> 270 * </tr> 271 * 272 * <tr> 273 * <td rowspan="2">Focus</td> 274 * <td><code>{@link #onFocusChanged(boolean, int, android.graphics.Rect)}</code></td> 275 * <td>Called when the view gains or loses focus. 276 * </td> 277 * </tr> 278 * 279 * <tr> 280 * <td><code>{@link #onWindowFocusChanged(boolean)}</code></td> 281 * <td>Called when the window containing the view gains or loses focus. 282 * </td> 283 * </tr> 284 * 285 * <tr> 286 * <td rowspan="3">Attaching</td> 287 * <td><code>{@link #onAttachedToWindow()}</code></td> 288 * <td>Called when the view is attached to a window. 289 * </td> 290 * </tr> 291 * 292 * <tr> 293 * <td><code>{@link #onDetachedFromWindow}</code></td> 294 * <td>Called when the view is detached from its window. 295 * </td> 296 * </tr> 297 * 298 * <tr> 299 * <td><code>{@link #onWindowVisibilityChanged(int)}</code></td> 300 * <td>Called when the visibility of the window containing the view 301 * has changed. 302 * </td> 303 * </tr> 304 * </tbody> 305 * 306 * </table> 307 * </p> 308 * 309 * <a name="IDs"></a> 310 * <h3>IDs</h3> 311 * Views may have an integer id associated with them. These ids are typically 312 * assigned in the layout XML files, and are used to find specific views within 313 * the view tree. A common pattern is to: 314 * <ul> 315 * <li>Define a Button in the layout file and assign it a unique ID. 316 * <pre> 317 * <Button 318 * android:id="@+id/my_button" 319 * android:layout_width="wrap_content" 320 * android:layout_height="wrap_content" 321 * android:text="@string/my_button_text"/> 322 * </pre></li> 323 * <li>From the onCreate method of an Activity, find the Button 324 * <pre class="prettyprint"> 325 * Button myButton = findViewById(R.id.my_button); 326 * </pre></li> 327 * </ul> 328 * <p> 329 * View IDs need not be unique throughout the tree, but it is good practice to 330 * ensure that they are at least unique within the part of the tree you are 331 * searching. 332 * </p> 333 * 334 * <a name="Position"></a> 335 * <h3>Position</h3> 336 * <p> 337 * The geometry of a view is that of a rectangle. A view has a location, 338 * expressed as a pair of <em>left</em> and <em>top</em> coordinates, and 339 * two dimensions, expressed as a width and a height. The unit for location 340 * and dimensions is the pixel. 341 * </p> 342 * 343 * <p> 344 * It is possible to retrieve the location of a view by invoking the methods 345 * {@link #getLeft()} and {@link #getTop()}. The former returns the left, or X, 346 * coordinate of the rectangle representing the view. The latter returns the 347 * top, or Y, coordinate of the rectangle representing the view. These methods 348 * both return the location of the view relative to its parent. For instance, 349 * when getLeft() returns 20, that means the view is located 20 pixels to the 350 * right of the left edge of its direct parent. 351 * </p> 352 * 353 * <p> 354 * In addition, several convenience methods are offered to avoid unnecessary 355 * computations, namely {@link #getRight()} and {@link #getBottom()}. 356 * These methods return the coordinates of the right and bottom edges of the 357 * rectangle representing the view. For instance, calling {@link #getRight()} 358 * is similar to the following computation: <code>getLeft() + getWidth()</code> 359 * (see <a href="#SizePaddingMargins">Size</a> for more information about the width.) 360 * </p> 361 * 362 * <a name="SizePaddingMargins"></a> 363 * <h3>Size, padding and margins</h3> 364 * <p> 365 * The size of a view is expressed with a width and a height. A view actually 366 * possess two pairs of width and height values. 367 * </p> 368 * 369 * <p> 370 * The first pair is known as <em>measured width</em> and 371 * <em>measured height</em>. These dimensions define how big a view wants to be 372 * within its parent (see <a href="#Layout">Layout</a> for more details.) The 373 * measured dimensions can be obtained by calling {@link #getMeasuredWidth()} 374 * and {@link #getMeasuredHeight()}. 375 * </p> 376 * 377 * <p> 378 * The second pair is simply known as <em>width</em> and <em>height</em>, or 379 * sometimes <em>drawing width</em> and <em>drawing height</em>. These 380 * dimensions define the actual size of the view on screen, at drawing time and 381 * after layout. These values may, but do not have to, be different from the 382 * measured width and height. The width and height can be obtained by calling 383 * {@link #getWidth()} and {@link #getHeight()}. 384 * </p> 385 * 386 * <p> 387 * To measure its dimensions, a view takes into account its padding. The padding 388 * is expressed in pixels for the left, top, right and bottom parts of the view. 389 * Padding can be used to offset the content of the view by a specific amount of 390 * pixels. For instance, a left padding of 2 will push the view's content by 391 * 2 pixels to the right of the left edge. Padding can be set using the 392 * {@link #setPadding(int, int, int, int)} or {@link #setPaddingRelative(int, int, int, int)} 393 * method and queried by calling {@link #getPaddingLeft()}, {@link #getPaddingTop()}, 394 * {@link #getPaddingRight()}, {@link #getPaddingBottom()}, {@link #getPaddingStart()}, 395 * {@link #getPaddingEnd()}. 396 * </p> 397 * 398 * <p> 399 * Even though a view can define a padding, it does not provide any support for 400 * margins. However, view groups provide such a support. Refer to 401 * {@link android.view.ViewGroup} and 402 * {@link android.view.ViewGroup.MarginLayoutParams} for further information. 403 * </p> 404 * 405 * <a name="Layout"></a> 406 * <h3>Layout</h3> 407 * <p> 408 * Layout is a two pass process: a measure pass and a layout pass. The measuring 409 * pass is implemented in {@link #measure(int, int)} and is a top-down traversal 410 * of the view tree. Each view pushes dimension specifications down the tree 411 * during the recursion. At the end of the measure pass, every view has stored 412 * its measurements. The second pass happens in 413 * {@link #layout(int,int,int,int)} and is also top-down. During 414 * this pass each parent is responsible for positioning all of its children 415 * using the sizes computed in the measure pass. 416 * </p> 417 * 418 * <p> 419 * When a view's measure() method returns, its {@link #getMeasuredWidth()} and 420 * {@link #getMeasuredHeight()} values must be set, along with those for all of 421 * that view's descendants. A view's measured width and measured height values 422 * must respect the constraints imposed by the view's parents. This guarantees 423 * that at the end of the measure pass, all parents accept all of their 424 * children's measurements. A parent view may call measure() more than once on 425 * its children. For example, the parent may measure each child once with 426 * unspecified dimensions to find out how big they want to be, then call 427 * measure() on them again with actual numbers if the sum of all the children's 428 * unconstrained sizes is too big or too small. 429 * </p> 430 * 431 * <p> 432 * The measure pass uses two classes to communicate dimensions. The 433 * {@link MeasureSpec} class is used by views to tell their parents how they 434 * want to be measured and positioned. The base LayoutParams class just 435 * describes how big the view wants to be for both width and height. For each 436 * dimension, it can specify one of: 437 * <ul> 438 * <li> an exact number 439 * <li>MATCH_PARENT, which means the view wants to be as big as its parent 440 * (minus padding) 441 * <li> WRAP_CONTENT, which means that the view wants to be just big enough to 442 * enclose its content (plus padding). 443 * </ul> 444 * There are subclasses of LayoutParams for different subclasses of ViewGroup. 445 * For example, AbsoluteLayout has its own subclass of LayoutParams which adds 446 * an X and Y value. 447 * </p> 448 * 449 * <p> 450 * MeasureSpecs are used to push requirements down the tree from parent to 451 * child. A MeasureSpec can be in one of three modes: 452 * <ul> 453 * <li>UNSPECIFIED: This is used by a parent to determine the desired dimension 454 * of a child view. For example, a LinearLayout may call measure() on its child 455 * with the height set to UNSPECIFIED and a width of EXACTLY 240 to find out how 456 * tall the child view wants to be given a width of 240 pixels. 457 * <li>EXACTLY: This is used by the parent to impose an exact size on the 458 * child. The child must use this size, and guarantee that all of its 459 * descendants will fit within this size. 460 * <li>AT_MOST: This is used by the parent to impose a maximum size on the 461 * child. The child must guarantee that it and all of its descendants will fit 462 * within this size. 463 * </ul> 464 * </p> 465 * 466 * <p> 467 * To initiate a layout, call {@link #requestLayout}. This method is typically 468 * called by a view on itself when it believes that is can no longer fit within 469 * its current bounds. 470 * </p> 471 * 472 * <a name="Drawing"></a> 473 * <h3>Drawing</h3> 474 * <p> 475 * Drawing is handled by walking the tree and recording the drawing commands of 476 * any View that needs to update. After this, the drawing commands of the 477 * entire tree are issued to screen, clipped to the newly damaged area. 478 * </p> 479 * 480 * <p> 481 * The tree is largely recorded and drawn in order, with parents drawn before 482 * (i.e., behind) their children, with siblings drawn in the order they appear 483 * in the tree. If you set a background drawable for a View, then the View will 484 * draw it before calling back to its <code>onDraw()</code> method. The child 485 * drawing order can be overridden with 486 * {@link ViewGroup#setChildrenDrawingOrderEnabled(boolean) custom child drawing order} 487 * in a ViewGroup, and with {@link #setZ(float)} custom Z values} set on Views. 488 * </p> 489 * 490 * <p> 491 * To force a view to draw, call {@link #invalidate()}. 492 * </p> 493 * 494 * <a name="EventHandlingThreading"></a> 495 * <h3>Event Handling and Threading</h3> 496 * <p> 497 * The basic cycle of a view is as follows: 498 * <ol> 499 * <li>An event comes in and is dispatched to the appropriate view. The view 500 * handles the event and notifies any listeners.</li> 501 * <li>If in the course of processing the event, the view's bounds may need 502 * to be changed, the view will call {@link #requestLayout()}.</li> 503 * <li>Similarly, if in the course of processing the event the view's appearance 504 * may need to be changed, the view will call {@link #invalidate()}.</li> 505 * <li>If either {@link #requestLayout()} or {@link #invalidate()} were called, 506 * the framework will take care of measuring, laying out, and drawing the tree 507 * as appropriate.</li> 508 * </ol> 509 * </p> 510 * 511 * <p><em>Note: The entire view tree is single threaded. You must always be on 512 * the UI thread when calling any method on any view.</em> 513 * If you are doing work on other threads and want to update the state of a view 514 * from that thread, you should use a {@link Handler}. 515 * </p> 516 * 517 * <a name="FocusHandling"></a> 518 * <h3>Focus Handling</h3> 519 * <p> 520 * The framework will handle routine focus movement in response to user input. 521 * This includes changing the focus as views are removed or hidden, or as new 522 * views become available. Views indicate their willingness to take focus 523 * through the {@link #isFocusable} method. To change whether a view can take 524 * focus, call {@link #setFocusable(boolean)}. When in touch mode (see notes below) 525 * views indicate whether they still would like focus via {@link #isFocusableInTouchMode} 526 * and can change this via {@link #setFocusableInTouchMode(boolean)}. 527 * </p> 528 * <p> 529 * Focus movement is based on an algorithm which finds the nearest neighbor in a 530 * given direction. In rare cases, the default algorithm may not match the 531 * intended behavior of the developer. In these situations, you can provide 532 * explicit overrides by using these XML attributes in the layout file: 533 * <pre> 534 * nextFocusDown 535 * nextFocusLeft 536 * nextFocusRight 537 * nextFocusUp 538 * </pre> 539 * </p> 540 * 541 * 542 * <p> 543 * To get a particular view to take focus, call {@link #requestFocus()}. 544 * </p> 545 * 546 * <a name="TouchMode"></a> 547 * <h3>Touch Mode</h3> 548 * <p> 549 * When a user is navigating a user interface via directional keys such as a D-pad, it is 550 * necessary to give focus to actionable items such as buttons so the user can see 551 * what will take input. If the device has touch capabilities, however, and the user 552 * begins interacting with the interface by touching it, it is no longer necessary to 553 * always highlight, or give focus to, a particular view. This motivates a mode 554 * for interaction named 'touch mode'. 555 * </p> 556 * <p> 557 * For a touch capable device, once the user touches the screen, the device 558 * will enter touch mode. From this point onward, only views for which 559 * {@link #isFocusableInTouchMode} is true will be focusable, such as text editing widgets. 560 * Other views that are touchable, like buttons, will not take focus when touched; they will 561 * only fire the on click listeners. 562 * </p> 563 * <p> 564 * Any time a user hits a directional key, such as a D-pad direction, the view device will 565 * exit touch mode, and find a view to take focus, so that the user may resume interacting 566 * with the user interface without touching the screen again. 567 * </p> 568 * <p> 569 * The touch mode state is maintained across {@link android.app.Activity}s. Call 570 * {@link #isInTouchMode} to see whether the device is currently in touch mode. 571 * </p> 572 * 573 * <a name="Scrolling"></a> 574 * <h3>Scrolling</h3> 575 * <p> 576 * The framework provides basic support for views that wish to internally 577 * scroll their content. This includes keeping track of the X and Y scroll 578 * offset as well as mechanisms for drawing scrollbars. See 579 * {@link #scrollBy(int, int)}, {@link #scrollTo(int, int)}, and 580 * {@link #awakenScrollBars()} for more details. 581 * </p> 582 * 583 * <a name="Tags"></a> 584 * <h3>Tags</h3> 585 * <p> 586 * Unlike IDs, tags are not used to identify views. Tags are essentially an 587 * extra piece of information that can be associated with a view. They are most 588 * often used as a convenience to store data related to views in the views 589 * themselves rather than by putting them in a separate structure. 590 * </p> 591 * <p> 592 * Tags may be specified with character sequence values in layout XML as either 593 * a single tag using the {@link android.R.styleable#View_tag android:tag} 594 * attribute or multiple tags using the {@code <tag>} child element: 595 * <pre> 596 * <View ... 597 * android:tag="@string/mytag_value" /> 598 * <View ...> 599 * <tag android:id="@+id/mytag" 600 * android:value="@string/mytag_value" /> 601 * </View> 602 * </pre> 603 * </p> 604 * <p> 605 * Tags may also be specified with arbitrary objects from code using 606 * {@link #setTag(Object)} or {@link #setTag(int, Object)}. 607 * </p> 608 * 609 * <a name="Themes"></a> 610 * <h3>Themes</h3> 611 * <p> 612 * By default, Views are created using the theme of the Context object supplied 613 * to their constructor; however, a different theme may be specified by using 614 * the {@link android.R.styleable#View_theme android:theme} attribute in layout 615 * XML or by passing a {@link ContextThemeWrapper} to the constructor from 616 * code. 617 * </p> 618 * <p> 619 * When the {@link android.R.styleable#View_theme android:theme} attribute is 620 * used in XML, the specified theme is applied on top of the inflation 621 * context's theme (see {@link LayoutInflater}) and used for the view itself as 622 * well as any child elements. 623 * </p> 624 * <p> 625 * In the following example, both views will be created using the Material dark 626 * color scheme; however, because an overlay theme is used which only defines a 627 * subset of attributes, the value of 628 * {@link android.R.styleable#Theme_colorAccent android:colorAccent} defined on 629 * the inflation context's theme (e.g. the Activity theme) will be preserved. 630 * <pre> 631 * <LinearLayout 632 * ... 633 * android:theme="@android:theme/ThemeOverlay.Material.Dark"> 634 * <View ...> 635 * </LinearLayout> 636 * </pre> 637 * </p> 638 * 639 * <a name="Properties"></a> 640 * <h3>Properties</h3> 641 * <p> 642 * The View class exposes an {@link #ALPHA} property, as well as several transform-related 643 * properties, such as {@link #TRANSLATION_X} and {@link #TRANSLATION_Y}. These properties are 644 * available both in the {@link Property} form as well as in similarly-named setter/getter 645 * methods (such as {@link #setAlpha(float)} for {@link #ALPHA}). These properties can 646 * be used to set persistent state associated with these rendering-related properties on the view. 647 * The properties and methods can also be used in conjunction with 648 * {@link android.animation.Animator Animator}-based animations, described more in the 649 * <a href="#Animation">Animation</a> section. 650 * </p> 651 * 652 * <a name="Animation"></a> 653 * <h3>Animation</h3> 654 * <p> 655 * Starting with Android 3.0, the preferred way of animating views is to use the 656 * {@link android.animation} package APIs. These {@link android.animation.Animator Animator}-based 657 * classes change actual properties of the View object, such as {@link #setAlpha(float) alpha} and 658 * {@link #setTranslationX(float) translationX}. This behavior is contrasted to that of the pre-3.0 659 * {@link android.view.animation.Animation Animation}-based classes, which instead animate only 660 * how the view is drawn on the display. In particular, the {@link ViewPropertyAnimator} class 661 * makes animating these View properties particularly easy and efficient. 662 * </p> 663 * <p> 664 * Alternatively, you can use the pre-3.0 animation classes to animate how Views are rendered. 665 * You can attach an {@link Animation} object to a view using 666 * {@link #setAnimation(Animation)} or 667 * {@link #startAnimation(Animation)}. The animation can alter the scale, 668 * rotation, translation and alpha of a view over time. If the animation is 669 * attached to a view that has children, the animation will affect the entire 670 * subtree rooted by that node. When an animation is started, the framework will 671 * take care of redrawing the appropriate views until the animation completes. 672 * </p> 673 * 674 * <a name="Security"></a> 675 * <h3>Security</h3> 676 * <p> 677 * Sometimes it is essential that an application be able to verify that an action 678 * is being performed with the full knowledge and consent of the user, such as 679 * granting a permission request, making a purchase or clicking on an advertisement. 680 * Unfortunately, a malicious application could try to spoof the user into 681 * performing these actions, unaware, by concealing the intended purpose of the view. 682 * As a remedy, the framework offers a touch filtering mechanism that can be used to 683 * improve the security of views that provide access to sensitive functionality. 684 * </p><p> 685 * To enable touch filtering, call {@link #setFilterTouchesWhenObscured(boolean)} or set the 686 * android:filterTouchesWhenObscured layout attribute to true. When enabled, the framework 687 * will discard touches that are received whenever the view's window is obscured by 688 * another visible window. As a result, the view will not receive touches whenever a 689 * toast, dialog or other window appears above the view's window. 690 * </p><p> 691 * For more fine-grained control over security, consider overriding the 692 * {@link #onFilterTouchEventForSecurity(MotionEvent)} method to implement your own 693 * security policy. See also {@link MotionEvent#FLAG_WINDOW_IS_OBSCURED}. 694 * </p> 695 * 696 * @attr ref android.R.styleable#View_alpha 697 * @attr ref android.R.styleable#View_background 698 * @attr ref android.R.styleable#View_clickable 699 * @attr ref android.R.styleable#View_contentDescription 700 * @attr ref android.R.styleable#View_drawingCacheQuality 701 * @attr ref android.R.styleable#View_duplicateParentState 702 * @attr ref android.R.styleable#View_id 703 * @attr ref android.R.styleable#View_requiresFadingEdge 704 * @attr ref android.R.styleable#View_fadeScrollbars 705 * @attr ref android.R.styleable#View_fadingEdgeLength 706 * @attr ref android.R.styleable#View_filterTouchesWhenObscured 707 * @attr ref android.R.styleable#View_fitsSystemWindows 708 * @attr ref android.R.styleable#View_isScrollContainer 709 * @attr ref android.R.styleable#View_focusable 710 * @attr ref android.R.styleable#View_focusableInTouchMode 711 * @attr ref android.R.styleable#View_focusedByDefault 712 * @attr ref android.R.styleable#View_hapticFeedbackEnabled 713 * @attr ref android.R.styleable#View_keepScreenOn 714 * @attr ref android.R.styleable#View_keyboardNavigationCluster 715 * @attr ref android.R.styleable#View_layerType 716 * @attr ref android.R.styleable#View_layoutDirection 717 * @attr ref android.R.styleable#View_longClickable 718 * @attr ref android.R.styleable#View_minHeight 719 * @attr ref android.R.styleable#View_minWidth 720 * @attr ref android.R.styleable#View_nextClusterForward 721 * @attr ref android.R.styleable#View_nextFocusDown 722 * @attr ref android.R.styleable#View_nextFocusLeft 723 * @attr ref android.R.styleable#View_nextFocusRight 724 * @attr ref android.R.styleable#View_nextFocusUp 725 * @attr ref android.R.styleable#View_onClick 726 * @attr ref android.R.styleable#View_padding 727 * @attr ref android.R.styleable#View_paddingHorizontal 728 * @attr ref android.R.styleable#View_paddingVertical 729 * @attr ref android.R.styleable#View_paddingBottom 730 * @attr ref android.R.styleable#View_paddingLeft 731 * @attr ref android.R.styleable#View_paddingRight 732 * @attr ref android.R.styleable#View_paddingTop 733 * @attr ref android.R.styleable#View_paddingStart 734 * @attr ref android.R.styleable#View_paddingEnd 735 * @attr ref android.R.styleable#View_saveEnabled 736 * @attr ref android.R.styleable#View_rotation 737 * @attr ref android.R.styleable#View_rotationX 738 * @attr ref android.R.styleable#View_rotationY 739 * @attr ref android.R.styleable#View_scaleX 740 * @attr ref android.R.styleable#View_scaleY 741 * @attr ref android.R.styleable#View_scrollX 742 * @attr ref android.R.styleable#View_scrollY 743 * @attr ref android.R.styleable#View_scrollbarSize 744 * @attr ref android.R.styleable#View_scrollbarStyle 745 * @attr ref android.R.styleable#View_scrollbars 746 * @attr ref android.R.styleable#View_scrollbarDefaultDelayBeforeFade 747 * @attr ref android.R.styleable#View_scrollbarFadeDuration 748 * @attr ref android.R.styleable#View_scrollbarTrackHorizontal 749 * @attr ref android.R.styleable#View_scrollbarThumbHorizontal 750 * @attr ref android.R.styleable#View_scrollbarThumbVertical 751 * @attr ref android.R.styleable#View_scrollbarTrackVertical 752 * @attr ref android.R.styleable#View_scrollbarAlwaysDrawHorizontalTrack 753 * @attr ref android.R.styleable#View_scrollbarAlwaysDrawVerticalTrack 754 * @attr ref android.R.styleable#View_stateListAnimator 755 * @attr ref android.R.styleable#View_transitionName 756 * @attr ref android.R.styleable#View_soundEffectsEnabled 757 * @attr ref android.R.styleable#View_tag 758 * @attr ref android.R.styleable#View_textAlignment 759 * @attr ref android.R.styleable#View_textDirection 760 * @attr ref android.R.styleable#View_transformPivotX 761 * @attr ref android.R.styleable#View_transformPivotY 762 * @attr ref android.R.styleable#View_translationX 763 * @attr ref android.R.styleable#View_translationY 764 * @attr ref android.R.styleable#View_translationZ 765 * @attr ref android.R.styleable#View_visibility 766 * @attr ref android.R.styleable#View_theme 767 * 768 * @see android.view.ViewGroup 769 */ 770@UiThread 771public class View implements Drawable.Callback, KeyEvent.Callback, 772 AccessibilityEventSource { 773 private static final boolean DBG = false; 774 775 /** @hide */ 776 public static boolean DEBUG_DRAW = false; 777 778 /** 779 * The logging tag used by this class with android.util.Log. 780 */ 781 protected static final String VIEW_LOG_TAG = "View"; 782 783 /** 784 * When set to true, apps will draw debugging information about their layouts. 785 * 786 * @hide 787 */ 788 public static final String DEBUG_LAYOUT_PROPERTY = "debug.layout"; 789 790 /** 791 * When set to true, this view will save its attribute data. 792 * 793 * @hide 794 */ 795 public static boolean mDebugViewAttributes = false; 796 797 /** 798 * Used to mark a View that has no ID. 799 */ 800 public static final int NO_ID = -1; 801 802 /** 803 * Last ID that is given to Views that are no part of activities. 804 * 805 * {@hide} 806 */ 807 public static final int LAST_APP_AUTOFILL_ID = Integer.MAX_VALUE / 2; 808 809 /** 810 * Attribute to find the autofilled highlight 811 * 812 * @see #getAutofilledDrawable() 813 */ 814 private static final int[] AUTOFILL_HIGHLIGHT_ATTR = 815 new int[]{android.R.attr.autofilledHighlight}; 816 817 /** 818 * Signals that compatibility booleans have been initialized according to 819 * target SDK versions. 820 */ 821 private static boolean sCompatibilityDone = false; 822 823 /** 824 * Use the old (broken) way of building MeasureSpecs. 825 */ 826 private static boolean sUseBrokenMakeMeasureSpec = false; 827 828 /** 829 * Always return a size of 0 for MeasureSpec values with a mode of UNSPECIFIED 830 */ 831 static boolean sUseZeroUnspecifiedMeasureSpec = false; 832 833 /** 834 * Ignore any optimizations using the measure cache. 835 */ 836 private static boolean sIgnoreMeasureCache = false; 837 838 /** 839 * Ignore an optimization that skips unnecessary EXACTLY layout passes. 840 */ 841 private static boolean sAlwaysRemeasureExactly = false; 842 843 /** 844 * Relax constraints around whether setLayoutParams() must be called after 845 * modifying the layout params. 846 */ 847 private static boolean sLayoutParamsAlwaysChanged = false; 848 849 /** 850 * Allow setForeground/setBackground to be called (and ignored) on a textureview, 851 * without throwing 852 */ 853 static boolean sTextureViewIgnoresDrawableSetters = false; 854 855 /** 856 * Prior to N, some ViewGroups would not convert LayoutParams properly even though both extend 857 * MarginLayoutParams. For instance, converting LinearLayout.LayoutParams to 858 * RelativeLayout.LayoutParams would lose margin information. This is fixed on N but target API 859 * check is implemented for backwards compatibility. 860 * 861 * {@hide} 862 */ 863 protected static boolean sPreserveMarginParamsInLayoutParamConversion; 864 865 /** 866 * Prior to N, when drag enters into child of a view that has already received an 867 * ACTION_DRAG_ENTERED event, the parent doesn't get a ACTION_DRAG_EXITED event. 868 * ACTION_DRAG_LOCATION and ACTION_DROP were delivered to the parent of a view that returned 869 * false from its event handler for these events. 870 * Starting from N, the parent will get ACTION_DRAG_EXITED event before the child gets its 871 * ACTION_DRAG_ENTERED. ACTION_DRAG_LOCATION and ACTION_DROP are never propagated to the parent. 872 * sCascadedDragDrop is true for pre-N apps for backwards compatibility implementation. 873 */ 874 static boolean sCascadedDragDrop; 875 876 /** 877 * Prior to O, auto-focusable didn't exist and widgets such as ListView use hasFocusable 878 * to determine things like whether or not to permit item click events. We can't break 879 * apps that do this just because more things (clickable things) are now auto-focusable 880 * and they would get different results, so give old behavior to old apps. 881 */ 882 static boolean sHasFocusableExcludeAutoFocusable; 883 884 /** 885 * Prior to O, auto-focusable didn't exist and views marked as clickable weren't implicitly 886 * made focusable by default. As a result, apps could (incorrectly) change the clickable 887 * setting of views off the UI thread. Now that clickable can effect the focusable state, 888 * changing the clickable attribute off the UI thread will cause an exception (since changing 889 * the focusable state checks). In order to prevent apps from crashing, we will handle this 890 * specific case and just not notify parents on new focusables resulting from marking views 891 * clickable from outside the UI thread. 892 */ 893 private static boolean sAutoFocusableOffUIThreadWontNotifyParents; 894 895 /** @hide */ 896 @IntDef({NOT_FOCUSABLE, FOCUSABLE, FOCUSABLE_AUTO}) 897 @Retention(RetentionPolicy.SOURCE) 898 public @interface Focusable {} 899 900 /** 901 * This view does not want keystrokes. 902 * <p> 903 * Use with {@link #setFocusable(int)} and <a href="#attr_android:focusable">{@code 904 * android:focusable}. 905 */ 906 public static final int NOT_FOCUSABLE = 0x00000000; 907 908 /** 909 * This view wants keystrokes. 910 * <p> 911 * Use with {@link #setFocusable(int)} and <a href="#attr_android:focusable">{@code 912 * android:focusable}. 913 */ 914 public static final int FOCUSABLE = 0x00000001; 915 916 /** 917 * This view determines focusability automatically. This is the default. 918 * <p> 919 * Use with {@link #setFocusable(int)} and <a href="#attr_android:focusable">{@code 920 * android:focusable}. 921 */ 922 public static final int FOCUSABLE_AUTO = 0x00000010; 923 924 /** 925 * Mask for use with setFlags indicating bits used for focus. 926 */ 927 private static final int FOCUSABLE_MASK = 0x00000011; 928 929 /** 930 * This view will adjust its padding to fit sytem windows (e.g. status bar) 931 */ 932 private static final int FITS_SYSTEM_WINDOWS = 0x00000002; 933 934 /** @hide */ 935 @IntDef({VISIBLE, INVISIBLE, GONE}) 936 @Retention(RetentionPolicy.SOURCE) 937 public @interface Visibility {} 938 939 /** 940 * This view is visible. 941 * Use with {@link #setVisibility} and <a href="#attr_android:visibility">{@code 942 * android:visibility}. 943 */ 944 public static final int VISIBLE = 0x00000000; 945 946 /** 947 * This view is invisible, but it still takes up space for layout purposes. 948 * Use with {@link #setVisibility} and <a href="#attr_android:visibility">{@code 949 * android:visibility}. 950 */ 951 public static final int INVISIBLE = 0x00000004; 952 953 /** 954 * This view is invisible, and it doesn't take any space for layout 955 * purposes. Use with {@link #setVisibility} and <a href="#attr_android:visibility">{@code 956 * android:visibility}. 957 */ 958 public static final int GONE = 0x00000008; 959 960 /** 961 * Mask for use with setFlags indicating bits used for visibility. 962 * {@hide} 963 */ 964 static final int VISIBILITY_MASK = 0x0000000C; 965 966 private static final int[] VISIBILITY_FLAGS = {VISIBLE, INVISIBLE, GONE}; 967 968 /** 969 * Hint indicating that this view can be autofilled with an email address. 970 * 971 * <p>Can be used with either {@link #setAutofillHints(String[])} or 972 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 973 * value should be <code>{@value #AUTOFILL_HINT_EMAIL_ADDRESS}</code>). 974 * 975 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 976 */ 977 public static final String AUTOFILL_HINT_EMAIL_ADDRESS = "emailAddress"; 978 979 /** 980 * Hint indicating that this view can be autofilled with a user's real name. 981 * 982 * <p>Can be used with either {@link #setAutofillHints(String[])} or 983 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 984 * value should be <code>{@value #AUTOFILL_HINT_NAME}</code>). 985 * 986 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 987 */ 988 public static final String AUTOFILL_HINT_NAME = "name"; 989 990 /** 991 * Hint indicating that this view can be autofilled with a username. 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_USERNAME}</code>). 996 * 997 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 998 */ 999 public static final String AUTOFILL_HINT_USERNAME = "username"; 1000 1001 /** 1002 * Hint indicating that this view can be autofilled with a password. 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_PASSWORD}</code>). 1007 * 1008 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1009 */ 1010 public static final String AUTOFILL_HINT_PASSWORD = "password"; 1011 1012 /** 1013 * Hint indicating that this view can be autofilled with a phone number. 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_PHONE}</code>). 1018 * 1019 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1020 */ 1021 public static final String AUTOFILL_HINT_PHONE = "phone"; 1022 1023 /** 1024 * Hint indicating that this view can be autofilled with a postal address. 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_POSTAL_ADDRESS}</code>). 1029 * 1030 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1031 */ 1032 public static final String AUTOFILL_HINT_POSTAL_ADDRESS = "postalAddress"; 1033 1034 /** 1035 * Hint indicating that this view can be autofilled with a postal code. 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_POSTAL_CODE}</code>). 1040 * 1041 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1042 */ 1043 public static final String AUTOFILL_HINT_POSTAL_CODE = "postalCode"; 1044 1045 /** 1046 * Hint indicating that this view can be autofilled with a credit card number. 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_CREDIT_CARD_NUMBER}</code>). 1051 * 1052 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1053 */ 1054 public static final String AUTOFILL_HINT_CREDIT_CARD_NUMBER = "creditCardNumber"; 1055 1056 /** 1057 * Hint indicating that this view can be autofilled with a credit card security 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_CREDIT_CARD_SECURITY_CODE}</code>). 1062 * 1063 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1064 */ 1065 public static final String AUTOFILL_HINT_CREDIT_CARD_SECURITY_CODE = "creditCardSecurityCode"; 1066 1067 /** 1068 * Hint indicating that this view can be autofilled with a credit card expiration date. 1069 * 1070 * <p>It should be used when the credit card expiration date is represented by just one view; 1071 * if it is represented by more than one (for example, one view for the month and another view 1072 * for the year), then each of these views should use the hint specific for the unit 1073 * ({@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DAY}, 1074 * {@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH}, 1075 * or {@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR}). 1076 * 1077 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1078 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1079 * value should be <code>{@value #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE}</code>). 1080 * 1081 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1082 */ 1083 public static final String AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE = 1084 "creditCardExpirationDate"; 1085 1086 /** 1087 * Hint indicating that this view can be autofilled with a credit card expiration month. 1088 * 1089 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1090 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1091 * value should be <code>{@value #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH}</code>). 1092 * 1093 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1094 */ 1095 public static final String AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH = 1096 "creditCardExpirationMonth"; 1097 1098 /** 1099 * Hint indicating that this view can be autofilled with a credit card expiration year. 1100 * 1101 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1102 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1103 * value should be <code>{@value #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR}</code>). 1104 * 1105 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1106 */ 1107 public static final String AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR = 1108 "creditCardExpirationYear"; 1109 1110 /** 1111 * Hint indicating that this view can be autofilled with a credit card expiration day. 1112 * 1113 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1114 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1115 * value should be <code>{@value #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DAY}</code>). 1116 * 1117 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1118 */ 1119 public static final String AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DAY = "creditCardExpirationDay"; 1120 1121 /** 1122 * Hints for the autofill services that describes the content of the view. 1123 */ 1124 private @Nullable String[] mAutofillHints; 1125 1126 /** 1127 * Autofill id, lazily created on calls to {@link #getAutofillId()}. 1128 */ 1129 private AutofillId mAutofillId; 1130 1131 /** @hide */ 1132 @IntDef({ 1133 AUTOFILL_TYPE_NONE, 1134 AUTOFILL_TYPE_TEXT, 1135 AUTOFILL_TYPE_TOGGLE, 1136 AUTOFILL_TYPE_LIST, 1137 AUTOFILL_TYPE_DATE 1138 }) 1139 @Retention(RetentionPolicy.SOURCE) 1140 public @interface AutofillType {} 1141 1142 /** 1143 * Autofill type for views that cannot be autofilled. 1144 * 1145 * <p>Typically used when the view is read-only; for example, a text label. 1146 * 1147 * @see #getAutofillType() 1148 */ 1149 public static final int AUTOFILL_TYPE_NONE = 0; 1150 1151 /** 1152 * Autofill type for a text field, which is filled by a {@link CharSequence}. 1153 * 1154 * <p>{@link AutofillValue} instances for autofilling a {@link View} can be obtained through 1155 * {@link AutofillValue#forText(CharSequence)}, and the value passed to autofill a 1156 * {@link View} can be fetched through {@link AutofillValue#getTextValue()}. 1157 * 1158 * @see #getAutofillType() 1159 */ 1160 public static final int AUTOFILL_TYPE_TEXT = 1; 1161 1162 /** 1163 * Autofill type for a togglable field, which is filled by a {@code boolean}. 1164 * 1165 * <p>{@link AutofillValue} instances for autofilling a {@link View} can be obtained through 1166 * {@link AutofillValue#forToggle(boolean)}, and the value passed to autofill a 1167 * {@link View} can be fetched through {@link AutofillValue#getToggleValue()}. 1168 * 1169 * @see #getAutofillType() 1170 */ 1171 public static final int AUTOFILL_TYPE_TOGGLE = 2; 1172 1173 /** 1174 * Autofill type for a selection list field, which is filled by an {@code int} 1175 * representing the element index inside the list (starting at {@code 0}). 1176 * 1177 * <p>{@link AutofillValue} instances for autofilling a {@link View} can be obtained through 1178 * {@link AutofillValue#forList(int)}, and the value passed to autofill a 1179 * {@link View} can be fetched through {@link AutofillValue#getListValue()}. 1180 * 1181 * <p>The available options in the selection list are typically provided by 1182 * {@link android.app.assist.AssistStructure.ViewNode#getAutofillOptions()}. 1183 * 1184 * @see #getAutofillType() 1185 */ 1186 public static final int AUTOFILL_TYPE_LIST = 3; 1187 1188 1189 /** 1190 * Autofill type for a field that contains a date, which is represented by a long representing 1191 * the number of milliseconds since the standard base time known as "the epoch", namely 1192 * January 1, 1970, 00:00:00 GMT (see {@link java.util.Date#getTime()}. 1193 * 1194 * <p>{@link AutofillValue} instances for autofilling a {@link View} can be obtained through 1195 * {@link AutofillValue#forDate(long)}, and the values passed to 1196 * autofill a {@link View} can be fetched through {@link AutofillValue#getDateValue()}. 1197 * 1198 * @see #getAutofillType() 1199 */ 1200 public static final int AUTOFILL_TYPE_DATE = 4; 1201 1202 /** @hide */ 1203 @IntDef({ 1204 IMPORTANT_FOR_AUTOFILL_AUTO, 1205 IMPORTANT_FOR_AUTOFILL_YES, 1206 IMPORTANT_FOR_AUTOFILL_NO, 1207 IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS, 1208 IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS 1209 }) 1210 @Retention(RetentionPolicy.SOURCE) 1211 public @interface AutofillImportance {} 1212 1213 /** 1214 * Automatically determine whether a view is important for autofill. 1215 * 1216 * @see #isImportantForAutofill() 1217 * @see #setImportantForAutofill(int) 1218 */ 1219 public static final int IMPORTANT_FOR_AUTOFILL_AUTO = 0x0; 1220 1221 /** 1222 * The view is important for autofill, and its children (if any) will be traversed. 1223 * 1224 * @see #isImportantForAutofill() 1225 * @see #setImportantForAutofill(int) 1226 */ 1227 public static final int IMPORTANT_FOR_AUTOFILL_YES = 0x1; 1228 1229 /** 1230 * The view is not important for autofill, but its children (if any) will be traversed. 1231 * 1232 * @see #isImportantForAutofill() 1233 * @see #setImportantForAutofill(int) 1234 */ 1235 public static final int IMPORTANT_FOR_AUTOFILL_NO = 0x2; 1236 1237 /** 1238 * The view is important for autofill, but its children (if any) will not be traversed. 1239 * 1240 * @see #isImportantForAutofill() 1241 * @see #setImportantForAutofill(int) 1242 */ 1243 public static final int IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS = 0x4; 1244 1245 /** 1246 * The view is not important for autofill, and its children (if any) will not be traversed. 1247 * 1248 * @see #isImportantForAutofill() 1249 * @see #setImportantForAutofill(int) 1250 */ 1251 public static final int IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS = 0x8; 1252 1253 /** @hide */ 1254 @IntDef( 1255 flag = true, 1256 value = {AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS}) 1257 @Retention(RetentionPolicy.SOURCE) 1258 public @interface AutofillFlags {} 1259 1260 /** 1261 * Flag requesting you to add views that are marked as not important for autofill 1262 * (see {@link #setImportantForAutofill(int)}) to a {@link ViewStructure}. 1263 */ 1264 public static final int AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS = 0x1; 1265 1266 /** 1267 * This view is enabled. Interpretation varies by subclass. 1268 * Use with ENABLED_MASK when calling setFlags. 1269 * {@hide} 1270 */ 1271 static final int ENABLED = 0x00000000; 1272 1273 /** 1274 * This view is disabled. Interpretation varies by subclass. 1275 * Use with ENABLED_MASK when calling setFlags. 1276 * {@hide} 1277 */ 1278 static final int DISABLED = 0x00000020; 1279 1280 /** 1281 * Mask for use with setFlags indicating bits used for indicating whether 1282 * this view is enabled 1283 * {@hide} 1284 */ 1285 static final int ENABLED_MASK = 0x00000020; 1286 1287 /** 1288 * This view won't draw. {@link #onDraw(android.graphics.Canvas)} won't be 1289 * called and further optimizations will be performed. It is okay to have 1290 * this flag set and a background. Use with DRAW_MASK when calling setFlags. 1291 * {@hide} 1292 */ 1293 static final int WILL_NOT_DRAW = 0x00000080; 1294 1295 /** 1296 * Mask for use with setFlags indicating bits used for indicating whether 1297 * this view is will draw 1298 * {@hide} 1299 */ 1300 static final int DRAW_MASK = 0x00000080; 1301 1302 /** 1303 * <p>This view doesn't show scrollbars.</p> 1304 * {@hide} 1305 */ 1306 static final int SCROLLBARS_NONE = 0x00000000; 1307 1308 /** 1309 * <p>This view shows horizontal scrollbars.</p> 1310 * {@hide} 1311 */ 1312 static final int SCROLLBARS_HORIZONTAL = 0x00000100; 1313 1314 /** 1315 * <p>This view shows vertical scrollbars.</p> 1316 * {@hide} 1317 */ 1318 static final int SCROLLBARS_VERTICAL = 0x00000200; 1319 1320 /** 1321 * <p>Mask for use with setFlags indicating bits used for indicating which 1322 * scrollbars are enabled.</p> 1323 * {@hide} 1324 */ 1325 static final int SCROLLBARS_MASK = 0x00000300; 1326 1327 /** 1328 * Indicates that the view should filter touches when its window is obscured. 1329 * Refer to the class comments for more information about this security feature. 1330 * {@hide} 1331 */ 1332 static final int FILTER_TOUCHES_WHEN_OBSCURED = 0x00000400; 1333 1334 /** 1335 * Set for framework elements that use FITS_SYSTEM_WINDOWS, to indicate 1336 * that they are optional and should be skipped if the window has 1337 * requested system UI flags that ignore those insets for layout. 1338 */ 1339 static final int OPTIONAL_FITS_SYSTEM_WINDOWS = 0x00000800; 1340 1341 /** 1342 * <p>This view doesn't show fading edges.</p> 1343 * {@hide} 1344 */ 1345 static final int FADING_EDGE_NONE = 0x00000000; 1346 1347 /** 1348 * <p>This view shows horizontal fading edges.</p> 1349 * {@hide} 1350 */ 1351 static final int FADING_EDGE_HORIZONTAL = 0x00001000; 1352 1353 /** 1354 * <p>This view shows vertical fading edges.</p> 1355 * {@hide} 1356 */ 1357 static final int FADING_EDGE_VERTICAL = 0x00002000; 1358 1359 /** 1360 * <p>Mask for use with setFlags indicating bits used for indicating which 1361 * fading edges are enabled.</p> 1362 * {@hide} 1363 */ 1364 static final int FADING_EDGE_MASK = 0x00003000; 1365 1366 /** 1367 * <p>Indicates this view can be clicked. When clickable, a View reacts 1368 * to clicks by notifying the OnClickListener.<p> 1369 * {@hide} 1370 */ 1371 static final int CLICKABLE = 0x00004000; 1372 1373 /** 1374 * <p>Indicates this view is caching its drawing into a bitmap.</p> 1375 * {@hide} 1376 */ 1377 static final int DRAWING_CACHE_ENABLED = 0x00008000; 1378 1379 /** 1380 * <p>Indicates that no icicle should be saved for this view.<p> 1381 * {@hide} 1382 */ 1383 static final int SAVE_DISABLED = 0x000010000; 1384 1385 /** 1386 * <p>Mask for use with setFlags indicating bits used for the saveEnabled 1387 * property.</p> 1388 * {@hide} 1389 */ 1390 static final int SAVE_DISABLED_MASK = 0x000010000; 1391 1392 /** 1393 * <p>Indicates that no drawing cache should ever be created for this view.<p> 1394 * {@hide} 1395 */ 1396 static final int WILL_NOT_CACHE_DRAWING = 0x000020000; 1397 1398 /** 1399 * <p>Indicates this view can take / keep focus when int touch mode.</p> 1400 * {@hide} 1401 */ 1402 static final int FOCUSABLE_IN_TOUCH_MODE = 0x00040000; 1403 1404 /** @hide */ 1405 @Retention(RetentionPolicy.SOURCE) 1406 @IntDef({DRAWING_CACHE_QUALITY_LOW, DRAWING_CACHE_QUALITY_HIGH, DRAWING_CACHE_QUALITY_AUTO}) 1407 public @interface DrawingCacheQuality {} 1408 1409 /** 1410 * <p>Enables low quality mode for the drawing cache.</p> 1411 */ 1412 public static final int DRAWING_CACHE_QUALITY_LOW = 0x00080000; 1413 1414 /** 1415 * <p>Enables high quality mode for the drawing cache.</p> 1416 */ 1417 public static final int DRAWING_CACHE_QUALITY_HIGH = 0x00100000; 1418 1419 /** 1420 * <p>Enables automatic quality mode for the drawing cache.</p> 1421 */ 1422 public static final int DRAWING_CACHE_QUALITY_AUTO = 0x00000000; 1423 1424 private static final int[] DRAWING_CACHE_QUALITY_FLAGS = { 1425 DRAWING_CACHE_QUALITY_AUTO, DRAWING_CACHE_QUALITY_LOW, DRAWING_CACHE_QUALITY_HIGH 1426 }; 1427 1428 /** 1429 * <p>Mask for use with setFlags indicating bits used for the cache 1430 * quality property.</p> 1431 * {@hide} 1432 */ 1433 static final int DRAWING_CACHE_QUALITY_MASK = 0x00180000; 1434 1435 /** 1436 * <p> 1437 * Indicates this view can be long clicked. When long clickable, a View 1438 * reacts to long clicks by notifying the OnLongClickListener or showing a 1439 * context menu. 1440 * </p> 1441 * {@hide} 1442 */ 1443 static final int LONG_CLICKABLE = 0x00200000; 1444 1445 /** 1446 * <p>Indicates that this view gets its drawable states from its direct parent 1447 * and ignores its original internal states.</p> 1448 * 1449 * @hide 1450 */ 1451 static final int DUPLICATE_PARENT_STATE = 0x00400000; 1452 1453 /** 1454 * <p> 1455 * Indicates this view can be context clicked. When context clickable, a View reacts to a 1456 * context click (e.g. a primary stylus button press or right mouse click) by notifying the 1457 * OnContextClickListener. 1458 * </p> 1459 * {@hide} 1460 */ 1461 static final int CONTEXT_CLICKABLE = 0x00800000; 1462 1463 1464 /** @hide */ 1465 @IntDef({ 1466 SCROLLBARS_INSIDE_OVERLAY, 1467 SCROLLBARS_INSIDE_INSET, 1468 SCROLLBARS_OUTSIDE_OVERLAY, 1469 SCROLLBARS_OUTSIDE_INSET 1470 }) 1471 @Retention(RetentionPolicy.SOURCE) 1472 public @interface ScrollBarStyle {} 1473 1474 /** 1475 * The scrollbar style to display the scrollbars inside the content area, 1476 * without increasing the padding. The scrollbars will be overlaid with 1477 * translucency on the view's content. 1478 */ 1479 public static final int SCROLLBARS_INSIDE_OVERLAY = 0; 1480 1481 /** 1482 * The scrollbar style to display the scrollbars inside the padded area, 1483 * increasing the padding of the view. The scrollbars will not overlap the 1484 * content area of the view. 1485 */ 1486 public static final int SCROLLBARS_INSIDE_INSET = 0x01000000; 1487 1488 /** 1489 * The scrollbar style to display the scrollbars at the edge of the view, 1490 * without increasing the padding. The scrollbars will be overlaid with 1491 * translucency. 1492 */ 1493 public static final int SCROLLBARS_OUTSIDE_OVERLAY = 0x02000000; 1494 1495 /** 1496 * The scrollbar style to display the scrollbars at the edge of the view, 1497 * increasing the padding of the view. The scrollbars will only overlap the 1498 * background, if any. 1499 */ 1500 public static final int SCROLLBARS_OUTSIDE_INSET = 0x03000000; 1501 1502 /** 1503 * Mask to check if the scrollbar style is overlay or inset. 1504 * {@hide} 1505 */ 1506 static final int SCROLLBARS_INSET_MASK = 0x01000000; 1507 1508 /** 1509 * Mask to check if the scrollbar style is inside or outside. 1510 * {@hide} 1511 */ 1512 static final int SCROLLBARS_OUTSIDE_MASK = 0x02000000; 1513 1514 /** 1515 * Mask for scrollbar style. 1516 * {@hide} 1517 */ 1518 static final int SCROLLBARS_STYLE_MASK = 0x03000000; 1519 1520 /** 1521 * View flag indicating that the screen should remain on while the 1522 * window containing this view is visible to the user. This effectively 1523 * takes care of automatically setting the WindowManager's 1524 * {@link WindowManager.LayoutParams#FLAG_KEEP_SCREEN_ON}. 1525 */ 1526 public static final int KEEP_SCREEN_ON = 0x04000000; 1527 1528 /** 1529 * View flag indicating whether this view should have sound effects enabled 1530 * for events such as clicking and touching. 1531 */ 1532 public static final int SOUND_EFFECTS_ENABLED = 0x08000000; 1533 1534 /** 1535 * View flag indicating whether this view should have haptic feedback 1536 * enabled for events such as long presses. 1537 */ 1538 public static final int HAPTIC_FEEDBACK_ENABLED = 0x10000000; 1539 1540 /** 1541 * <p>Indicates that the view hierarchy should stop saving state when 1542 * it reaches this view. If state saving is initiated immediately at 1543 * the view, it will be allowed. 1544 * {@hide} 1545 */ 1546 static final int PARENT_SAVE_DISABLED = 0x20000000; 1547 1548 /** 1549 * <p>Mask for use with setFlags indicating bits used for PARENT_SAVE_DISABLED.</p> 1550 * {@hide} 1551 */ 1552 static final int PARENT_SAVE_DISABLED_MASK = 0x20000000; 1553 1554 private static Paint sDebugPaint; 1555 1556 /** 1557 * <p>Indicates this view can display a tooltip on hover or long press.</p> 1558 * {@hide} 1559 */ 1560 static final int TOOLTIP = 0x40000000; 1561 1562 /** @hide */ 1563 @IntDef(flag = true, 1564 value = { 1565 FOCUSABLES_ALL, 1566 FOCUSABLES_TOUCH_MODE 1567 }) 1568 @Retention(RetentionPolicy.SOURCE) 1569 public @interface FocusableMode {} 1570 1571 /** 1572 * View flag indicating whether {@link #addFocusables(ArrayList, int, int)} 1573 * should add all focusable Views regardless if they are focusable in touch mode. 1574 */ 1575 public static final int FOCUSABLES_ALL = 0x00000000; 1576 1577 /** 1578 * View flag indicating whether {@link #addFocusables(ArrayList, int, int)} 1579 * should add only Views focusable in touch mode. 1580 */ 1581 public static final int FOCUSABLES_TOUCH_MODE = 0x00000001; 1582 1583 /** @hide */ 1584 @IntDef({ 1585 FOCUS_BACKWARD, 1586 FOCUS_FORWARD, 1587 FOCUS_LEFT, 1588 FOCUS_UP, 1589 FOCUS_RIGHT, 1590 FOCUS_DOWN 1591 }) 1592 @Retention(RetentionPolicy.SOURCE) 1593 public @interface FocusDirection {} 1594 1595 /** @hide */ 1596 @IntDef({ 1597 FOCUS_LEFT, 1598 FOCUS_UP, 1599 FOCUS_RIGHT, 1600 FOCUS_DOWN 1601 }) 1602 @Retention(RetentionPolicy.SOURCE) 1603 public @interface FocusRealDirection {} // Like @FocusDirection, but without forward/backward 1604 1605 /** 1606 * Use with {@link #focusSearch(int)}. Move focus to the previous selectable 1607 * item. 1608 */ 1609 public static final int FOCUS_BACKWARD = 0x00000001; 1610 1611 /** 1612 * Use with {@link #focusSearch(int)}. Move focus to the next selectable 1613 * item. 1614 */ 1615 public static final int FOCUS_FORWARD = 0x00000002; 1616 1617 /** 1618 * Use with {@link #focusSearch(int)}. Move focus to the left. 1619 */ 1620 public static final int FOCUS_LEFT = 0x00000011; 1621 1622 /** 1623 * Use with {@link #focusSearch(int)}. Move focus up. 1624 */ 1625 public static final int FOCUS_UP = 0x00000021; 1626 1627 /** 1628 * Use with {@link #focusSearch(int)}. Move focus to the right. 1629 */ 1630 public static final int FOCUS_RIGHT = 0x00000042; 1631 1632 /** 1633 * Use with {@link #focusSearch(int)}. Move focus down. 1634 */ 1635 public static final int FOCUS_DOWN = 0x00000082; 1636 1637 /** 1638 * Bits of {@link #getMeasuredWidthAndState()} and 1639 * {@link #getMeasuredWidthAndState()} that provide the actual measured size. 1640 */ 1641 public static final int MEASURED_SIZE_MASK = 0x00ffffff; 1642 1643 /** 1644 * Bits of {@link #getMeasuredWidthAndState()} and 1645 * {@link #getMeasuredWidthAndState()} that provide the additional state bits. 1646 */ 1647 public static final int MEASURED_STATE_MASK = 0xff000000; 1648 1649 /** 1650 * Bit shift of {@link #MEASURED_STATE_MASK} to get to the height bits 1651 * for functions that combine both width and height into a single int, 1652 * such as {@link #getMeasuredState()} and the childState argument of 1653 * {@link #resolveSizeAndState(int, int, int)}. 1654 */ 1655 public static final int MEASURED_HEIGHT_STATE_SHIFT = 16; 1656 1657 /** 1658 * Bit of {@link #getMeasuredWidthAndState()} and 1659 * {@link #getMeasuredWidthAndState()} that indicates the measured size 1660 * is smaller that the space the view would like to have. 1661 */ 1662 public static final int MEASURED_STATE_TOO_SMALL = 0x01000000; 1663 1664 /** 1665 * Base View state sets 1666 */ 1667 // Singles 1668 /** 1669 * Indicates the view has no states set. States are used with 1670 * {@link android.graphics.drawable.Drawable} to change the drawing of the 1671 * view depending on its state. 1672 * 1673 * @see android.graphics.drawable.Drawable 1674 * @see #getDrawableState() 1675 */ 1676 protected static final int[] EMPTY_STATE_SET; 1677 /** 1678 * Indicates the view is enabled. States are used with 1679 * {@link android.graphics.drawable.Drawable} to change the drawing of the 1680 * view depending on its state. 1681 * 1682 * @see android.graphics.drawable.Drawable 1683 * @see #getDrawableState() 1684 */ 1685 protected static final int[] ENABLED_STATE_SET; 1686 /** 1687 * Indicates the view is focused. States are used with 1688 * {@link android.graphics.drawable.Drawable} to change the drawing of the 1689 * view depending on its state. 1690 * 1691 * @see android.graphics.drawable.Drawable 1692 * @see #getDrawableState() 1693 */ 1694 protected static final int[] FOCUSED_STATE_SET; 1695 /** 1696 * Indicates the view is selected. States are used with 1697 * {@link android.graphics.drawable.Drawable} to change the drawing of the 1698 * view depending on its state. 1699 * 1700 * @see android.graphics.drawable.Drawable 1701 * @see #getDrawableState() 1702 */ 1703 protected static final int[] SELECTED_STATE_SET; 1704 /** 1705 * Indicates the view is pressed. States are used with 1706 * {@link android.graphics.drawable.Drawable} to change the drawing of the 1707 * view depending on its state. 1708 * 1709 * @see android.graphics.drawable.Drawable 1710 * @see #getDrawableState() 1711 */ 1712 protected static final int[] PRESSED_STATE_SET; 1713 /** 1714 * Indicates the view's window has focus. States are used with 1715 * {@link android.graphics.drawable.Drawable} to change the drawing of the 1716 * view depending on its state. 1717 * 1718 * @see android.graphics.drawable.Drawable 1719 * @see #getDrawableState() 1720 */ 1721 protected static final int[] WINDOW_FOCUSED_STATE_SET; 1722 // Doubles 1723 /** 1724 * Indicates the view is enabled and has the focus. 1725 * 1726 * @see #ENABLED_STATE_SET 1727 * @see #FOCUSED_STATE_SET 1728 */ 1729 protected static final int[] ENABLED_FOCUSED_STATE_SET; 1730 /** 1731 * Indicates the view is enabled and selected. 1732 * 1733 * @see #ENABLED_STATE_SET 1734 * @see #SELECTED_STATE_SET 1735 */ 1736 protected static final int[] ENABLED_SELECTED_STATE_SET; 1737 /** 1738 * Indicates the view is enabled and that its window has focus. 1739 * 1740 * @see #ENABLED_STATE_SET 1741 * @see #WINDOW_FOCUSED_STATE_SET 1742 */ 1743 protected static final int[] ENABLED_WINDOW_FOCUSED_STATE_SET; 1744 /** 1745 * Indicates the view is focused and selected. 1746 * 1747 * @see #FOCUSED_STATE_SET 1748 * @see #SELECTED_STATE_SET 1749 */ 1750 protected static final int[] FOCUSED_SELECTED_STATE_SET; 1751 /** 1752 * Indicates the view has the focus and that its window has the focus. 1753 * 1754 * @see #FOCUSED_STATE_SET 1755 * @see #WINDOW_FOCUSED_STATE_SET 1756 */ 1757 protected static final int[] FOCUSED_WINDOW_FOCUSED_STATE_SET; 1758 /** 1759 * Indicates the view is selected and that its window has the focus. 1760 * 1761 * @see #SELECTED_STATE_SET 1762 * @see #WINDOW_FOCUSED_STATE_SET 1763 */ 1764 protected static final int[] SELECTED_WINDOW_FOCUSED_STATE_SET; 1765 // Triples 1766 /** 1767 * Indicates the view is enabled, focused and selected. 1768 * 1769 * @see #ENABLED_STATE_SET 1770 * @see #FOCUSED_STATE_SET 1771 * @see #SELECTED_STATE_SET 1772 */ 1773 protected static final int[] ENABLED_FOCUSED_SELECTED_STATE_SET; 1774 /** 1775 * Indicates the view is enabled, focused and its window has the focus. 1776 * 1777 * @see #ENABLED_STATE_SET 1778 * @see #FOCUSED_STATE_SET 1779 * @see #WINDOW_FOCUSED_STATE_SET 1780 */ 1781 protected static final int[] ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET; 1782 /** 1783 * Indicates the view is enabled, selected and its window has the focus. 1784 * 1785 * @see #ENABLED_STATE_SET 1786 * @see #SELECTED_STATE_SET 1787 * @see #WINDOW_FOCUSED_STATE_SET 1788 */ 1789 protected static final int[] ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET; 1790 /** 1791 * Indicates the view is focused, selected and its window has the focus. 1792 * 1793 * @see #FOCUSED_STATE_SET 1794 * @see #SELECTED_STATE_SET 1795 * @see #WINDOW_FOCUSED_STATE_SET 1796 */ 1797 protected static final int[] FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 1798 /** 1799 * Indicates the view is enabled, focused, selected and its window 1800 * has the focus. 1801 * 1802 * @see #ENABLED_STATE_SET 1803 * @see #FOCUSED_STATE_SET 1804 * @see #SELECTED_STATE_SET 1805 * @see #WINDOW_FOCUSED_STATE_SET 1806 */ 1807 protected static final int[] ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 1808 /** 1809 * Indicates the view is pressed and its window has the focus. 1810 * 1811 * @see #PRESSED_STATE_SET 1812 * @see #WINDOW_FOCUSED_STATE_SET 1813 */ 1814 protected static final int[] PRESSED_WINDOW_FOCUSED_STATE_SET; 1815 /** 1816 * Indicates the view is pressed and selected. 1817 * 1818 * @see #PRESSED_STATE_SET 1819 * @see #SELECTED_STATE_SET 1820 */ 1821 protected static final int[] PRESSED_SELECTED_STATE_SET; 1822 /** 1823 * Indicates the view is pressed, selected and its window has the focus. 1824 * 1825 * @see #PRESSED_STATE_SET 1826 * @see #SELECTED_STATE_SET 1827 * @see #WINDOW_FOCUSED_STATE_SET 1828 */ 1829 protected static final int[] PRESSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 1830 /** 1831 * Indicates the view is pressed and focused. 1832 * 1833 * @see #PRESSED_STATE_SET 1834 * @see #FOCUSED_STATE_SET 1835 */ 1836 protected static final int[] PRESSED_FOCUSED_STATE_SET; 1837 /** 1838 * Indicates the view is pressed, focused and its window has the focus. 1839 * 1840 * @see #PRESSED_STATE_SET 1841 * @see #FOCUSED_STATE_SET 1842 * @see #WINDOW_FOCUSED_STATE_SET 1843 */ 1844 protected static final int[] PRESSED_FOCUSED_WINDOW_FOCUSED_STATE_SET; 1845 /** 1846 * Indicates the view is pressed, focused and selected. 1847 * 1848 * @see #PRESSED_STATE_SET 1849 * @see #SELECTED_STATE_SET 1850 * @see #FOCUSED_STATE_SET 1851 */ 1852 protected static final int[] PRESSED_FOCUSED_SELECTED_STATE_SET; 1853 /** 1854 * Indicates the view is pressed, focused, selected and its window has the focus. 1855 * 1856 * @see #PRESSED_STATE_SET 1857 * @see #FOCUSED_STATE_SET 1858 * @see #SELECTED_STATE_SET 1859 * @see #WINDOW_FOCUSED_STATE_SET 1860 */ 1861 protected static final int[] PRESSED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 1862 /** 1863 * Indicates the view is pressed and enabled. 1864 * 1865 * @see #PRESSED_STATE_SET 1866 * @see #ENABLED_STATE_SET 1867 */ 1868 protected static final int[] PRESSED_ENABLED_STATE_SET; 1869 /** 1870 * Indicates the view is pressed, enabled and its window has the focus. 1871 * 1872 * @see #PRESSED_STATE_SET 1873 * @see #ENABLED_STATE_SET 1874 * @see #WINDOW_FOCUSED_STATE_SET 1875 */ 1876 protected static final int[] PRESSED_ENABLED_WINDOW_FOCUSED_STATE_SET; 1877 /** 1878 * Indicates the view is pressed, enabled and selected. 1879 * 1880 * @see #PRESSED_STATE_SET 1881 * @see #ENABLED_STATE_SET 1882 * @see #SELECTED_STATE_SET 1883 */ 1884 protected static final int[] PRESSED_ENABLED_SELECTED_STATE_SET; 1885 /** 1886 * Indicates the view is pressed, enabled, selected and its window has the 1887 * focus. 1888 * 1889 * @see #PRESSED_STATE_SET 1890 * @see #ENABLED_STATE_SET 1891 * @see #SELECTED_STATE_SET 1892 * @see #WINDOW_FOCUSED_STATE_SET 1893 */ 1894 protected static final int[] PRESSED_ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET; 1895 /** 1896 * Indicates the view is pressed, enabled and focused. 1897 * 1898 * @see #PRESSED_STATE_SET 1899 * @see #ENABLED_STATE_SET 1900 * @see #FOCUSED_STATE_SET 1901 */ 1902 protected static final int[] PRESSED_ENABLED_FOCUSED_STATE_SET; 1903 /** 1904 * Indicates the view is pressed, enabled, focused and its window has the 1905 * focus. 1906 * 1907 * @see #PRESSED_STATE_SET 1908 * @see #ENABLED_STATE_SET 1909 * @see #FOCUSED_STATE_SET 1910 * @see #WINDOW_FOCUSED_STATE_SET 1911 */ 1912 protected static final int[] PRESSED_ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET; 1913 /** 1914 * Indicates the view is pressed, enabled, focused and selected. 1915 * 1916 * @see #PRESSED_STATE_SET 1917 * @see #ENABLED_STATE_SET 1918 * @see #SELECTED_STATE_SET 1919 * @see #FOCUSED_STATE_SET 1920 */ 1921 protected static final int[] PRESSED_ENABLED_FOCUSED_SELECTED_STATE_SET; 1922 /** 1923 * Indicates the view is pressed, enabled, focused, selected and its window 1924 * has the focus. 1925 * 1926 * @see #PRESSED_STATE_SET 1927 * @see #ENABLED_STATE_SET 1928 * @see #SELECTED_STATE_SET 1929 * @see #FOCUSED_STATE_SET 1930 * @see #WINDOW_FOCUSED_STATE_SET 1931 */ 1932 protected static final int[] PRESSED_ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 1933 1934 static { 1935 EMPTY_STATE_SET = StateSet.get(0); 1936 1937 WINDOW_FOCUSED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_WINDOW_FOCUSED); 1938 1939 SELECTED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_SELECTED); 1940 SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1941 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED); 1942 1943 FOCUSED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_FOCUSED); 1944 FOCUSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1945 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_FOCUSED); 1946 FOCUSED_SELECTED_STATE_SET = StateSet.get( 1947 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_FOCUSED); 1948 FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1949 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 1950 | StateSet.VIEW_STATE_FOCUSED); 1951 1952 ENABLED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_ENABLED); 1953 ENABLED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1954 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_ENABLED); 1955 ENABLED_SELECTED_STATE_SET = StateSet.get( 1956 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_ENABLED); 1957 ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1958 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 1959 | StateSet.VIEW_STATE_ENABLED); 1960 ENABLED_FOCUSED_STATE_SET = StateSet.get( 1961 StateSet.VIEW_STATE_FOCUSED | StateSet.VIEW_STATE_ENABLED); 1962 ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1963 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_FOCUSED 1964 | StateSet.VIEW_STATE_ENABLED); 1965 ENABLED_FOCUSED_SELECTED_STATE_SET = StateSet.get( 1966 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_FOCUSED 1967 | StateSet.VIEW_STATE_ENABLED); 1968 ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1969 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 1970 | StateSet.VIEW_STATE_FOCUSED| StateSet.VIEW_STATE_ENABLED); 1971 1972 PRESSED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_PRESSED); 1973 PRESSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1974 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_PRESSED); 1975 PRESSED_SELECTED_STATE_SET = StateSet.get( 1976 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_PRESSED); 1977 PRESSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1978 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 1979 | StateSet.VIEW_STATE_PRESSED); 1980 PRESSED_FOCUSED_STATE_SET = StateSet.get( 1981 StateSet.VIEW_STATE_FOCUSED | StateSet.VIEW_STATE_PRESSED); 1982 PRESSED_FOCUSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1983 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_FOCUSED 1984 | StateSet.VIEW_STATE_PRESSED); 1985 PRESSED_FOCUSED_SELECTED_STATE_SET = StateSet.get( 1986 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_FOCUSED 1987 | StateSet.VIEW_STATE_PRESSED); 1988 PRESSED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1989 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 1990 | StateSet.VIEW_STATE_FOCUSED | StateSet.VIEW_STATE_PRESSED); 1991 PRESSED_ENABLED_STATE_SET = StateSet.get( 1992 StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_PRESSED); 1993 PRESSED_ENABLED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1994 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_ENABLED 1995 | StateSet.VIEW_STATE_PRESSED); 1996 PRESSED_ENABLED_SELECTED_STATE_SET = StateSet.get( 1997 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_ENABLED 1998 | StateSet.VIEW_STATE_PRESSED); 1999 PRESSED_ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2000 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 2001 | StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_PRESSED); 2002 PRESSED_ENABLED_FOCUSED_STATE_SET = StateSet.get( 2003 StateSet.VIEW_STATE_FOCUSED | StateSet.VIEW_STATE_ENABLED 2004 | StateSet.VIEW_STATE_PRESSED); 2005 PRESSED_ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2006 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_FOCUSED 2007 | StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_PRESSED); 2008 PRESSED_ENABLED_FOCUSED_SELECTED_STATE_SET = StateSet.get( 2009 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_FOCUSED 2010 | StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_PRESSED); 2011 PRESSED_ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2012 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 2013 | StateSet.VIEW_STATE_FOCUSED| StateSet.VIEW_STATE_ENABLED 2014 | StateSet.VIEW_STATE_PRESSED); 2015 } 2016 2017 /** 2018 * Accessibility event types that are dispatched for text population. 2019 */ 2020 private static final int POPULATING_ACCESSIBILITY_EVENT_TYPES = 2021 AccessibilityEvent.TYPE_VIEW_CLICKED 2022 | AccessibilityEvent.TYPE_VIEW_LONG_CLICKED 2023 | AccessibilityEvent.TYPE_VIEW_SELECTED 2024 | AccessibilityEvent.TYPE_VIEW_FOCUSED 2025 | AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED 2026 | AccessibilityEvent.TYPE_VIEW_HOVER_ENTER 2027 | AccessibilityEvent.TYPE_VIEW_HOVER_EXIT 2028 | AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED 2029 | AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED 2030 | AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED 2031 | AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY; 2032 2033 static final int DEBUG_CORNERS_COLOR = Color.rgb(63, 127, 255); 2034 2035 static final int DEBUG_CORNERS_SIZE_DIP = 8; 2036 2037 /** 2038 * Temporary Rect currently for use in setBackground(). This will probably 2039 * be extended in the future to hold our own class with more than just 2040 * a Rect. :) 2041 */ 2042 static final ThreadLocal<Rect> sThreadLocal = new ThreadLocal<Rect>(); 2043 2044 /** 2045 * Map used to store views' tags. 2046 */ 2047 private SparseArray<Object> mKeyedTags; 2048 2049 /** 2050 * The next available accessibility id. 2051 */ 2052 private static int sNextAccessibilityViewId; 2053 2054 /** 2055 * The animation currently associated with this view. 2056 * @hide 2057 */ 2058 protected Animation mCurrentAnimation = null; 2059 2060 /** 2061 * Width as measured during measure pass. 2062 * {@hide} 2063 */ 2064 @ViewDebug.ExportedProperty(category = "measurement") 2065 int mMeasuredWidth; 2066 2067 /** 2068 * Height as measured during measure pass. 2069 * {@hide} 2070 */ 2071 @ViewDebug.ExportedProperty(category = "measurement") 2072 int mMeasuredHeight; 2073 2074 /** 2075 * Flag to indicate that this view was marked INVALIDATED, or had its display list 2076 * invalidated, prior to the current drawing iteration. If true, the view must re-draw 2077 * its display list. This flag, used only when hw accelerated, allows us to clear the 2078 * flag while retaining this information until it's needed (at getDisplayList() time and 2079 * in drawChild(), when we decide to draw a view's children's display lists into our own). 2080 * 2081 * {@hide} 2082 */ 2083 boolean mRecreateDisplayList = false; 2084 2085 /** 2086 * The view's identifier. 2087 * {@hide} 2088 * 2089 * @see #setId(int) 2090 * @see #getId() 2091 */ 2092 @IdRes 2093 @ViewDebug.ExportedProperty(resolveId = true) 2094 int mID = NO_ID; 2095 2096 /** The ID of this view for autofill purposes. 2097 * <ul> 2098 * <li>== {@link #NO_ID}: ID has not been assigned yet 2099 * <li>≤ {@link #LAST_APP_AUTOFILL_ID}: View is not part of a activity. The ID is 2100 * unique in the process. This might change 2101 * over activity lifecycle events. 2102 * <li>> {@link #LAST_APP_AUTOFILL_ID}: View is part of a activity. The ID is 2103 * unique in the activity. This stays the same 2104 * over activity lifecycle events. 2105 */ 2106 private int mAutofillViewId = NO_ID; 2107 2108 // ID for accessibility purposes. This ID must be unique for every window 2109 private int mAccessibilityViewId = NO_ID; 2110 2111 private int mAccessibilityCursorPosition = ACCESSIBILITY_CURSOR_POSITION_UNDEFINED; 2112 2113 /** 2114 * The view's tag. 2115 * {@hide} 2116 * 2117 * @see #setTag(Object) 2118 * @see #getTag() 2119 */ 2120 protected Object mTag = null; 2121 2122 // for mPrivateFlags: 2123 /** {@hide} */ 2124 static final int PFLAG_WANTS_FOCUS = 0x00000001; 2125 /** {@hide} */ 2126 static final int PFLAG_FOCUSED = 0x00000002; 2127 /** {@hide} */ 2128 static final int PFLAG_SELECTED = 0x00000004; 2129 /** {@hide} */ 2130 static final int PFLAG_IS_ROOT_NAMESPACE = 0x00000008; 2131 /** {@hide} */ 2132 static final int PFLAG_HAS_BOUNDS = 0x00000010; 2133 /** {@hide} */ 2134 static final int PFLAG_DRAWN = 0x00000020; 2135 /** 2136 * When this flag is set, this view is running an animation on behalf of its 2137 * children and should therefore not cancel invalidate requests, even if they 2138 * lie outside of this view's bounds. 2139 * 2140 * {@hide} 2141 */ 2142 static final int PFLAG_DRAW_ANIMATION = 0x00000040; 2143 /** {@hide} */ 2144 static final int PFLAG_SKIP_DRAW = 0x00000080; 2145 /** {@hide} */ 2146 static final int PFLAG_REQUEST_TRANSPARENT_REGIONS = 0x00000200; 2147 /** {@hide} */ 2148 static final int PFLAG_DRAWABLE_STATE_DIRTY = 0x00000400; 2149 /** {@hide} */ 2150 static final int PFLAG_MEASURED_DIMENSION_SET = 0x00000800; 2151 /** {@hide} */ 2152 static final int PFLAG_FORCE_LAYOUT = 0x00001000; 2153 /** {@hide} */ 2154 static final int PFLAG_LAYOUT_REQUIRED = 0x00002000; 2155 2156 private static final int PFLAG_PRESSED = 0x00004000; 2157 2158 /** {@hide} */ 2159 static final int PFLAG_DRAWING_CACHE_VALID = 0x00008000; 2160 /** 2161 * Flag used to indicate that this view should be drawn once more (and only once 2162 * more) after its animation has completed. 2163 * {@hide} 2164 */ 2165 static final int PFLAG_ANIMATION_STARTED = 0x00010000; 2166 2167 private static final int PFLAG_SAVE_STATE_CALLED = 0x00020000; 2168 2169 /** 2170 * Indicates that the View returned true when onSetAlpha() was called and that 2171 * the alpha must be restored. 2172 * {@hide} 2173 */ 2174 static final int PFLAG_ALPHA_SET = 0x00040000; 2175 2176 /** 2177 * Set by {@link #setScrollContainer(boolean)}. 2178 */ 2179 static final int PFLAG_SCROLL_CONTAINER = 0x00080000; 2180 2181 /** 2182 * Set by {@link #setScrollContainer(boolean)}. 2183 */ 2184 static final int PFLAG_SCROLL_CONTAINER_ADDED = 0x00100000; 2185 2186 /** 2187 * View flag indicating whether this view was invalidated (fully or partially.) 2188 * 2189 * @hide 2190 */ 2191 static final int PFLAG_DIRTY = 0x00200000; 2192 2193 /** 2194 * View flag indicating whether this view was invalidated by an opaque 2195 * invalidate request. 2196 * 2197 * @hide 2198 */ 2199 static final int PFLAG_DIRTY_OPAQUE = 0x00400000; 2200 2201 /** 2202 * Mask for {@link #PFLAG_DIRTY} and {@link #PFLAG_DIRTY_OPAQUE}. 2203 * 2204 * @hide 2205 */ 2206 static final int PFLAG_DIRTY_MASK = 0x00600000; 2207 2208 /** 2209 * Indicates whether the background is opaque. 2210 * 2211 * @hide 2212 */ 2213 static final int PFLAG_OPAQUE_BACKGROUND = 0x00800000; 2214 2215 /** 2216 * Indicates whether the scrollbars are opaque. 2217 * 2218 * @hide 2219 */ 2220 static final int PFLAG_OPAQUE_SCROLLBARS = 0x01000000; 2221 2222 /** 2223 * Indicates whether the view is opaque. 2224 * 2225 * @hide 2226 */ 2227 static final int PFLAG_OPAQUE_MASK = 0x01800000; 2228 2229 /** 2230 * Indicates a prepressed state; 2231 * the short time between ACTION_DOWN and recognizing 2232 * a 'real' press. Prepressed is used to recognize quick taps 2233 * even when they are shorter than ViewConfiguration.getTapTimeout(). 2234 * 2235 * @hide 2236 */ 2237 private static final int PFLAG_PREPRESSED = 0x02000000; 2238 2239 /** 2240 * Indicates whether the view is temporarily detached. 2241 * 2242 * @hide 2243 */ 2244 static final int PFLAG_CANCEL_NEXT_UP_EVENT = 0x04000000; 2245 2246 /** 2247 * Indicates that we should awaken scroll bars once attached 2248 * 2249 * PLEASE NOTE: This flag is now unused as we now send onVisibilityChanged 2250 * during window attachment and it is no longer needed. Feel free to repurpose it. 2251 * 2252 * @hide 2253 */ 2254 private static final int PFLAG_AWAKEN_SCROLL_BARS_ON_ATTACH = 0x08000000; 2255 2256 /** 2257 * Indicates that the view has received HOVER_ENTER. Cleared on HOVER_EXIT. 2258 * @hide 2259 */ 2260 private static final int PFLAG_HOVERED = 0x10000000; 2261 2262 /** 2263 * no longer needed, should be reused 2264 */ 2265 private static final int PFLAG_DOES_NOTHING_REUSE_PLEASE = 0x20000000; 2266 2267 /** {@hide} */ 2268 static final int PFLAG_ACTIVATED = 0x40000000; 2269 2270 /** 2271 * Indicates that this view was specifically invalidated, not just dirtied because some 2272 * child view was invalidated. The flag is used to determine when we need to recreate 2273 * a view's display list (as opposed to just returning a reference to its existing 2274 * display list). 2275 * 2276 * @hide 2277 */ 2278 static final int PFLAG_INVALIDATED = 0x80000000; 2279 2280 /** 2281 * Masks for mPrivateFlags2, as generated by dumpFlags(): 2282 * 2283 * |-------|-------|-------|-------| 2284 * 1 PFLAG2_DRAG_CAN_ACCEPT 2285 * 1 PFLAG2_DRAG_HOVERED 2286 * 11 PFLAG2_LAYOUT_DIRECTION_MASK 2287 * 1 PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL 2288 * 1 PFLAG2_LAYOUT_DIRECTION_RESOLVED 2289 * 11 PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK 2290 * 1 PFLAG2_TEXT_DIRECTION_FLAGS[1] 2291 * 1 PFLAG2_TEXT_DIRECTION_FLAGS[2] 2292 * 11 PFLAG2_TEXT_DIRECTION_FLAGS[3] 2293 * 1 PFLAG2_TEXT_DIRECTION_FLAGS[4] 2294 * 1 1 PFLAG2_TEXT_DIRECTION_FLAGS[5] 2295 * 11 PFLAG2_TEXT_DIRECTION_FLAGS[6] 2296 * 111 PFLAG2_TEXT_DIRECTION_FLAGS[7] 2297 * 111 PFLAG2_TEXT_DIRECTION_MASK 2298 * 1 PFLAG2_TEXT_DIRECTION_RESOLVED 2299 * 1 PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT 2300 * 111 PFLAG2_TEXT_DIRECTION_RESOLVED_MASK 2301 * 1 PFLAG2_TEXT_ALIGNMENT_FLAGS[1] 2302 * 1 PFLAG2_TEXT_ALIGNMENT_FLAGS[2] 2303 * 11 PFLAG2_TEXT_ALIGNMENT_FLAGS[3] 2304 * 1 PFLAG2_TEXT_ALIGNMENT_FLAGS[4] 2305 * 1 1 PFLAG2_TEXT_ALIGNMENT_FLAGS[5] 2306 * 11 PFLAG2_TEXT_ALIGNMENT_FLAGS[6] 2307 * 111 PFLAG2_TEXT_ALIGNMENT_MASK 2308 * 1 PFLAG2_TEXT_ALIGNMENT_RESOLVED 2309 * 1 PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT 2310 * 111 PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK 2311 * 111 PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK 2312 * 11 PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK 2313 * 1 PFLAG2_ACCESSIBILITY_FOCUSED 2314 * 1 PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED 2315 * 1 PFLAG2_VIEW_QUICK_REJECTED 2316 * 1 PFLAG2_PADDING_RESOLVED 2317 * 1 PFLAG2_DRAWABLE_RESOLVED 2318 * 1 PFLAG2_HAS_TRANSIENT_STATE 2319 * |-------|-------|-------|-------| 2320 */ 2321 2322 /** 2323 * Indicates that this view has reported that it can accept the current drag's content. 2324 * Cleared when the drag operation concludes. 2325 * @hide 2326 */ 2327 static final int PFLAG2_DRAG_CAN_ACCEPT = 0x00000001; 2328 2329 /** 2330 * Indicates that this view is currently directly under the drag location in a 2331 * drag-and-drop operation involving content that it can accept. Cleared when 2332 * the drag exits the view, or when the drag operation concludes. 2333 * @hide 2334 */ 2335 static final int PFLAG2_DRAG_HOVERED = 0x00000002; 2336 2337 /** @hide */ 2338 @IntDef({ 2339 LAYOUT_DIRECTION_LTR, 2340 LAYOUT_DIRECTION_RTL, 2341 LAYOUT_DIRECTION_INHERIT, 2342 LAYOUT_DIRECTION_LOCALE 2343 }) 2344 @Retention(RetentionPolicy.SOURCE) 2345 // Not called LayoutDirection to avoid conflict with android.util.LayoutDirection 2346 public @interface LayoutDir {} 2347 2348 /** @hide */ 2349 @IntDef({ 2350 LAYOUT_DIRECTION_LTR, 2351 LAYOUT_DIRECTION_RTL 2352 }) 2353 @Retention(RetentionPolicy.SOURCE) 2354 public @interface ResolvedLayoutDir {} 2355 2356 /** 2357 * A flag to indicate that the layout direction of this view has not been defined yet. 2358 * @hide 2359 */ 2360 public static final int LAYOUT_DIRECTION_UNDEFINED = LayoutDirection.UNDEFINED; 2361 2362 /** 2363 * Horizontal layout direction of this view is from Left to Right. 2364 * Use with {@link #setLayoutDirection}. 2365 */ 2366 public static final int LAYOUT_DIRECTION_LTR = LayoutDirection.LTR; 2367 2368 /** 2369 * Horizontal layout direction of this view is from Right to Left. 2370 * Use with {@link #setLayoutDirection}. 2371 */ 2372 public static final int LAYOUT_DIRECTION_RTL = LayoutDirection.RTL; 2373 2374 /** 2375 * Horizontal layout direction of this view is inherited from its parent. 2376 * Use with {@link #setLayoutDirection}. 2377 */ 2378 public static final int LAYOUT_DIRECTION_INHERIT = LayoutDirection.INHERIT; 2379 2380 /** 2381 * Horizontal layout direction of this view is from deduced from the default language 2382 * script for the locale. Use with {@link #setLayoutDirection}. 2383 */ 2384 public static final int LAYOUT_DIRECTION_LOCALE = LayoutDirection.LOCALE; 2385 2386 /** 2387 * Bit shift to get the horizontal layout direction. (bits after DRAG_HOVERED) 2388 * @hide 2389 */ 2390 static final int PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT = 2; 2391 2392 /** 2393 * Mask for use with private flags indicating bits used for horizontal layout direction. 2394 * @hide 2395 */ 2396 static final int PFLAG2_LAYOUT_DIRECTION_MASK = 0x00000003 << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 2397 2398 /** 2399 * Indicates whether the view horizontal layout direction has been resolved and drawn to the 2400 * right-to-left direction. 2401 * @hide 2402 */ 2403 static final int PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL = 4 << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 2404 2405 /** 2406 * Indicates whether the view horizontal layout direction has been resolved. 2407 * @hide 2408 */ 2409 static final int PFLAG2_LAYOUT_DIRECTION_RESOLVED = 8 << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 2410 2411 /** 2412 * Mask for use with private flags indicating bits used for resolved horizontal layout direction. 2413 * @hide 2414 */ 2415 static final int PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK = 0x0000000C 2416 << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 2417 2418 /* 2419 * Array of horizontal layout direction flags for mapping attribute "layoutDirection" to correct 2420 * flag value. 2421 * @hide 2422 */ 2423 private static final int[] LAYOUT_DIRECTION_FLAGS = { 2424 LAYOUT_DIRECTION_LTR, 2425 LAYOUT_DIRECTION_RTL, 2426 LAYOUT_DIRECTION_INHERIT, 2427 LAYOUT_DIRECTION_LOCALE 2428 }; 2429 2430 /** 2431 * Default horizontal layout direction. 2432 */ 2433 private static final int LAYOUT_DIRECTION_DEFAULT = LAYOUT_DIRECTION_INHERIT; 2434 2435 /** 2436 * Default horizontal layout direction. 2437 * @hide 2438 */ 2439 static final int LAYOUT_DIRECTION_RESOLVED_DEFAULT = LAYOUT_DIRECTION_LTR; 2440 2441 /** 2442 * Text direction is inherited through {@link ViewGroup} 2443 */ 2444 public static final int TEXT_DIRECTION_INHERIT = 0; 2445 2446 /** 2447 * Text direction is using "first strong algorithm". The first strong directional character 2448 * determines the paragraph direction. If there is no strong directional character, the 2449 * paragraph direction is the view's resolved layout direction. 2450 */ 2451 public static final int TEXT_DIRECTION_FIRST_STRONG = 1; 2452 2453 /** 2454 * Text direction is using "any-RTL" algorithm. The paragraph direction is RTL if it contains 2455 * any strong RTL character, otherwise it is LTR if it contains any strong LTR characters. 2456 * If there are neither, the paragraph direction is the view's resolved layout direction. 2457 */ 2458 public static final int TEXT_DIRECTION_ANY_RTL = 2; 2459 2460 /** 2461 * Text direction is forced to LTR. 2462 */ 2463 public static final int TEXT_DIRECTION_LTR = 3; 2464 2465 /** 2466 * Text direction is forced to RTL. 2467 */ 2468 public static final int TEXT_DIRECTION_RTL = 4; 2469 2470 /** 2471 * Text direction is coming from the system Locale. 2472 */ 2473 public static final int TEXT_DIRECTION_LOCALE = 5; 2474 2475 /** 2476 * Text direction is using "first strong algorithm". The first strong directional character 2477 * determines the paragraph direction. If there is no strong directional character, the 2478 * paragraph direction is LTR. 2479 */ 2480 public static final int TEXT_DIRECTION_FIRST_STRONG_LTR = 6; 2481 2482 /** 2483 * Text direction is using "first strong algorithm". The first strong directional character 2484 * determines the paragraph direction. If there is no strong directional character, the 2485 * paragraph direction is RTL. 2486 */ 2487 public static final int TEXT_DIRECTION_FIRST_STRONG_RTL = 7; 2488 2489 /** 2490 * Default text direction is inherited 2491 */ 2492 private static final int TEXT_DIRECTION_DEFAULT = TEXT_DIRECTION_INHERIT; 2493 2494 /** 2495 * Default resolved text direction 2496 * @hide 2497 */ 2498 static final int TEXT_DIRECTION_RESOLVED_DEFAULT = TEXT_DIRECTION_FIRST_STRONG; 2499 2500 /** 2501 * Bit shift to get the horizontal layout direction. (bits after LAYOUT_DIRECTION_RESOLVED) 2502 * @hide 2503 */ 2504 static final int PFLAG2_TEXT_DIRECTION_MASK_SHIFT = 6; 2505 2506 /** 2507 * Mask for use with private flags indicating bits used for text direction. 2508 * @hide 2509 */ 2510 static final int PFLAG2_TEXT_DIRECTION_MASK = 0x00000007 2511 << PFLAG2_TEXT_DIRECTION_MASK_SHIFT; 2512 2513 /** 2514 * Array of text direction flags for mapping attribute "textDirection" to correct 2515 * flag value. 2516 * @hide 2517 */ 2518 private static final int[] PFLAG2_TEXT_DIRECTION_FLAGS = { 2519 TEXT_DIRECTION_INHERIT << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2520 TEXT_DIRECTION_FIRST_STRONG << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2521 TEXT_DIRECTION_ANY_RTL << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2522 TEXT_DIRECTION_LTR << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2523 TEXT_DIRECTION_RTL << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2524 TEXT_DIRECTION_LOCALE << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2525 TEXT_DIRECTION_FIRST_STRONG_LTR << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2526 TEXT_DIRECTION_FIRST_STRONG_RTL << PFLAG2_TEXT_DIRECTION_MASK_SHIFT 2527 }; 2528 2529 /** 2530 * Indicates whether the view text direction has been resolved. 2531 * @hide 2532 */ 2533 static final int PFLAG2_TEXT_DIRECTION_RESOLVED = 0x00000008 2534 << PFLAG2_TEXT_DIRECTION_MASK_SHIFT; 2535 2536 /** 2537 * Bit shift to get the horizontal layout direction. (bits after DRAG_HOVERED) 2538 * @hide 2539 */ 2540 static final int PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT = 10; 2541 2542 /** 2543 * Mask for use with private flags indicating bits used for resolved text direction. 2544 * @hide 2545 */ 2546 static final int PFLAG2_TEXT_DIRECTION_RESOLVED_MASK = 0x00000007 2547 << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT; 2548 2549 /** 2550 * Indicates whether the view text direction has been resolved to the "first strong" heuristic. 2551 * @hide 2552 */ 2553 static final int PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT = 2554 TEXT_DIRECTION_RESOLVED_DEFAULT << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT; 2555 2556 /** @hide */ 2557 @IntDef({ 2558 TEXT_ALIGNMENT_INHERIT, 2559 TEXT_ALIGNMENT_GRAVITY, 2560 TEXT_ALIGNMENT_CENTER, 2561 TEXT_ALIGNMENT_TEXT_START, 2562 TEXT_ALIGNMENT_TEXT_END, 2563 TEXT_ALIGNMENT_VIEW_START, 2564 TEXT_ALIGNMENT_VIEW_END 2565 }) 2566 @Retention(RetentionPolicy.SOURCE) 2567 public @interface TextAlignment {} 2568 2569 /** 2570 * Default text alignment. The text alignment of this View is inherited from its parent. 2571 * Use with {@link #setTextAlignment(int)} 2572 */ 2573 public static final int TEXT_ALIGNMENT_INHERIT = 0; 2574 2575 /** 2576 * Default for the root view. The gravity determines the text alignment, ALIGN_NORMAL, 2577 * ALIGN_CENTER, or ALIGN_OPPOSITE, which are relative to each paragraph’s text direction. 2578 * 2579 * Use with {@link #setTextAlignment(int)} 2580 */ 2581 public static final int TEXT_ALIGNMENT_GRAVITY = 1; 2582 2583 /** 2584 * Align to the start of the paragraph, e.g. ALIGN_NORMAL. 2585 * 2586 * Use with {@link #setTextAlignment(int)} 2587 */ 2588 public static final int TEXT_ALIGNMENT_TEXT_START = 2; 2589 2590 /** 2591 * Align to the end of the paragraph, e.g. ALIGN_OPPOSITE. 2592 * 2593 * Use with {@link #setTextAlignment(int)} 2594 */ 2595 public static final int TEXT_ALIGNMENT_TEXT_END = 3; 2596 2597 /** 2598 * Center the paragraph, e.g. ALIGN_CENTER. 2599 * 2600 * Use with {@link #setTextAlignment(int)} 2601 */ 2602 public static final int TEXT_ALIGNMENT_CENTER = 4; 2603 2604 /** 2605 * Align to the start of the view, which is ALIGN_LEFT if the view’s resolved 2606 * layoutDirection is LTR, and ALIGN_RIGHT otherwise. 2607 * 2608 * Use with {@link #setTextAlignment(int)} 2609 */ 2610 public static final int TEXT_ALIGNMENT_VIEW_START = 5; 2611 2612 /** 2613 * Align to the end of the view, which is ALIGN_RIGHT if the view’s resolved 2614 * layoutDirection is LTR, and ALIGN_LEFT otherwise. 2615 * 2616 * Use with {@link #setTextAlignment(int)} 2617 */ 2618 public static final int TEXT_ALIGNMENT_VIEW_END = 6; 2619 2620 /** 2621 * Default text alignment is inherited 2622 */ 2623 private static final int TEXT_ALIGNMENT_DEFAULT = TEXT_ALIGNMENT_GRAVITY; 2624 2625 /** 2626 * Default resolved text alignment 2627 * @hide 2628 */ 2629 static final int TEXT_ALIGNMENT_RESOLVED_DEFAULT = TEXT_ALIGNMENT_GRAVITY; 2630 2631 /** 2632 * Bit shift to get the horizontal layout direction. (bits after DRAG_HOVERED) 2633 * @hide 2634 */ 2635 static final int PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT = 13; 2636 2637 /** 2638 * Mask for use with private flags indicating bits used for text alignment. 2639 * @hide 2640 */ 2641 static final int PFLAG2_TEXT_ALIGNMENT_MASK = 0x00000007 << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT; 2642 2643 /** 2644 * Array of text direction flags for mapping attribute "textAlignment" to correct 2645 * flag value. 2646 * @hide 2647 */ 2648 private static final int[] PFLAG2_TEXT_ALIGNMENT_FLAGS = { 2649 TEXT_ALIGNMENT_INHERIT << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 2650 TEXT_ALIGNMENT_GRAVITY << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 2651 TEXT_ALIGNMENT_TEXT_START << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 2652 TEXT_ALIGNMENT_TEXT_END << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 2653 TEXT_ALIGNMENT_CENTER << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 2654 TEXT_ALIGNMENT_VIEW_START << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 2655 TEXT_ALIGNMENT_VIEW_END << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT 2656 }; 2657 2658 /** 2659 * Indicates whether the view text alignment has been resolved. 2660 * @hide 2661 */ 2662 static final int PFLAG2_TEXT_ALIGNMENT_RESOLVED = 0x00000008 << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT; 2663 2664 /** 2665 * Bit shift to get the resolved text alignment. 2666 * @hide 2667 */ 2668 static final int PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT = 17; 2669 2670 /** 2671 * Mask for use with private flags indicating bits used for text alignment. 2672 * @hide 2673 */ 2674 static final int PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK = 0x00000007 2675 << PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT; 2676 2677 /** 2678 * Indicates whether if the view text alignment has been resolved to gravity 2679 */ 2680 private static final int PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT = 2681 TEXT_ALIGNMENT_RESOLVED_DEFAULT << PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT; 2682 2683 // Accessiblity constants for mPrivateFlags2 2684 2685 /** 2686 * Shift for the bits in {@link #mPrivateFlags2} related to the 2687 * "importantForAccessibility" attribute. 2688 */ 2689 static final int PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT = 20; 2690 2691 /** 2692 * Automatically determine whether a view is important for accessibility. 2693 */ 2694 public static final int IMPORTANT_FOR_ACCESSIBILITY_AUTO = 0x00000000; 2695 2696 /** 2697 * The view is important for accessibility. 2698 */ 2699 public static final int IMPORTANT_FOR_ACCESSIBILITY_YES = 0x00000001; 2700 2701 /** 2702 * The view is not important for accessibility. 2703 */ 2704 public static final int IMPORTANT_FOR_ACCESSIBILITY_NO = 0x00000002; 2705 2706 /** 2707 * The view is not important for accessibility, nor are any of its 2708 * descendant views. 2709 */ 2710 public static final int IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS = 0x00000004; 2711 2712 /** 2713 * The default whether the view is important for accessibility. 2714 */ 2715 static final int IMPORTANT_FOR_ACCESSIBILITY_DEFAULT = IMPORTANT_FOR_ACCESSIBILITY_AUTO; 2716 2717 /** 2718 * Mask for obtaining the bits which specify how to determine 2719 * whether a view is important for accessibility. 2720 */ 2721 static final int PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK = (IMPORTANT_FOR_ACCESSIBILITY_AUTO 2722 | IMPORTANT_FOR_ACCESSIBILITY_YES | IMPORTANT_FOR_ACCESSIBILITY_NO 2723 | IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS) 2724 << PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT; 2725 2726 /** 2727 * Shift for the bits in {@link #mPrivateFlags2} related to the 2728 * "accessibilityLiveRegion" attribute. 2729 */ 2730 static final int PFLAG2_ACCESSIBILITY_LIVE_REGION_SHIFT = 23; 2731 2732 /** 2733 * Live region mode specifying that accessibility services should not 2734 * automatically announce changes to this view. This is the default live 2735 * region mode for most views. 2736 * <p> 2737 * Use with {@link #setAccessibilityLiveRegion(int)}. 2738 */ 2739 public static final int ACCESSIBILITY_LIVE_REGION_NONE = 0x00000000; 2740 2741 /** 2742 * Live region mode specifying that accessibility services should announce 2743 * changes to this view. 2744 * <p> 2745 * Use with {@link #setAccessibilityLiveRegion(int)}. 2746 */ 2747 public static final int ACCESSIBILITY_LIVE_REGION_POLITE = 0x00000001; 2748 2749 /** 2750 * Live region mode specifying that accessibility services should interrupt 2751 * ongoing speech to immediately announce changes to this view. 2752 * <p> 2753 * Use with {@link #setAccessibilityLiveRegion(int)}. 2754 */ 2755 public static final int ACCESSIBILITY_LIVE_REGION_ASSERTIVE = 0x00000002; 2756 2757 /** 2758 * The default whether the view is important for accessibility. 2759 */ 2760 static final int ACCESSIBILITY_LIVE_REGION_DEFAULT = ACCESSIBILITY_LIVE_REGION_NONE; 2761 2762 /** 2763 * Mask for obtaining the bits which specify a view's accessibility live 2764 * region mode. 2765 */ 2766 static final int PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK = (ACCESSIBILITY_LIVE_REGION_NONE 2767 | ACCESSIBILITY_LIVE_REGION_POLITE | ACCESSIBILITY_LIVE_REGION_ASSERTIVE) 2768 << PFLAG2_ACCESSIBILITY_LIVE_REGION_SHIFT; 2769 2770 /** 2771 * Flag indicating whether a view has accessibility focus. 2772 */ 2773 static final int PFLAG2_ACCESSIBILITY_FOCUSED = 0x04000000; 2774 2775 /** 2776 * Flag whether the accessibility state of the subtree rooted at this view changed. 2777 */ 2778 static final int PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED = 0x08000000; 2779 2780 /** 2781 * Flag indicating whether a view failed the quickReject() check in draw(). This condition 2782 * is used to check whether later changes to the view's transform should invalidate the 2783 * view to force the quickReject test to run again. 2784 */ 2785 static final int PFLAG2_VIEW_QUICK_REJECTED = 0x10000000; 2786 2787 /** 2788 * Flag indicating that start/end padding has been resolved into left/right padding 2789 * for use in measurement, layout, drawing, etc. This is set by {@link #resolvePadding()} 2790 * and checked by {@link #measure(int, int)} to determine if padding needs to be resolved 2791 * during measurement. In some special cases this is required such as when an adapter-based 2792 * view measures prospective children without attaching them to a window. 2793 */ 2794 static final int PFLAG2_PADDING_RESOLVED = 0x20000000; 2795 2796 /** 2797 * Flag indicating that the start/end drawables has been resolved into left/right ones. 2798 */ 2799 static final int PFLAG2_DRAWABLE_RESOLVED = 0x40000000; 2800 2801 /** 2802 * Indicates that the view is tracking some sort of transient state 2803 * that the app should not need to be aware of, but that the framework 2804 * should take special care to preserve. 2805 */ 2806 static final int PFLAG2_HAS_TRANSIENT_STATE = 0x80000000; 2807 2808 /** 2809 * Group of bits indicating that RTL properties resolution is done. 2810 */ 2811 static final int ALL_RTL_PROPERTIES_RESOLVED = PFLAG2_LAYOUT_DIRECTION_RESOLVED | 2812 PFLAG2_TEXT_DIRECTION_RESOLVED | 2813 PFLAG2_TEXT_ALIGNMENT_RESOLVED | 2814 PFLAG2_PADDING_RESOLVED | 2815 PFLAG2_DRAWABLE_RESOLVED; 2816 2817 // There are a couple of flags left in mPrivateFlags2 2818 2819 /* End of masks for mPrivateFlags2 */ 2820 2821 /** 2822 * Masks for mPrivateFlags3, as generated by dumpFlags(): 2823 * 2824 * |-------|-------|-------|-------| 2825 * 1 PFLAG3_VIEW_IS_ANIMATING_TRANSFORM 2826 * 1 PFLAG3_VIEW_IS_ANIMATING_ALPHA 2827 * 1 PFLAG3_IS_LAID_OUT 2828 * 1 PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT 2829 * 1 PFLAG3_CALLED_SUPER 2830 * 1 PFLAG3_APPLYING_INSETS 2831 * 1 PFLAG3_FITTING_SYSTEM_WINDOWS 2832 * 1 PFLAG3_NESTED_SCROLLING_ENABLED 2833 * 1 PFLAG3_SCROLL_INDICATOR_TOP 2834 * 1 PFLAG3_SCROLL_INDICATOR_BOTTOM 2835 * 1 PFLAG3_SCROLL_INDICATOR_LEFT 2836 * 1 PFLAG3_SCROLL_INDICATOR_RIGHT 2837 * 1 PFLAG3_SCROLL_INDICATOR_START 2838 * 1 PFLAG3_SCROLL_INDICATOR_END 2839 * 1 PFLAG3_ASSIST_BLOCKED 2840 * 1 PFLAG3_CLUSTER 2841 * 1 PFLAG3_IS_AUTOFILLED 2842 * 1 PFLAG3_FINGER_DOWN 2843 * 1 PFLAG3_FOCUSED_BY_DEFAULT 2844 * 1111 PFLAG3_IMPORTANT_FOR_AUTOFILL 2845 * 1 PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE 2846 * 1 PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED 2847 * 1 PFLAG3_TEMPORARY_DETACH 2848 * 1 PFLAG3_NO_REVEAL_ON_FOCUS 2849 * 1 PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT 2850 * |-------|-------|-------|-------| 2851 */ 2852 2853 /** 2854 * Flag indicating that view has a transform animation set on it. This is used to track whether 2855 * an animation is cleared between successive frames, in order to tell the associated 2856 * DisplayList to clear its animation matrix. 2857 */ 2858 static final int PFLAG3_VIEW_IS_ANIMATING_TRANSFORM = 0x1; 2859 2860 /** 2861 * Flag indicating that view has an alpha animation set on it. This is used to track whether an 2862 * animation is cleared between successive frames, in order to tell the associated 2863 * DisplayList to restore its alpha value. 2864 */ 2865 static final int PFLAG3_VIEW_IS_ANIMATING_ALPHA = 0x2; 2866 2867 /** 2868 * Flag indicating that the view has been through at least one layout since it 2869 * was last attached to a window. 2870 */ 2871 static final int PFLAG3_IS_LAID_OUT = 0x4; 2872 2873 /** 2874 * Flag indicating that a call to measure() was skipped and should be done 2875 * instead when layout() is invoked. 2876 */ 2877 static final int PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT = 0x8; 2878 2879 /** 2880 * Flag indicating that an overridden method correctly called down to 2881 * the superclass implementation as required by the API spec. 2882 */ 2883 static final int PFLAG3_CALLED_SUPER = 0x10; 2884 2885 /** 2886 * Flag indicating that we're in the process of applying window insets. 2887 */ 2888 static final int PFLAG3_APPLYING_INSETS = 0x20; 2889 2890 /** 2891 * Flag indicating that we're in the process of fitting system windows using the old method. 2892 */ 2893 static final int PFLAG3_FITTING_SYSTEM_WINDOWS = 0x40; 2894 2895 /** 2896 * Flag indicating that nested scrolling is enabled for this view. 2897 * The view will optionally cooperate with views up its parent chain to allow for 2898 * integrated nested scrolling along the same axis. 2899 */ 2900 static final int PFLAG3_NESTED_SCROLLING_ENABLED = 0x80; 2901 2902 /** 2903 * Flag indicating that the bottom scroll indicator should be displayed 2904 * when this view can scroll up. 2905 */ 2906 static final int PFLAG3_SCROLL_INDICATOR_TOP = 0x0100; 2907 2908 /** 2909 * Flag indicating that the bottom scroll indicator should be displayed 2910 * when this view can scroll down. 2911 */ 2912 static final int PFLAG3_SCROLL_INDICATOR_BOTTOM = 0x0200; 2913 2914 /** 2915 * Flag indicating that the left scroll indicator should be displayed 2916 * when this view can scroll left. 2917 */ 2918 static final int PFLAG3_SCROLL_INDICATOR_LEFT = 0x0400; 2919 2920 /** 2921 * Flag indicating that the right scroll indicator should be displayed 2922 * when this view can scroll right. 2923 */ 2924 static final int PFLAG3_SCROLL_INDICATOR_RIGHT = 0x0800; 2925 2926 /** 2927 * Flag indicating that the start scroll indicator should be displayed 2928 * when this view can scroll in the start direction. 2929 */ 2930 static final int PFLAG3_SCROLL_INDICATOR_START = 0x1000; 2931 2932 /** 2933 * Flag indicating that the end scroll indicator should be displayed 2934 * when this view can scroll in the end direction. 2935 */ 2936 static final int PFLAG3_SCROLL_INDICATOR_END = 0x2000; 2937 2938 static final int DRAG_MASK = PFLAG2_DRAG_CAN_ACCEPT | PFLAG2_DRAG_HOVERED; 2939 2940 static final int SCROLL_INDICATORS_NONE = 0x0000; 2941 2942 /** 2943 * Mask for use with setFlags indicating bits used for indicating which 2944 * scroll indicators are enabled. 2945 */ 2946 static final int SCROLL_INDICATORS_PFLAG3_MASK = PFLAG3_SCROLL_INDICATOR_TOP 2947 | PFLAG3_SCROLL_INDICATOR_BOTTOM | PFLAG3_SCROLL_INDICATOR_LEFT 2948 | PFLAG3_SCROLL_INDICATOR_RIGHT | PFLAG3_SCROLL_INDICATOR_START 2949 | PFLAG3_SCROLL_INDICATOR_END; 2950 2951 /** 2952 * Left-shift required to translate between public scroll indicator flags 2953 * and internal PFLAGS3 flags. When used as a right-shift, translates 2954 * PFLAGS3 flags to public flags. 2955 */ 2956 static final int SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT = 8; 2957 2958 /** @hide */ 2959 @Retention(RetentionPolicy.SOURCE) 2960 @IntDef(flag = true, 2961 value = { 2962 SCROLL_INDICATOR_TOP, 2963 SCROLL_INDICATOR_BOTTOM, 2964 SCROLL_INDICATOR_LEFT, 2965 SCROLL_INDICATOR_RIGHT, 2966 SCROLL_INDICATOR_START, 2967 SCROLL_INDICATOR_END, 2968 }) 2969 public @interface ScrollIndicators {} 2970 2971 /** 2972 * Scroll indicator direction for the top edge of the view. 2973 * 2974 * @see #setScrollIndicators(int) 2975 * @see #setScrollIndicators(int, int) 2976 * @see #getScrollIndicators() 2977 */ 2978 public static final int SCROLL_INDICATOR_TOP = 2979 PFLAG3_SCROLL_INDICATOR_TOP >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 2980 2981 /** 2982 * Scroll indicator direction for the bottom edge of the view. 2983 * 2984 * @see #setScrollIndicators(int) 2985 * @see #setScrollIndicators(int, int) 2986 * @see #getScrollIndicators() 2987 */ 2988 public static final int SCROLL_INDICATOR_BOTTOM = 2989 PFLAG3_SCROLL_INDICATOR_BOTTOM >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 2990 2991 /** 2992 * Scroll indicator direction for the left edge of the view. 2993 * 2994 * @see #setScrollIndicators(int) 2995 * @see #setScrollIndicators(int, int) 2996 * @see #getScrollIndicators() 2997 */ 2998 public static final int SCROLL_INDICATOR_LEFT = 2999 PFLAG3_SCROLL_INDICATOR_LEFT >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 3000 3001 /** 3002 * Scroll indicator direction for the right edge of the view. 3003 * 3004 * @see #setScrollIndicators(int) 3005 * @see #setScrollIndicators(int, int) 3006 * @see #getScrollIndicators() 3007 */ 3008 public static final int SCROLL_INDICATOR_RIGHT = 3009 PFLAG3_SCROLL_INDICATOR_RIGHT >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 3010 3011 /** 3012 * Scroll indicator direction for the starting edge of the view. 3013 * <p> 3014 * Resolved according to the view's layout direction, see 3015 * {@link #getLayoutDirection()} for more information. 3016 * 3017 * @see #setScrollIndicators(int) 3018 * @see #setScrollIndicators(int, int) 3019 * @see #getScrollIndicators() 3020 */ 3021 public static final int SCROLL_INDICATOR_START = 3022 PFLAG3_SCROLL_INDICATOR_START >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 3023 3024 /** 3025 * Scroll indicator direction for the ending edge of the view. 3026 * <p> 3027 * Resolved according to the view's layout direction, see 3028 * {@link #getLayoutDirection()} for more information. 3029 * 3030 * @see #setScrollIndicators(int) 3031 * @see #setScrollIndicators(int, int) 3032 * @see #getScrollIndicators() 3033 */ 3034 public static final int SCROLL_INDICATOR_END = 3035 PFLAG3_SCROLL_INDICATOR_END >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 3036 3037 /** 3038 * <p>Indicates that we are allowing {@link ViewStructure} to traverse 3039 * into this view.<p> 3040 */ 3041 static final int PFLAG3_ASSIST_BLOCKED = 0x4000; 3042 3043 /** 3044 * Flag indicating that the view is a root of a keyboard navigation cluster. 3045 * 3046 * @see #isKeyboardNavigationCluster() 3047 * @see #setKeyboardNavigationCluster(boolean) 3048 */ 3049 private static final int PFLAG3_CLUSTER = 0x8000; 3050 3051 /** 3052 * Flag indicating that the view is autofilled 3053 * 3054 * @see #isAutofilled() 3055 * @see #setAutofilled(boolean) 3056 */ 3057 private static final int PFLAG3_IS_AUTOFILLED = 0x10000; 3058 3059 /** 3060 * Indicates that the user is currently touching the screen. 3061 * Currently used for the tooltip positioning only. 3062 */ 3063 private static final int PFLAG3_FINGER_DOWN = 0x20000; 3064 3065 /** 3066 * Flag indicating that this view is the default-focus view. 3067 * 3068 * @see #isFocusedByDefault() 3069 * @see #setFocusedByDefault(boolean) 3070 */ 3071 private static final int PFLAG3_FOCUSED_BY_DEFAULT = 0x40000; 3072 3073 /** 3074 * Shift for the bits in {@link #mPrivateFlags3} related to the 3075 * "importantForAutofill" attribute. 3076 */ 3077 static final int PFLAG3_IMPORTANT_FOR_AUTOFILL_SHIFT = 19; 3078 3079 /** 3080 * Mask for obtaining the bits which specify how to determine 3081 * whether a view is important for autofill. 3082 */ 3083 static final int PFLAG3_IMPORTANT_FOR_AUTOFILL_MASK = (IMPORTANT_FOR_AUTOFILL_AUTO 3084 | IMPORTANT_FOR_AUTOFILL_YES | IMPORTANT_FOR_AUTOFILL_NO 3085 | IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS 3086 | IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS) 3087 << PFLAG3_IMPORTANT_FOR_AUTOFILL_SHIFT; 3088 3089 /** 3090 * Whether this view has rendered elements that overlap (see {@link 3091 * #hasOverlappingRendering()}, {@link #forceHasOverlappingRendering(boolean)}, and 3092 * {@link #getHasOverlappingRendering()} ). The value in this bit is only valid when 3093 * PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED has been set. Otherwise, the value is 3094 * determined by whatever {@link #hasOverlappingRendering()} returns. 3095 */ 3096 private static final int PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE = 0x800000; 3097 3098 /** 3099 * Whether {@link #forceHasOverlappingRendering(boolean)} has been called. When true, value 3100 * in PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE is valid. 3101 */ 3102 private static final int PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED = 0x1000000; 3103 3104 /** 3105 * Flag indicating that the view is temporarily detached from the parent view. 3106 * 3107 * @see #onStartTemporaryDetach() 3108 * @see #onFinishTemporaryDetach() 3109 */ 3110 static final int PFLAG3_TEMPORARY_DETACH = 0x2000000; 3111 3112 /** 3113 * Flag indicating that the view does not wish to be revealed within its parent 3114 * hierarchy when it gains focus. Expressed in the negative since the historical 3115 * default behavior is to reveal on focus; this flag suppresses that behavior. 3116 * 3117 * @see #setRevealOnFocusHint(boolean) 3118 * @see #getRevealOnFocusHint() 3119 */ 3120 private static final int PFLAG3_NO_REVEAL_ON_FOCUS = 0x4000000; 3121 3122 /** 3123 * Flag indicating that when layout is completed we should notify 3124 * that the view was entered for autofill purposes. To minimize 3125 * showing autofill for views not visible to the user we evaluate 3126 * user visibility which cannot be done until the view is laid out. 3127 */ 3128 static final int PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT = 0x8000000; 3129 3130 /* End of masks for mPrivateFlags3 */ 3131 3132 /** 3133 * Always allow a user to over-scroll this view, provided it is a 3134 * view that can scroll. 3135 * 3136 * @see #getOverScrollMode() 3137 * @see #setOverScrollMode(int) 3138 */ 3139 public static final int OVER_SCROLL_ALWAYS = 0; 3140 3141 /** 3142 * Allow a user to over-scroll this view only if the content is large 3143 * enough to meaningfully scroll, provided it is a view that can scroll. 3144 * 3145 * @see #getOverScrollMode() 3146 * @see #setOverScrollMode(int) 3147 */ 3148 public static final int OVER_SCROLL_IF_CONTENT_SCROLLS = 1; 3149 3150 /** 3151 * Never allow a user to over-scroll this view. 3152 * 3153 * @see #getOverScrollMode() 3154 * @see #setOverScrollMode(int) 3155 */ 3156 public static final int OVER_SCROLL_NEVER = 2; 3157 3158 /** 3159 * Special constant for {@link #setSystemUiVisibility(int)}: View has 3160 * requested the system UI (status bar) to be visible (the default). 3161 * 3162 * @see #setSystemUiVisibility(int) 3163 */ 3164 public static final int SYSTEM_UI_FLAG_VISIBLE = 0; 3165 3166 /** 3167 * Flag for {@link #setSystemUiVisibility(int)}: View has requested the 3168 * system UI to enter an unobtrusive "low profile" mode. 3169 * 3170 * <p>This is for use in games, book readers, video players, or any other 3171 * "immersive" application where the usual system chrome is deemed too distracting. 3172 * 3173 * <p>In low profile mode, the status bar and/or navigation icons may dim. 3174 * 3175 * @see #setSystemUiVisibility(int) 3176 */ 3177 public static final int SYSTEM_UI_FLAG_LOW_PROFILE = 0x00000001; 3178 3179 /** 3180 * Flag for {@link #setSystemUiVisibility(int)}: View has requested that the 3181 * system navigation be temporarily hidden. 3182 * 3183 * <p>This is an even less obtrusive state than that called for by 3184 * {@link #SYSTEM_UI_FLAG_LOW_PROFILE}; on devices that draw essential navigation controls 3185 * (Home, Back, and the like) on screen, <code>SYSTEM_UI_FLAG_HIDE_NAVIGATION</code> will cause 3186 * those to disappear. This is useful (in conjunction with the 3187 * {@link android.view.WindowManager.LayoutParams#FLAG_FULLSCREEN FLAG_FULLSCREEN} and 3188 * {@link android.view.WindowManager.LayoutParams#FLAG_LAYOUT_IN_SCREEN FLAG_LAYOUT_IN_SCREEN} 3189 * window flags) for displaying content using every last pixel on the display. 3190 * 3191 * <p>There is a limitation: because navigation controls are so important, the least user 3192 * interaction will cause them to reappear immediately. When this happens, both 3193 * this flag and {@link #SYSTEM_UI_FLAG_FULLSCREEN} will be cleared automatically, 3194 * so that both elements reappear at the same time. 3195 * 3196 * @see #setSystemUiVisibility(int) 3197 */ 3198 public static final int SYSTEM_UI_FLAG_HIDE_NAVIGATION = 0x00000002; 3199 3200 /** 3201 * Flag for {@link #setSystemUiVisibility(int)}: View has requested to go 3202 * into the normal fullscreen mode so that its content can take over the screen 3203 * while still allowing the user to interact with the application. 3204 * 3205 * <p>This has the same visual effect as 3206 * {@link android.view.WindowManager.LayoutParams#FLAG_FULLSCREEN 3207 * WindowManager.LayoutParams.FLAG_FULLSCREEN}, 3208 * meaning that non-critical screen decorations (such as the status bar) will be 3209 * hidden while the user is in the View's window, focusing the experience on 3210 * that content. Unlike the window flag, if you are using ActionBar in 3211 * overlay mode with {@link Window#FEATURE_ACTION_BAR_OVERLAY 3212 * Window.FEATURE_ACTION_BAR_OVERLAY}, then enabling this flag will also 3213 * hide the action bar. 3214 * 3215 * <p>This approach to going fullscreen is best used over the window flag when 3216 * it is a transient state -- that is, the application does this at certain 3217 * points in its user interaction where it wants to allow the user to focus 3218 * on content, but not as a continuous state. For situations where the application 3219 * would like to simply stay full screen the entire time (such as a game that 3220 * wants to take over the screen), the 3221 * {@link android.view.WindowManager.LayoutParams#FLAG_FULLSCREEN window flag} 3222 * is usually a better approach. The state set here will be removed by the system 3223 * in various situations (such as the user moving to another application) like 3224 * the other system UI states. 3225 * 3226 * <p>When using this flag, the application should provide some easy facility 3227 * for the user to go out of it. A common example would be in an e-book 3228 * reader, where tapping on the screen brings back whatever screen and UI 3229 * decorations that had been hidden while the user was immersed in reading 3230 * the book. 3231 * 3232 * @see #setSystemUiVisibility(int) 3233 */ 3234 public static final int SYSTEM_UI_FLAG_FULLSCREEN = 0x00000004; 3235 3236 /** 3237 * Flag for {@link #setSystemUiVisibility(int)}: When using other layout 3238 * flags, we would like a stable view of the content insets given to 3239 * {@link #fitSystemWindows(Rect)}. This means that the insets seen there 3240 * will always represent the worst case that the application can expect 3241 * as a continuous state. In the stock Android UI this is the space for 3242 * the system bar, nav bar, and status bar, but not more transient elements 3243 * such as an input method. 3244 * 3245 * The stable layout your UI sees is based on the system UI modes you can 3246 * switch to. That is, if you specify {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN} 3247 * then you will get a stable layout for changes of the 3248 * {@link #SYSTEM_UI_FLAG_FULLSCREEN} mode; if you specify 3249 * {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN} and 3250 * {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION}, then you can transition 3251 * to {@link #SYSTEM_UI_FLAG_FULLSCREEN} and {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION} 3252 * with a stable layout. (Note that you should avoid using 3253 * {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION} by itself.) 3254 * 3255 * If you have set the window flag {@link WindowManager.LayoutParams#FLAG_FULLSCREEN} 3256 * to hide the status bar (instead of using {@link #SYSTEM_UI_FLAG_FULLSCREEN}), 3257 * then a hidden status bar will be considered a "stable" state for purposes 3258 * here. This allows your UI to continually hide the status bar, while still 3259 * using the system UI flags to hide the action bar while still retaining 3260 * a stable layout. Note that changing the window fullscreen flag will never 3261 * provide a stable layout for a clean transition. 3262 * 3263 * <p>If you are using ActionBar in 3264 * overlay mode with {@link Window#FEATURE_ACTION_BAR_OVERLAY 3265 * Window.FEATURE_ACTION_BAR_OVERLAY}, this flag will also impact the 3266 * insets it adds to those given to the application. 3267 */ 3268 public static final int SYSTEM_UI_FLAG_LAYOUT_STABLE = 0x00000100; 3269 3270 /** 3271 * Flag for {@link #setSystemUiVisibility(int)}: View would like its window 3272 * to be laid out as if it has requested 3273 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, even if it currently hasn't. This 3274 * allows it to avoid artifacts when switching in and out of that mode, at 3275 * the expense that some of its user interface may be covered by screen 3276 * decorations when they are shown. You can perform layout of your inner 3277 * UI elements to account for the navigation system UI through the 3278 * {@link #fitSystemWindows(Rect)} method. 3279 */ 3280 public static final int SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION = 0x00000200; 3281 3282 /** 3283 * Flag for {@link #setSystemUiVisibility(int)}: View would like its window 3284 * to be laid out as if it has requested 3285 * {@link #SYSTEM_UI_FLAG_FULLSCREEN}, even if it currently hasn't. This 3286 * allows it to avoid artifacts when switching in and out of that mode, at 3287 * the expense that some of its user interface may be covered by screen 3288 * decorations when they are shown. You can perform layout of your inner 3289 * UI elements to account for non-fullscreen system UI through the 3290 * {@link #fitSystemWindows(Rect)} method. 3291 */ 3292 public static final int SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN = 0x00000400; 3293 3294 /** 3295 * Flag for {@link #setSystemUiVisibility(int)}: View would like to remain interactive when 3296 * hiding the navigation bar with {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}. If this flag is 3297 * not set, {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION} will be force cleared by the system on any 3298 * user interaction. 3299 * <p>Since this flag is a modifier for {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, it only 3300 * has an effect when used in combination with that flag.</p> 3301 */ 3302 public static final int SYSTEM_UI_FLAG_IMMERSIVE = 0x00000800; 3303 3304 /** 3305 * Flag for {@link #setSystemUiVisibility(int)}: View would like to remain interactive when 3306 * hiding the status bar with {@link #SYSTEM_UI_FLAG_FULLSCREEN} and/or hiding the navigation 3307 * bar with {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}. Use this flag to create an immersive 3308 * experience while also hiding the system bars. If this flag is not set, 3309 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION} will be force cleared by the system on any user 3310 * interaction, and {@link #SYSTEM_UI_FLAG_FULLSCREEN} will be force-cleared by the system 3311 * if the user swipes from the top of the screen. 3312 * <p>When system bars are hidden in immersive mode, they can be revealed temporarily with 3313 * system gestures, such as swiping from the top of the screen. These transient system bars 3314 * will overlay app’s content, may have some degree of transparency, and will automatically 3315 * hide after a short timeout. 3316 * </p><p>Since this flag is a modifier for {@link #SYSTEM_UI_FLAG_FULLSCREEN} and 3317 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, it only has an effect when used in combination 3318 * with one or both of those flags.</p> 3319 */ 3320 public static final int SYSTEM_UI_FLAG_IMMERSIVE_STICKY = 0x00001000; 3321 3322 /** 3323 * Flag for {@link #setSystemUiVisibility(int)}: Requests the status bar to draw in a mode that 3324 * is compatible with light status bar backgrounds. 3325 * 3326 * <p>For this to take effect, the window must request 3327 * {@link android.view.WindowManager.LayoutParams#FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS 3328 * FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS} but not 3329 * {@link android.view.WindowManager.LayoutParams#FLAG_TRANSLUCENT_STATUS 3330 * FLAG_TRANSLUCENT_STATUS}. 3331 * 3332 * @see android.R.attr#windowLightStatusBar 3333 */ 3334 public static final int SYSTEM_UI_FLAG_LIGHT_STATUS_BAR = 0x00002000; 3335 3336 /** 3337 * This flag was previously used for a private API. DO NOT reuse it for a public API as it might 3338 * trigger undefined behavior on older platforms with apps compiled against a new SDK. 3339 */ 3340 private static final int SYSTEM_UI_RESERVED_LEGACY1 = 0x00004000; 3341 3342 /** 3343 * This flag was previously used for a private API. DO NOT reuse it for a public API as it might 3344 * trigger undefined behavior on older platforms with apps compiled against a new SDK. 3345 */ 3346 private static final int SYSTEM_UI_RESERVED_LEGACY2 = 0x00010000; 3347 3348 /** 3349 * Flag for {@link #setSystemUiVisibility(int)}: Requests the navigation bar to draw in a mode 3350 * that is compatible with light navigation bar backgrounds. 3351 * 3352 * <p>For this to take effect, the window must request 3353 * {@link android.view.WindowManager.LayoutParams#FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS 3354 * FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS} but not 3355 * {@link android.view.WindowManager.LayoutParams#FLAG_TRANSLUCENT_NAVIGATION 3356 * FLAG_TRANSLUCENT_NAVIGATION}. 3357 */ 3358 public static final int SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR = 0x00000010; 3359 3360 /** 3361 * @deprecated Use {@link #SYSTEM_UI_FLAG_LOW_PROFILE} instead. 3362 */ 3363 @Deprecated 3364 public static final int STATUS_BAR_HIDDEN = SYSTEM_UI_FLAG_LOW_PROFILE; 3365 3366 /** 3367 * @deprecated Use {@link #SYSTEM_UI_FLAG_VISIBLE} instead. 3368 */ 3369 @Deprecated 3370 public static final int STATUS_BAR_VISIBLE = SYSTEM_UI_FLAG_VISIBLE; 3371 3372 /** 3373 * @hide 3374 * 3375 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3376 * out of the public fields to keep the undefined bits out of the developer's way. 3377 * 3378 * Flag to make the status bar not expandable. Unless you also 3379 * set {@link #STATUS_BAR_DISABLE_NOTIFICATION_ICONS}, new notifications will continue to show. 3380 */ 3381 public static final int STATUS_BAR_DISABLE_EXPAND = 0x00010000; 3382 3383 /** 3384 * @hide 3385 * 3386 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3387 * out of the public fields to keep the undefined bits out of the developer's way. 3388 * 3389 * Flag to hide notification icons and scrolling ticker text. 3390 */ 3391 public static final int STATUS_BAR_DISABLE_NOTIFICATION_ICONS = 0x00020000; 3392 3393 /** 3394 * @hide 3395 * 3396 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3397 * out of the public fields to keep the undefined bits out of the developer's way. 3398 * 3399 * Flag to disable incoming notification alerts. This will not block 3400 * icons, but it will block sound, vibrating and other visual or aural notifications. 3401 */ 3402 public static final int STATUS_BAR_DISABLE_NOTIFICATION_ALERTS = 0x00040000; 3403 3404 /** 3405 * @hide 3406 * 3407 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3408 * out of the public fields to keep the undefined bits out of the developer's way. 3409 * 3410 * Flag to hide only the scrolling ticker. Note that 3411 * {@link #STATUS_BAR_DISABLE_NOTIFICATION_ICONS} implies 3412 * {@link #STATUS_BAR_DISABLE_NOTIFICATION_TICKER}. 3413 */ 3414 public static final int STATUS_BAR_DISABLE_NOTIFICATION_TICKER = 0x00080000; 3415 3416 /** 3417 * @hide 3418 * 3419 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3420 * out of the public fields to keep the undefined bits out of the developer's way. 3421 * 3422 * Flag to hide the center system info area. 3423 */ 3424 public static final int STATUS_BAR_DISABLE_SYSTEM_INFO = 0x00100000; 3425 3426 /** 3427 * @hide 3428 * 3429 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3430 * out of the public fields to keep the undefined bits out of the developer's way. 3431 * 3432 * Flag to hide only the home button. Don't use this 3433 * unless you're a special part of the system UI (i.e., setup wizard, keyguard). 3434 */ 3435 public static final int STATUS_BAR_DISABLE_HOME = 0x00200000; 3436 3437 /** 3438 * @hide 3439 * 3440 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3441 * out of the public fields to keep the undefined bits out of the developer's way. 3442 * 3443 * Flag to hide only the back button. Don't use this 3444 * unless you're a special part of the system UI (i.e., setup wizard, keyguard). 3445 */ 3446 public static final int STATUS_BAR_DISABLE_BACK = 0x00400000; 3447 3448 /** 3449 * @hide 3450 * 3451 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3452 * out of the public fields to keep the undefined bits out of the developer's way. 3453 * 3454 * Flag to hide only the clock. You might use this if your activity has 3455 * its own clock making the status bar's clock redundant. 3456 */ 3457 public static final int STATUS_BAR_DISABLE_CLOCK = 0x00800000; 3458 3459 /** 3460 * @hide 3461 * 3462 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3463 * out of the public fields to keep the undefined bits out of the developer's way. 3464 * 3465 * Flag to hide only the recent apps button. Don't use this 3466 * unless you're a special part of the system UI (i.e., setup wizard, keyguard). 3467 */ 3468 public static final int STATUS_BAR_DISABLE_RECENT = 0x01000000; 3469 3470 /** 3471 * @hide 3472 * 3473 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3474 * out of the public fields to keep the undefined bits out of the developer's way. 3475 * 3476 * Flag to disable the global search gesture. Don't use this 3477 * unless you're a special part of the system UI (i.e., setup wizard, keyguard). 3478 */ 3479 public static final int STATUS_BAR_DISABLE_SEARCH = 0x02000000; 3480 3481 /** 3482 * @hide 3483 * 3484 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3485 * out of the public fields to keep the undefined bits out of the developer's way. 3486 * 3487 * Flag to specify that the status bar is displayed in transient mode. 3488 */ 3489 public static final int STATUS_BAR_TRANSIENT = 0x04000000; 3490 3491 /** 3492 * @hide 3493 * 3494 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3495 * out of the public fields to keep the undefined bits out of the developer's way. 3496 * 3497 * Flag to specify that the navigation bar is displayed in transient mode. 3498 */ 3499 public static final int NAVIGATION_BAR_TRANSIENT = 0x08000000; 3500 3501 /** 3502 * @hide 3503 * 3504 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3505 * out of the public fields to keep the undefined bits out of the developer's way. 3506 * 3507 * Flag to specify that the hidden status bar would like to be shown. 3508 */ 3509 public static final int STATUS_BAR_UNHIDE = 0x10000000; 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 specify that the hidden navigation bar would like to be shown. 3518 */ 3519 public static final int NAVIGATION_BAR_UNHIDE = 0x20000000; 3520 3521 /** 3522 * @hide 3523 * 3524 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3525 * out of the public fields to keep the undefined bits out of the developer's way. 3526 * 3527 * Flag to specify that the status bar is displayed in translucent mode. 3528 */ 3529 public static final int STATUS_BAR_TRANSLUCENT = 0x40000000; 3530 3531 /** 3532 * @hide 3533 * 3534 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3535 * out of the public fields to keep the undefined bits out of the developer's way. 3536 * 3537 * Flag to specify that the navigation bar is displayed in translucent mode. 3538 */ 3539 public static final int NAVIGATION_BAR_TRANSLUCENT = 0x80000000; 3540 3541 /** 3542 * @hide 3543 * 3544 * Makes navigation bar transparent (but not the status bar). 3545 */ 3546 public static final int NAVIGATION_BAR_TRANSPARENT = 0x00008000; 3547 3548 /** 3549 * @hide 3550 * 3551 * Makes status bar transparent (but not the navigation bar). 3552 */ 3553 public static final int STATUS_BAR_TRANSPARENT = 0x00000008; 3554 3555 /** 3556 * @hide 3557 * 3558 * Makes both status bar and navigation bar transparent. 3559 */ 3560 public static final int SYSTEM_UI_TRANSPARENT = NAVIGATION_BAR_TRANSPARENT 3561 | STATUS_BAR_TRANSPARENT; 3562 3563 /** 3564 * @hide 3565 */ 3566 public static final int PUBLIC_STATUS_BAR_VISIBILITY_MASK = 0x00003FF7; 3567 3568 /** 3569 * These are the system UI flags that can be cleared by events outside 3570 * of an application. Currently this is just the ability to tap on the 3571 * screen while hiding the navigation bar to have it return. 3572 * @hide 3573 */ 3574 public static final int SYSTEM_UI_CLEARABLE_FLAGS = 3575 SYSTEM_UI_FLAG_LOW_PROFILE | SYSTEM_UI_FLAG_HIDE_NAVIGATION 3576 | SYSTEM_UI_FLAG_FULLSCREEN; 3577 3578 /** 3579 * Flags that can impact the layout in relation to system UI. 3580 */ 3581 public static final int SYSTEM_UI_LAYOUT_FLAGS = 3582 SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION 3583 | SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN; 3584 3585 /** @hide */ 3586 @IntDef(flag = true, 3587 value = { FIND_VIEWS_WITH_TEXT, FIND_VIEWS_WITH_CONTENT_DESCRIPTION }) 3588 @Retention(RetentionPolicy.SOURCE) 3589 public @interface FindViewFlags {} 3590 3591 /** 3592 * Find views that render the specified text. 3593 * 3594 * @see #findViewsWithText(ArrayList, CharSequence, int) 3595 */ 3596 public static final int FIND_VIEWS_WITH_TEXT = 0x00000001; 3597 3598 /** 3599 * Find find views that contain the specified content description. 3600 * 3601 * @see #findViewsWithText(ArrayList, CharSequence, int) 3602 */ 3603 public static final int FIND_VIEWS_WITH_CONTENT_DESCRIPTION = 0x00000002; 3604 3605 /** 3606 * Find views that contain {@link AccessibilityNodeProvider}. Such 3607 * a View is a root of virtual view hierarchy and may contain the searched 3608 * text. If this flag is set Views with providers are automatically 3609 * added and it is a responsibility of the client to call the APIs of 3610 * the provider to determine whether the virtual tree rooted at this View 3611 * contains the text, i.e. getting the list of {@link AccessibilityNodeInfo}s 3612 * representing the virtual views with this text. 3613 * 3614 * @see #findViewsWithText(ArrayList, CharSequence, int) 3615 * 3616 * @hide 3617 */ 3618 public static final int FIND_VIEWS_WITH_ACCESSIBILITY_NODE_PROVIDERS = 0x00000004; 3619 3620 /** 3621 * The undefined cursor position. 3622 * 3623 * @hide 3624 */ 3625 public static final int ACCESSIBILITY_CURSOR_POSITION_UNDEFINED = -1; 3626 3627 /** 3628 * Indicates that the screen has changed state and is now off. 3629 * 3630 * @see #onScreenStateChanged(int) 3631 */ 3632 public static final int SCREEN_STATE_OFF = 0x0; 3633 3634 /** 3635 * Indicates that the screen has changed state and is now on. 3636 * 3637 * @see #onScreenStateChanged(int) 3638 */ 3639 public static final int SCREEN_STATE_ON = 0x1; 3640 3641 /** 3642 * Indicates no axis of view scrolling. 3643 */ 3644 public static final int SCROLL_AXIS_NONE = 0; 3645 3646 /** 3647 * Indicates scrolling along the horizontal axis. 3648 */ 3649 public static final int SCROLL_AXIS_HORIZONTAL = 1 << 0; 3650 3651 /** 3652 * Indicates scrolling along the vertical axis. 3653 */ 3654 public static final int SCROLL_AXIS_VERTICAL = 1 << 1; 3655 3656 /** 3657 * Controls the over-scroll mode for this view. 3658 * See {@link #overScrollBy(int, int, int, int, int, int, int, int, boolean)}, 3659 * {@link #OVER_SCROLL_ALWAYS}, {@link #OVER_SCROLL_IF_CONTENT_SCROLLS}, 3660 * and {@link #OVER_SCROLL_NEVER}. 3661 */ 3662 private int mOverScrollMode; 3663 3664 /** 3665 * The parent this view is attached to. 3666 * {@hide} 3667 * 3668 * @see #getParent() 3669 */ 3670 protected ViewParent mParent; 3671 3672 /** 3673 * {@hide} 3674 */ 3675 AttachInfo mAttachInfo; 3676 3677 /** 3678 * {@hide} 3679 */ 3680 @ViewDebug.ExportedProperty(flagMapping = { 3681 @ViewDebug.FlagToString(mask = PFLAG_FORCE_LAYOUT, equals = PFLAG_FORCE_LAYOUT, 3682 name = "FORCE_LAYOUT"), 3683 @ViewDebug.FlagToString(mask = PFLAG_LAYOUT_REQUIRED, equals = PFLAG_LAYOUT_REQUIRED, 3684 name = "LAYOUT_REQUIRED"), 3685 @ViewDebug.FlagToString(mask = PFLAG_DRAWING_CACHE_VALID, equals = PFLAG_DRAWING_CACHE_VALID, 3686 name = "DRAWING_CACHE_INVALID", outputIf = false), 3687 @ViewDebug.FlagToString(mask = PFLAG_DRAWN, equals = PFLAG_DRAWN, name = "DRAWN", outputIf = true), 3688 @ViewDebug.FlagToString(mask = PFLAG_DRAWN, equals = PFLAG_DRAWN, name = "NOT_DRAWN", outputIf = false), 3689 @ViewDebug.FlagToString(mask = PFLAG_DIRTY_MASK, equals = PFLAG_DIRTY_OPAQUE, name = "DIRTY_OPAQUE"), 3690 @ViewDebug.FlagToString(mask = PFLAG_DIRTY_MASK, equals = PFLAG_DIRTY, name = "DIRTY") 3691 }, formatToHexString = true) 3692 3693 /* @hide */ 3694 public int mPrivateFlags; 3695 int mPrivateFlags2; 3696 int mPrivateFlags3; 3697 3698 /** 3699 * This view's request for the visibility of the status bar. 3700 * @hide 3701 */ 3702 @ViewDebug.ExportedProperty(flagMapping = { 3703 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_LOW_PROFILE, 3704 equals = SYSTEM_UI_FLAG_LOW_PROFILE, 3705 name = "SYSTEM_UI_FLAG_LOW_PROFILE", outputIf = true), 3706 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_HIDE_NAVIGATION, 3707 equals = SYSTEM_UI_FLAG_HIDE_NAVIGATION, 3708 name = "SYSTEM_UI_FLAG_HIDE_NAVIGATION", outputIf = true), 3709 @ViewDebug.FlagToString(mask = PUBLIC_STATUS_BAR_VISIBILITY_MASK, 3710 equals = SYSTEM_UI_FLAG_VISIBLE, 3711 name = "SYSTEM_UI_FLAG_VISIBLE", outputIf = true) 3712 }, formatToHexString = true) 3713 int mSystemUiVisibility; 3714 3715 /** 3716 * Reference count for transient state. 3717 * @see #setHasTransientState(boolean) 3718 */ 3719 int mTransientStateCount = 0; 3720 3721 /** 3722 * Count of how many windows this view has been attached to. 3723 */ 3724 int mWindowAttachCount; 3725 3726 /** 3727 * The layout parameters associated with this view and used by the parent 3728 * {@link android.view.ViewGroup} to determine how this view should be 3729 * laid out. 3730 * {@hide} 3731 */ 3732 protected ViewGroup.LayoutParams mLayoutParams; 3733 3734 /** 3735 * The view flags hold various views states. 3736 * {@hide} 3737 */ 3738 @ViewDebug.ExportedProperty(formatToHexString = true) 3739 int mViewFlags; 3740 3741 static class TransformationInfo { 3742 /** 3743 * The transform matrix for the View. This transform is calculated internally 3744 * based on the translation, rotation, and scale properties. 3745 * 3746 * Do *not* use this variable directly; instead call getMatrix(), which will 3747 * load the value from the View's RenderNode. 3748 */ 3749 private final Matrix mMatrix = new Matrix(); 3750 3751 /** 3752 * The inverse transform matrix for the View. This transform is calculated 3753 * internally based on the translation, rotation, and scale properties. 3754 * 3755 * Do *not* use this variable directly; instead call getInverseMatrix(), 3756 * which will load the value from the View's RenderNode. 3757 */ 3758 private Matrix mInverseMatrix; 3759 3760 /** 3761 * The opacity of the View. This is a value from 0 to 1, where 0 means 3762 * completely transparent and 1 means completely opaque. 3763 */ 3764 @ViewDebug.ExportedProperty 3765 float mAlpha = 1f; 3766 3767 /** 3768 * The opacity of the view as manipulated by the Fade transition. This is a hidden 3769 * property only used by transitions, which is composited with the other alpha 3770 * values to calculate the final visual alpha value. 3771 */ 3772 float mTransitionAlpha = 1f; 3773 } 3774 3775 /** @hide */ 3776 public TransformationInfo mTransformationInfo; 3777 3778 /** 3779 * Current clip bounds. to which all drawing of this view are constrained. 3780 */ 3781 Rect mClipBounds = null; 3782 3783 private boolean mLastIsOpaque; 3784 3785 /** 3786 * The distance in pixels from the left edge of this view's parent 3787 * to the left edge of this view. 3788 * {@hide} 3789 */ 3790 @ViewDebug.ExportedProperty(category = "layout") 3791 protected int mLeft; 3792 /** 3793 * The distance in pixels from the left edge of this view's parent 3794 * to the right edge of this view. 3795 * {@hide} 3796 */ 3797 @ViewDebug.ExportedProperty(category = "layout") 3798 protected int mRight; 3799 /** 3800 * The distance in pixels from the top edge of this view's parent 3801 * to the top edge of this view. 3802 * {@hide} 3803 */ 3804 @ViewDebug.ExportedProperty(category = "layout") 3805 protected int mTop; 3806 /** 3807 * The distance in pixels from the top edge of this view's parent 3808 * to the bottom edge of this view. 3809 * {@hide} 3810 */ 3811 @ViewDebug.ExportedProperty(category = "layout") 3812 protected int mBottom; 3813 3814 /** 3815 * The offset, in pixels, by which the content of this view is scrolled 3816 * horizontally. 3817 * {@hide} 3818 */ 3819 @ViewDebug.ExportedProperty(category = "scrolling") 3820 protected int mScrollX; 3821 /** 3822 * The offset, in pixels, by which the content of this view is scrolled 3823 * vertically. 3824 * {@hide} 3825 */ 3826 @ViewDebug.ExportedProperty(category = "scrolling") 3827 protected int mScrollY; 3828 3829 /** 3830 * The left padding in pixels, that is the distance in pixels between the 3831 * left edge of this view and the left edge of its content. 3832 * {@hide} 3833 */ 3834 @ViewDebug.ExportedProperty(category = "padding") 3835 protected int mPaddingLeft = 0; 3836 /** 3837 * The right padding in pixels, that is the distance in pixels between the 3838 * right edge of this view and the right edge of its content. 3839 * {@hide} 3840 */ 3841 @ViewDebug.ExportedProperty(category = "padding") 3842 protected int mPaddingRight = 0; 3843 /** 3844 * The top padding in pixels, that is the distance in pixels between the 3845 * top edge of this view and the top edge of its content. 3846 * {@hide} 3847 */ 3848 @ViewDebug.ExportedProperty(category = "padding") 3849 protected int mPaddingTop; 3850 /** 3851 * The bottom padding in pixels, that is the distance in pixels between the 3852 * bottom edge of this view and the bottom edge of its content. 3853 * {@hide} 3854 */ 3855 @ViewDebug.ExportedProperty(category = "padding") 3856 protected int mPaddingBottom; 3857 3858 /** 3859 * The layout insets in pixels, that is the distance in pixels between the 3860 * visible edges of this view its bounds. 3861 */ 3862 private Insets mLayoutInsets; 3863 3864 /** 3865 * Briefly describes the view and is primarily used for accessibility support. 3866 */ 3867 private CharSequence mContentDescription; 3868 3869 /** 3870 * Specifies the id of a view for which this view serves as a label for 3871 * accessibility purposes. 3872 */ 3873 private int mLabelForId = View.NO_ID; 3874 3875 /** 3876 * Predicate for matching labeled view id with its label for 3877 * accessibility purposes. 3878 */ 3879 private MatchLabelForPredicate mMatchLabelForPredicate; 3880 3881 /** 3882 * Specifies a view before which this one is visited in accessibility traversal. 3883 */ 3884 private int mAccessibilityTraversalBeforeId = NO_ID; 3885 3886 /** 3887 * Specifies a view after which this one is visited in accessibility traversal. 3888 */ 3889 private int mAccessibilityTraversalAfterId = NO_ID; 3890 3891 /** 3892 * Predicate for matching a view by its id. 3893 */ 3894 private MatchIdPredicate mMatchIdPredicate; 3895 3896 /** 3897 * Cache the paddingRight set by the user to append to the scrollbar's size. 3898 * 3899 * @hide 3900 */ 3901 @ViewDebug.ExportedProperty(category = "padding") 3902 protected int mUserPaddingRight; 3903 3904 /** 3905 * Cache the paddingBottom set by the user to append to the scrollbar's size. 3906 * 3907 * @hide 3908 */ 3909 @ViewDebug.ExportedProperty(category = "padding") 3910 protected int mUserPaddingBottom; 3911 3912 /** 3913 * Cache the paddingLeft set by the user to append to the scrollbar's size. 3914 * 3915 * @hide 3916 */ 3917 @ViewDebug.ExportedProperty(category = "padding") 3918 protected int mUserPaddingLeft; 3919 3920 /** 3921 * Cache the paddingStart set by the user to append to the scrollbar's size. 3922 * 3923 */ 3924 @ViewDebug.ExportedProperty(category = "padding") 3925 int mUserPaddingStart; 3926 3927 /** 3928 * Cache the paddingEnd set by the user to append to the scrollbar's size. 3929 * 3930 */ 3931 @ViewDebug.ExportedProperty(category = "padding") 3932 int mUserPaddingEnd; 3933 3934 /** 3935 * Cache initial left padding. 3936 * 3937 * @hide 3938 */ 3939 int mUserPaddingLeftInitial; 3940 3941 /** 3942 * Cache initial right padding. 3943 * 3944 * @hide 3945 */ 3946 int mUserPaddingRightInitial; 3947 3948 /** 3949 * Default undefined padding 3950 */ 3951 private static final int UNDEFINED_PADDING = Integer.MIN_VALUE; 3952 3953 /** 3954 * Cache if a left padding has been defined 3955 */ 3956 private boolean mLeftPaddingDefined = false; 3957 3958 /** 3959 * Cache if a right padding has been defined 3960 */ 3961 private boolean mRightPaddingDefined = false; 3962 3963 /** 3964 * @hide 3965 */ 3966 int mOldWidthMeasureSpec = Integer.MIN_VALUE; 3967 /** 3968 * @hide 3969 */ 3970 int mOldHeightMeasureSpec = Integer.MIN_VALUE; 3971 3972 private LongSparseLongArray mMeasureCache; 3973 3974 @ViewDebug.ExportedProperty(deepExport = true, prefix = "bg_") 3975 private Drawable mBackground; 3976 private TintInfo mBackgroundTint; 3977 3978 @ViewDebug.ExportedProperty(deepExport = true, prefix = "fg_") 3979 private ForegroundInfo mForegroundInfo; 3980 3981 private Drawable mScrollIndicatorDrawable; 3982 3983 /** 3984 * RenderNode used for backgrounds. 3985 * <p> 3986 * When non-null and valid, this is expected to contain an up-to-date copy 3987 * of the background drawable. It is cleared on temporary detach, and reset 3988 * on cleanup. 3989 */ 3990 private RenderNode mBackgroundRenderNode; 3991 3992 private int mBackgroundResource; 3993 private boolean mBackgroundSizeChanged; 3994 3995 /** The default focus highlight. 3996 * @see #mDefaultFocusHighlightEnabled 3997 * @see Drawable#hasFocusStateSpecified() 3998 */ 3999 private Drawable mDefaultFocusHighlight; 4000 private Drawable mDefaultFocusHighlightCache; 4001 private boolean mDefaultFocusHighlightSizeChanged; 4002 /** 4003 * True if the default focus highlight is needed on the target device. 4004 */ 4005 private static boolean sUseDefaultFocusHighlight; 4006 4007 private String mTransitionName; 4008 4009 static class TintInfo { 4010 ColorStateList mTintList; 4011 PorterDuff.Mode mTintMode; 4012 boolean mHasTintMode; 4013 boolean mHasTintList; 4014 } 4015 4016 private static class ForegroundInfo { 4017 private Drawable mDrawable; 4018 private TintInfo mTintInfo; 4019 private int mGravity = Gravity.FILL; 4020 private boolean mInsidePadding = true; 4021 private boolean mBoundsChanged = true; 4022 private final Rect mSelfBounds = new Rect(); 4023 private final Rect mOverlayBounds = new Rect(); 4024 } 4025 4026 static class ListenerInfo { 4027 /** 4028 * Listener used to dispatch focus change events. 4029 * This field should be made private, so it is hidden from the SDK. 4030 * {@hide} 4031 */ 4032 protected OnFocusChangeListener mOnFocusChangeListener; 4033 4034 /** 4035 * Listeners for layout change events. 4036 */ 4037 private ArrayList<OnLayoutChangeListener> mOnLayoutChangeListeners; 4038 4039 protected OnScrollChangeListener mOnScrollChangeListener; 4040 4041 /** 4042 * Listeners for attach events. 4043 */ 4044 private CopyOnWriteArrayList<OnAttachStateChangeListener> mOnAttachStateChangeListeners; 4045 4046 /** 4047 * Listener used to dispatch click events. 4048 * This field should be made private, so it is hidden from the SDK. 4049 * {@hide} 4050 */ 4051 public OnClickListener mOnClickListener; 4052 4053 /** 4054 * Listener used to dispatch long click events. 4055 * This field should be made private, so it is hidden from the SDK. 4056 * {@hide} 4057 */ 4058 protected OnLongClickListener mOnLongClickListener; 4059 4060 /** 4061 * Listener used to dispatch context click events. This field should be made private, so it 4062 * is hidden from the SDK. 4063 * {@hide} 4064 */ 4065 protected OnContextClickListener mOnContextClickListener; 4066 4067 /** 4068 * Listener used to build the context menu. 4069 * This field should be made private, so it is hidden from the SDK. 4070 * {@hide} 4071 */ 4072 protected OnCreateContextMenuListener mOnCreateContextMenuListener; 4073 4074 private OnKeyListener mOnKeyListener; 4075 4076 private OnTouchListener mOnTouchListener; 4077 4078 private OnHoverListener mOnHoverListener; 4079 4080 private OnGenericMotionListener mOnGenericMotionListener; 4081 4082 private OnDragListener mOnDragListener; 4083 4084 private OnSystemUiVisibilityChangeListener mOnSystemUiVisibilityChangeListener; 4085 4086 OnApplyWindowInsetsListener mOnApplyWindowInsetsListener; 4087 4088 OnCapturedPointerListener mOnCapturedPointerListener; 4089 } 4090 4091 ListenerInfo mListenerInfo; 4092 4093 private static class TooltipInfo { 4094 /** 4095 * Text to be displayed in a tooltip popup. 4096 */ 4097 @Nullable 4098 CharSequence mTooltipText; 4099 4100 /** 4101 * View-relative position of the tooltip anchor point. 4102 */ 4103 int mAnchorX; 4104 int mAnchorY; 4105 4106 /** 4107 * The tooltip popup. 4108 */ 4109 @Nullable 4110 TooltipPopup mTooltipPopup; 4111 4112 /** 4113 * Set to true if the tooltip was shown as a result of a long click. 4114 */ 4115 boolean mTooltipFromLongClick; 4116 4117 /** 4118 * Keep these Runnables so that they can be used to reschedule. 4119 */ 4120 Runnable mShowTooltipRunnable; 4121 Runnable mHideTooltipRunnable; 4122 } 4123 4124 TooltipInfo mTooltipInfo; 4125 4126 // Temporary values used to hold (x,y) coordinates when delegating from the 4127 // two-arg performLongClick() method to the legacy no-arg version. 4128 private float mLongClickX = Float.NaN; 4129 private float mLongClickY = Float.NaN; 4130 4131 /** 4132 * The application environment this view lives in. 4133 * This field should be made private, so it is hidden from the SDK. 4134 * {@hide} 4135 */ 4136 @ViewDebug.ExportedProperty(deepExport = true) 4137 protected Context mContext; 4138 4139 private final Resources mResources; 4140 4141 private ScrollabilityCache mScrollCache; 4142 4143 private int[] mDrawableState = null; 4144 4145 ViewOutlineProvider mOutlineProvider = ViewOutlineProvider.BACKGROUND; 4146 4147 /** 4148 * Animator that automatically runs based on state changes. 4149 */ 4150 private StateListAnimator mStateListAnimator; 4151 4152 /** 4153 * When this view has focus and the next focus is {@link #FOCUS_LEFT}, 4154 * the user may specify which view to go to next. 4155 */ 4156 private int mNextFocusLeftId = View.NO_ID; 4157 4158 /** 4159 * When this view has focus and the next focus is {@link #FOCUS_RIGHT}, 4160 * the user may specify which view to go to next. 4161 */ 4162 private int mNextFocusRightId = View.NO_ID; 4163 4164 /** 4165 * When this view has focus and the next focus is {@link #FOCUS_UP}, 4166 * the user may specify which view to go to next. 4167 */ 4168 private int mNextFocusUpId = View.NO_ID; 4169 4170 /** 4171 * When this view has focus and the next focus is {@link #FOCUS_DOWN}, 4172 * the user may specify which view to go to next. 4173 */ 4174 private int mNextFocusDownId = View.NO_ID; 4175 4176 /** 4177 * When this view has focus and the next focus is {@link #FOCUS_FORWARD}, 4178 * the user may specify which view to go to next. 4179 */ 4180 int mNextFocusForwardId = View.NO_ID; 4181 4182 /** 4183 * User-specified next keyboard navigation cluster in the {@link #FOCUS_FORWARD} direction. 4184 * 4185 * @see #findUserSetNextKeyboardNavigationCluster(View, int) 4186 */ 4187 int mNextClusterForwardId = View.NO_ID; 4188 4189 /** 4190 * Whether this View should use a default focus highlight when it gets focused but doesn't 4191 * have {@link android.R.attr#state_focused} defined in its background. 4192 */ 4193 boolean mDefaultFocusHighlightEnabled = true; 4194 4195 private CheckForLongPress mPendingCheckForLongPress; 4196 private CheckForTap mPendingCheckForTap = null; 4197 private PerformClick mPerformClick; 4198 private SendViewScrolledAccessibilityEvent mSendViewScrolledAccessibilityEvent; 4199 4200 private UnsetPressedState mUnsetPressedState; 4201 4202 /** 4203 * Whether the long press's action has been invoked. The tap's action is invoked on the 4204 * up event while a long press is invoked as soon as the long press duration is reached, so 4205 * a long press could be performed before the tap is checked, in which case the tap's action 4206 * should not be invoked. 4207 */ 4208 private boolean mHasPerformedLongPress; 4209 4210 /** 4211 * Whether a context click button is currently pressed down. This is true when the stylus is 4212 * touching the screen and the primary button has been pressed, or if a mouse's right button is 4213 * pressed. This is false once the button is released or if the stylus has been lifted. 4214 */ 4215 private boolean mInContextButtonPress; 4216 4217 /** 4218 * Whether the next up event should be ignored for the purposes of gesture recognition. This is 4219 * true after a stylus button press has occured, when the next up event should not be recognized 4220 * as a tap. 4221 */ 4222 private boolean mIgnoreNextUpEvent; 4223 4224 /** 4225 * The minimum height of the view. We'll try our best to have the height 4226 * of this view to at least this amount. 4227 */ 4228 @ViewDebug.ExportedProperty(category = "measurement") 4229 private int mMinHeight; 4230 4231 /** 4232 * The minimum width of the view. We'll try our best to have the width 4233 * of this view to at least this amount. 4234 */ 4235 @ViewDebug.ExportedProperty(category = "measurement") 4236 private int mMinWidth; 4237 4238 /** 4239 * The delegate to handle touch events that are physically in this view 4240 * but should be handled by another view. 4241 */ 4242 private TouchDelegate mTouchDelegate = null; 4243 4244 /** 4245 * Solid color to use as a background when creating the drawing cache. Enables 4246 * the cache to use 16 bit bitmaps instead of 32 bit. 4247 */ 4248 private int mDrawingCacheBackgroundColor = 0; 4249 4250 /** 4251 * Special tree observer used when mAttachInfo is null. 4252 */ 4253 private ViewTreeObserver mFloatingTreeObserver; 4254 4255 /** 4256 * Cache the touch slop from the context that created the view. 4257 */ 4258 private int mTouchSlop; 4259 4260 /** 4261 * Object that handles automatic animation of view properties. 4262 */ 4263 private ViewPropertyAnimator mAnimator = null; 4264 4265 /** 4266 * List of registered FrameMetricsObservers. 4267 */ 4268 private ArrayList<FrameMetricsObserver> mFrameMetricsObservers; 4269 4270 /** 4271 * Flag indicating that a drag can cross window boundaries. When 4272 * {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, int)} is called 4273 * with this flag set, all visible applications with targetSdkVersion >= 4274 * {@link android.os.Build.VERSION_CODES#N API 24} will be able to participate 4275 * in the drag operation and receive the dragged content. 4276 * 4277 * <p>If this is the only flag set, then the drag recipient will only have access to text data 4278 * and intents contained in the {@link ClipData} object. Access to URIs contained in the 4279 * {@link ClipData} is determined by other DRAG_FLAG_GLOBAL_* flags</p> 4280 */ 4281 public static final int DRAG_FLAG_GLOBAL = 1 << 8; // 256 4282 4283 /** 4284 * When this flag is used with {@link #DRAG_FLAG_GLOBAL}, the drag recipient will be able to 4285 * request read access to the content URI(s) contained in the {@link ClipData} object. 4286 * @see android.content.Intent#FLAG_GRANT_READ_URI_PERMISSION 4287 */ 4288 public static final int DRAG_FLAG_GLOBAL_URI_READ = Intent.FLAG_GRANT_READ_URI_PERMISSION; 4289 4290 /** 4291 * When this flag is used with {@link #DRAG_FLAG_GLOBAL}, the drag recipient will be able to 4292 * request write access to the content URI(s) contained in the {@link ClipData} object. 4293 * @see android.content.Intent#FLAG_GRANT_WRITE_URI_PERMISSION 4294 */ 4295 public static final int DRAG_FLAG_GLOBAL_URI_WRITE = Intent.FLAG_GRANT_WRITE_URI_PERMISSION; 4296 4297 /** 4298 * When this flag is used with {@link #DRAG_FLAG_GLOBAL_URI_READ} and/or {@link 4299 * #DRAG_FLAG_GLOBAL_URI_WRITE}, the URI permission grant can be persisted across device 4300 * reboots until explicitly revoked with 4301 * {@link android.content.Context#revokeUriPermission(Uri, int)} Context.revokeUriPermission}. 4302 * @see android.content.Intent#FLAG_GRANT_PERSISTABLE_URI_PERMISSION 4303 */ 4304 public static final int DRAG_FLAG_GLOBAL_PERSISTABLE_URI_PERMISSION = 4305 Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION; 4306 4307 /** 4308 * When this flag is used with {@link #DRAG_FLAG_GLOBAL_URI_READ} and/or {@link 4309 * #DRAG_FLAG_GLOBAL_URI_WRITE}, the URI permission grant applies to any URI that is a prefix 4310 * match against the original granted URI. 4311 * @see android.content.Intent#FLAG_GRANT_PREFIX_URI_PERMISSION 4312 */ 4313 public static final int DRAG_FLAG_GLOBAL_PREFIX_URI_PERMISSION = 4314 Intent.FLAG_GRANT_PREFIX_URI_PERMISSION; 4315 4316 /** 4317 * Flag indicating that the drag shadow will be opaque. When 4318 * {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, int)} is called 4319 * with this flag set, the drag shadow will be opaque, otherwise, it will be semitransparent. 4320 */ 4321 public static final int DRAG_FLAG_OPAQUE = 1 << 9; 4322 4323 /** 4324 * Vertical scroll factor cached by {@link #getVerticalScrollFactor}. 4325 */ 4326 private float mVerticalScrollFactor; 4327 4328 /** 4329 * Position of the vertical scroll bar. 4330 */ 4331 private int mVerticalScrollbarPosition; 4332 4333 /** 4334 * Position the scroll bar at the default position as determined by the system. 4335 */ 4336 public static final int SCROLLBAR_POSITION_DEFAULT = 0; 4337 4338 /** 4339 * Position the scroll bar along the left edge. 4340 */ 4341 public static final int SCROLLBAR_POSITION_LEFT = 1; 4342 4343 /** 4344 * Position the scroll bar along the right edge. 4345 */ 4346 public static final int SCROLLBAR_POSITION_RIGHT = 2; 4347 4348 /** 4349 * Indicates that the view does not have a layer. 4350 * 4351 * @see #getLayerType() 4352 * @see #setLayerType(int, android.graphics.Paint) 4353 * @see #LAYER_TYPE_SOFTWARE 4354 * @see #LAYER_TYPE_HARDWARE 4355 */ 4356 public static final int LAYER_TYPE_NONE = 0; 4357 4358 /** 4359 * <p>Indicates that the view has a software layer. A software layer is backed 4360 * by a bitmap and causes the view to be rendered using Android's software 4361 * rendering pipeline, even if hardware acceleration is enabled.</p> 4362 * 4363 * <p>Software layers have various usages:</p> 4364 * <p>When the application is not using hardware acceleration, a software layer 4365 * is useful to apply a specific color filter and/or blending mode and/or 4366 * translucency to a view and all its children.</p> 4367 * <p>When the application is using hardware acceleration, a software layer 4368 * is useful to render drawing primitives not supported by the hardware 4369 * accelerated pipeline. It can also be used to cache a complex view tree 4370 * into a texture and reduce the complexity of drawing operations. For instance, 4371 * when animating a complex view tree with a translation, a software layer can 4372 * be used to render the view tree only once.</p> 4373 * <p>Software layers should be avoided when the affected view tree updates 4374 * often. Every update will require to re-render the software layer, which can 4375 * potentially be slow (particularly when hardware acceleration is turned on 4376 * since the layer will have to be uploaded into a hardware texture after every 4377 * update.)</p> 4378 * 4379 * @see #getLayerType() 4380 * @see #setLayerType(int, android.graphics.Paint) 4381 * @see #LAYER_TYPE_NONE 4382 * @see #LAYER_TYPE_HARDWARE 4383 */ 4384 public static final int LAYER_TYPE_SOFTWARE = 1; 4385 4386 /** 4387 * <p>Indicates that the view has a hardware layer. A hardware layer is backed 4388 * by a hardware specific texture (generally Frame Buffer Objects or FBO on 4389 * OpenGL hardware) and causes the view to be rendered using Android's hardware 4390 * rendering pipeline, but only if hardware acceleration is turned on for the 4391 * view hierarchy. When hardware acceleration is turned off, hardware layers 4392 * behave exactly as {@link #LAYER_TYPE_SOFTWARE software layers}.</p> 4393 * 4394 * <p>A hardware layer is useful to apply a specific color filter and/or 4395 * blending mode and/or translucency to a view and all its children.</p> 4396 * <p>A hardware layer can be used to cache a complex view tree into a 4397 * texture and reduce the complexity of drawing operations. For instance, 4398 * when animating a complex view tree with a translation, a hardware layer can 4399 * be used to render the view tree only once.</p> 4400 * <p>A hardware layer can also be used to increase the rendering quality when 4401 * rotation transformations are applied on a view. It can also be used to 4402 * prevent potential clipping issues when applying 3D transforms on a view.</p> 4403 * 4404 * @see #getLayerType() 4405 * @see #setLayerType(int, android.graphics.Paint) 4406 * @see #LAYER_TYPE_NONE 4407 * @see #LAYER_TYPE_SOFTWARE 4408 */ 4409 public static final int LAYER_TYPE_HARDWARE = 2; 4410 4411 @ViewDebug.ExportedProperty(category = "drawing", mapping = { 4412 @ViewDebug.IntToString(from = LAYER_TYPE_NONE, to = "NONE"), 4413 @ViewDebug.IntToString(from = LAYER_TYPE_SOFTWARE, to = "SOFTWARE"), 4414 @ViewDebug.IntToString(from = LAYER_TYPE_HARDWARE, to = "HARDWARE") 4415 }) 4416 int mLayerType = LAYER_TYPE_NONE; 4417 Paint mLayerPaint; 4418 4419 /** 4420 * Set to true when drawing cache is enabled and cannot be created. 4421 * 4422 * @hide 4423 */ 4424 public boolean mCachingFailed; 4425 private Bitmap mDrawingCache; 4426 private Bitmap mUnscaledDrawingCache; 4427 4428 /** 4429 * RenderNode holding View properties, potentially holding a DisplayList of View content. 4430 * <p> 4431 * When non-null and valid, this is expected to contain an up-to-date copy 4432 * of the View content. Its DisplayList content is cleared on temporary detach and reset on 4433 * cleanup. 4434 */ 4435 final RenderNode mRenderNode; 4436 4437 /** 4438 * Set to true when the view is sending hover accessibility events because it 4439 * is the innermost hovered view. 4440 */ 4441 private boolean mSendingHoverAccessibilityEvents; 4442 4443 /** 4444 * Delegate for injecting accessibility functionality. 4445 */ 4446 AccessibilityDelegate mAccessibilityDelegate; 4447 4448 /** 4449 * The view's overlay layer. Developers get a reference to the overlay via getOverlay() 4450 * and add/remove objects to/from the overlay directly through the Overlay methods. 4451 */ 4452 ViewOverlay mOverlay; 4453 4454 /** 4455 * The currently active parent view for receiving delegated nested scrolling events. 4456 * This is set by {@link #startNestedScroll(int)} during a touch interaction and cleared 4457 * by {@link #stopNestedScroll()} at the same point where we clear 4458 * requestDisallowInterceptTouchEvent. 4459 */ 4460 private ViewParent mNestedScrollingParent; 4461 4462 /** 4463 * Consistency verifier for debugging purposes. 4464 * @hide 4465 */ 4466 protected final InputEventConsistencyVerifier mInputEventConsistencyVerifier = 4467 InputEventConsistencyVerifier.isInstrumentationEnabled() ? 4468 new InputEventConsistencyVerifier(this, 0) : null; 4469 4470 private static final AtomicInteger sNextGeneratedId = new AtomicInteger(1); 4471 4472 private int[] mTempNestedScrollConsumed; 4473 4474 /** 4475 * An overlay is going to draw this View instead of being drawn as part of this 4476 * View's parent. mGhostView is the View in the Overlay that must be invalidated 4477 * when this view is invalidated. 4478 */ 4479 GhostView mGhostView; 4480 4481 /** 4482 * Holds pairs of adjacent attribute data: attribute name followed by its value. 4483 * @hide 4484 */ 4485 @ViewDebug.ExportedProperty(category = "attributes", hasAdjacentMapping = true) 4486 public String[] mAttributes; 4487 4488 /** 4489 * Maps a Resource id to its name. 4490 */ 4491 private static SparseArray<String> mAttributeMap; 4492 4493 /** 4494 * Queue of pending runnables. Used to postpone calls to post() until this 4495 * view is attached and has a handler. 4496 */ 4497 private HandlerActionQueue mRunQueue; 4498 4499 /** 4500 * The pointer icon when the mouse hovers on this view. The default is null. 4501 */ 4502 private PointerIcon mPointerIcon; 4503 4504 /** 4505 * @hide 4506 */ 4507 String mStartActivityRequestWho; 4508 4509 @Nullable 4510 private RoundScrollbarRenderer mRoundScrollbarRenderer; 4511 4512 /** Used to delay visibility updates sent to the autofill manager */ 4513 private Handler mVisibilityChangeForAutofillHandler; 4514 4515 /** 4516 * Simple constructor to use when creating a view from code. 4517 * 4518 * @param context The Context the view is running in, through which it can 4519 * access the current theme, resources, etc. 4520 */ 4521 public View(Context context) { 4522 mContext = context; 4523 mResources = context != null ? context.getResources() : null; 4524 mViewFlags = SOUND_EFFECTS_ENABLED | HAPTIC_FEEDBACK_ENABLED | FOCUSABLE_AUTO; 4525 // Set some flags defaults 4526 mPrivateFlags2 = 4527 (LAYOUT_DIRECTION_DEFAULT << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT) | 4528 (TEXT_DIRECTION_DEFAULT << PFLAG2_TEXT_DIRECTION_MASK_SHIFT) | 4529 (PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT) | 4530 (TEXT_ALIGNMENT_DEFAULT << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT) | 4531 (PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT) | 4532 (IMPORTANT_FOR_ACCESSIBILITY_DEFAULT << PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT); 4533 mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); 4534 setOverScrollMode(OVER_SCROLL_IF_CONTENT_SCROLLS); 4535 mUserPaddingStart = UNDEFINED_PADDING; 4536 mUserPaddingEnd = UNDEFINED_PADDING; 4537 mRenderNode = RenderNode.create(getClass().getName(), this); 4538 4539 if (!sCompatibilityDone && context != null) { 4540 final int targetSdkVersion = context.getApplicationInfo().targetSdkVersion; 4541 4542 // Older apps may need this compatibility hack for measurement. 4543 sUseBrokenMakeMeasureSpec = targetSdkVersion <= Build.VERSION_CODES.JELLY_BEAN_MR1; 4544 4545 // Older apps expect onMeasure() to always be called on a layout pass, regardless 4546 // of whether a layout was requested on that View. 4547 sIgnoreMeasureCache = targetSdkVersion < Build.VERSION_CODES.KITKAT; 4548 4549 Canvas.sCompatibilityRestore = targetSdkVersion < Build.VERSION_CODES.M; 4550 Canvas.sCompatibilitySetBitmap = targetSdkVersion < Build.VERSION_CODES.O; 4551 4552 // In M and newer, our widgets can pass a "hint" value in the size 4553 // for UNSPECIFIED MeasureSpecs. This lets child views of scrolling containers 4554 // know what the expected parent size is going to be, so e.g. list items can size 4555 // themselves at 1/3 the size of their container. It breaks older apps though, 4556 // specifically apps that use some popular open source libraries. 4557 sUseZeroUnspecifiedMeasureSpec = targetSdkVersion < Build.VERSION_CODES.M; 4558 4559 // Old versions of the platform would give different results from 4560 // LinearLayout measurement passes using EXACTLY and non-EXACTLY 4561 // modes, so we always need to run an additional EXACTLY pass. 4562 sAlwaysRemeasureExactly = targetSdkVersion <= Build.VERSION_CODES.M; 4563 4564 // Prior to N, layout params could change without requiring a 4565 // subsequent call to setLayoutParams() and they would usually 4566 // work. Partial layout breaks this assumption. 4567 sLayoutParamsAlwaysChanged = targetSdkVersion <= Build.VERSION_CODES.M; 4568 4569 // Prior to N, TextureView would silently ignore calls to setBackground/setForeground. 4570 // On N+, we throw, but that breaks compatibility with apps that use these methods. 4571 sTextureViewIgnoresDrawableSetters = targetSdkVersion <= Build.VERSION_CODES.M; 4572 4573 // Prior to N, we would drop margins in LayoutParam conversions. The fix triggers bugs 4574 // in apps so we target check it to avoid breaking existing apps. 4575 sPreserveMarginParamsInLayoutParamConversion = 4576 targetSdkVersion >= Build.VERSION_CODES.N; 4577 4578 sCascadedDragDrop = targetSdkVersion < Build.VERSION_CODES.N; 4579 4580 sHasFocusableExcludeAutoFocusable = targetSdkVersion < Build.VERSION_CODES.O; 4581 4582 sAutoFocusableOffUIThreadWontNotifyParents = targetSdkVersion < Build.VERSION_CODES.O; 4583 4584 sUseDefaultFocusHighlight = context.getResources().getBoolean( 4585 com.android.internal.R.bool.config_useDefaultFocusHighlight); 4586 4587 sCompatibilityDone = true; 4588 } 4589 } 4590 4591 /** 4592 * Constructor that is called when inflating a view from XML. This is called 4593 * when a view is being constructed from an XML file, supplying attributes 4594 * that were specified in the XML file. This version uses a default style of 4595 * 0, so the only attribute values applied are those in the Context's Theme 4596 * and the given AttributeSet. 4597 * 4598 * <p> 4599 * The method onFinishInflate() will be called after all children have been 4600 * added. 4601 * 4602 * @param context The Context the view is running in, through which it can 4603 * access the current theme, resources, etc. 4604 * @param attrs The attributes of the XML tag that is inflating the view. 4605 * @see #View(Context, AttributeSet, int) 4606 */ 4607 public View(Context context, @Nullable AttributeSet attrs) { 4608 this(context, attrs, 0); 4609 } 4610 4611 /** 4612 * Perform inflation from XML and apply a class-specific base style from a 4613 * theme attribute. This constructor of View allows subclasses to use their 4614 * own base style when they are inflating. For example, a Button class's 4615 * constructor would call this version of the super class constructor and 4616 * supply <code>R.attr.buttonStyle</code> for <var>defStyleAttr</var>; this 4617 * allows the theme's button style to modify all of the base view attributes 4618 * (in particular its background) as well as the Button class's attributes. 4619 * 4620 * @param context The Context the view is running in, through which it can 4621 * access the current theme, resources, etc. 4622 * @param attrs The attributes of the XML tag that is inflating the view. 4623 * @param defStyleAttr An attribute in the current theme that contains a 4624 * reference to a style resource that supplies default values for 4625 * the view. Can be 0 to not look for defaults. 4626 * @see #View(Context, AttributeSet) 4627 */ 4628 public View(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { 4629 this(context, attrs, defStyleAttr, 0); 4630 } 4631 4632 /** 4633 * Perform inflation from XML and apply a class-specific base style from a 4634 * theme attribute or style resource. This constructor of View allows 4635 * subclasses to use their own base style when they are inflating. 4636 * <p> 4637 * When determining the final value of a particular attribute, there are 4638 * four inputs that come into play: 4639 * <ol> 4640 * <li>Any attribute values in the given AttributeSet. 4641 * <li>The style resource specified in the AttributeSet (named "style"). 4642 * <li>The default style specified by <var>defStyleAttr</var>. 4643 * <li>The default style specified by <var>defStyleRes</var>. 4644 * <li>The base values in this theme. 4645 * </ol> 4646 * <p> 4647 * Each of these inputs is considered in-order, with the first listed taking 4648 * precedence over the following ones. In other words, if in the 4649 * AttributeSet you have supplied <code><Button * textColor="#ff000000"></code> 4650 * , then the button's text will <em>always</em> be black, regardless of 4651 * what is specified in any of the styles. 4652 * 4653 * @param context The Context the view is running in, through which it can 4654 * access the current theme, resources, etc. 4655 * @param attrs The attributes of the XML tag that is inflating the view. 4656 * @param defStyleAttr An attribute in the current theme that contains a 4657 * reference to a style resource that supplies default values for 4658 * the view. Can be 0 to not look for defaults. 4659 * @param defStyleRes A resource identifier of a style resource that 4660 * supplies default values for the view, used only if 4661 * defStyleAttr is 0 or can not be found in the theme. Can be 0 4662 * to not look for defaults. 4663 * @see #View(Context, AttributeSet, int) 4664 */ 4665 public View(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) { 4666 this(context); 4667 4668 final TypedArray a = context.obtainStyledAttributes( 4669 attrs, com.android.internal.R.styleable.View, defStyleAttr, defStyleRes); 4670 4671 if (mDebugViewAttributes) { 4672 saveAttributeData(attrs, a); 4673 } 4674 4675 Drawable background = null; 4676 4677 int leftPadding = -1; 4678 int topPadding = -1; 4679 int rightPadding = -1; 4680 int bottomPadding = -1; 4681 int startPadding = UNDEFINED_PADDING; 4682 int endPadding = UNDEFINED_PADDING; 4683 4684 int padding = -1; 4685 int paddingHorizontal = -1; 4686 int paddingVertical = -1; 4687 4688 int viewFlagValues = 0; 4689 int viewFlagMasks = 0; 4690 4691 boolean setScrollContainer = false; 4692 4693 int x = 0; 4694 int y = 0; 4695 4696 float tx = 0; 4697 float ty = 0; 4698 float tz = 0; 4699 float elevation = 0; 4700 float rotation = 0; 4701 float rotationX = 0; 4702 float rotationY = 0; 4703 float sx = 1f; 4704 float sy = 1f; 4705 boolean transformSet = false; 4706 4707 int scrollbarStyle = SCROLLBARS_INSIDE_OVERLAY; 4708 int overScrollMode = mOverScrollMode; 4709 boolean initializeScrollbars = false; 4710 boolean initializeScrollIndicators = false; 4711 4712 boolean startPaddingDefined = false; 4713 boolean endPaddingDefined = false; 4714 boolean leftPaddingDefined = false; 4715 boolean rightPaddingDefined = false; 4716 4717 final int targetSdkVersion = context.getApplicationInfo().targetSdkVersion; 4718 4719 // Set default values. 4720 viewFlagValues |= FOCUSABLE_AUTO; 4721 viewFlagMasks |= FOCUSABLE_AUTO; 4722 4723 final int N = a.getIndexCount(); 4724 for (int i = 0; i < N; i++) { 4725 int attr = a.getIndex(i); 4726 switch (attr) { 4727 case com.android.internal.R.styleable.View_background: 4728 background = a.getDrawable(attr); 4729 break; 4730 case com.android.internal.R.styleable.View_padding: 4731 padding = a.getDimensionPixelSize(attr, -1); 4732 mUserPaddingLeftInitial = padding; 4733 mUserPaddingRightInitial = padding; 4734 leftPaddingDefined = true; 4735 rightPaddingDefined = true; 4736 break; 4737 case com.android.internal.R.styleable.View_paddingHorizontal: 4738 paddingHorizontal = a.getDimensionPixelSize(attr, -1); 4739 mUserPaddingLeftInitial = paddingHorizontal; 4740 mUserPaddingRightInitial = paddingHorizontal; 4741 leftPaddingDefined = true; 4742 rightPaddingDefined = true; 4743 break; 4744 case com.android.internal.R.styleable.View_paddingVertical: 4745 paddingVertical = a.getDimensionPixelSize(attr, -1); 4746 break; 4747 case com.android.internal.R.styleable.View_paddingLeft: 4748 leftPadding = a.getDimensionPixelSize(attr, -1); 4749 mUserPaddingLeftInitial = leftPadding; 4750 leftPaddingDefined = true; 4751 break; 4752 case com.android.internal.R.styleable.View_paddingTop: 4753 topPadding = a.getDimensionPixelSize(attr, -1); 4754 break; 4755 case com.android.internal.R.styleable.View_paddingRight: 4756 rightPadding = a.getDimensionPixelSize(attr, -1); 4757 mUserPaddingRightInitial = rightPadding; 4758 rightPaddingDefined = true; 4759 break; 4760 case com.android.internal.R.styleable.View_paddingBottom: 4761 bottomPadding = a.getDimensionPixelSize(attr, -1); 4762 break; 4763 case com.android.internal.R.styleable.View_paddingStart: 4764 startPadding = a.getDimensionPixelSize(attr, UNDEFINED_PADDING); 4765 startPaddingDefined = (startPadding != UNDEFINED_PADDING); 4766 break; 4767 case com.android.internal.R.styleable.View_paddingEnd: 4768 endPadding = a.getDimensionPixelSize(attr, UNDEFINED_PADDING); 4769 endPaddingDefined = (endPadding != UNDEFINED_PADDING); 4770 break; 4771 case com.android.internal.R.styleable.View_scrollX: 4772 x = a.getDimensionPixelOffset(attr, 0); 4773 break; 4774 case com.android.internal.R.styleable.View_scrollY: 4775 y = a.getDimensionPixelOffset(attr, 0); 4776 break; 4777 case com.android.internal.R.styleable.View_alpha: 4778 setAlpha(a.getFloat(attr, 1f)); 4779 break; 4780 case com.android.internal.R.styleable.View_transformPivotX: 4781 setPivotX(a.getDimension(attr, 0)); 4782 break; 4783 case com.android.internal.R.styleable.View_transformPivotY: 4784 setPivotY(a.getDimension(attr, 0)); 4785 break; 4786 case com.android.internal.R.styleable.View_translationX: 4787 tx = a.getDimension(attr, 0); 4788 transformSet = true; 4789 break; 4790 case com.android.internal.R.styleable.View_translationY: 4791 ty = a.getDimension(attr, 0); 4792 transformSet = true; 4793 break; 4794 case com.android.internal.R.styleable.View_translationZ: 4795 tz = a.getDimension(attr, 0); 4796 transformSet = true; 4797 break; 4798 case com.android.internal.R.styleable.View_elevation: 4799 elevation = a.getDimension(attr, 0); 4800 transformSet = true; 4801 break; 4802 case com.android.internal.R.styleable.View_rotation: 4803 rotation = a.getFloat(attr, 0); 4804 transformSet = true; 4805 break; 4806 case com.android.internal.R.styleable.View_rotationX: 4807 rotationX = a.getFloat(attr, 0); 4808 transformSet = true; 4809 break; 4810 case com.android.internal.R.styleable.View_rotationY: 4811 rotationY = a.getFloat(attr, 0); 4812 transformSet = true; 4813 break; 4814 case com.android.internal.R.styleable.View_scaleX: 4815 sx = a.getFloat(attr, 1f); 4816 transformSet = true; 4817 break; 4818 case com.android.internal.R.styleable.View_scaleY: 4819 sy = a.getFloat(attr, 1f); 4820 transformSet = true; 4821 break; 4822 case com.android.internal.R.styleable.View_id: 4823 mID = a.getResourceId(attr, NO_ID); 4824 break; 4825 case com.android.internal.R.styleable.View_tag: 4826 mTag = a.getText(attr); 4827 break; 4828 case com.android.internal.R.styleable.View_fitsSystemWindows: 4829 if (a.getBoolean(attr, false)) { 4830 viewFlagValues |= FITS_SYSTEM_WINDOWS; 4831 viewFlagMasks |= FITS_SYSTEM_WINDOWS; 4832 } 4833 break; 4834 case com.android.internal.R.styleable.View_focusable: 4835 viewFlagValues = (viewFlagValues & ~FOCUSABLE_MASK) | getFocusableAttribute(a); 4836 if ((viewFlagValues & FOCUSABLE_AUTO) == 0) { 4837 viewFlagMasks |= FOCUSABLE_MASK; 4838 } 4839 break; 4840 case com.android.internal.R.styleable.View_focusableInTouchMode: 4841 if (a.getBoolean(attr, false)) { 4842 // unset auto focus since focusableInTouchMode implies explicit focusable 4843 viewFlagValues &= ~FOCUSABLE_AUTO; 4844 viewFlagValues |= FOCUSABLE_IN_TOUCH_MODE | FOCUSABLE; 4845 viewFlagMasks |= FOCUSABLE_IN_TOUCH_MODE | FOCUSABLE_MASK; 4846 } 4847 break; 4848 case com.android.internal.R.styleable.View_clickable: 4849 if (a.getBoolean(attr, false)) { 4850 viewFlagValues |= CLICKABLE; 4851 viewFlagMasks |= CLICKABLE; 4852 } 4853 break; 4854 case com.android.internal.R.styleable.View_longClickable: 4855 if (a.getBoolean(attr, false)) { 4856 viewFlagValues |= LONG_CLICKABLE; 4857 viewFlagMasks |= LONG_CLICKABLE; 4858 } 4859 break; 4860 case com.android.internal.R.styleable.View_contextClickable: 4861 if (a.getBoolean(attr, false)) { 4862 viewFlagValues |= CONTEXT_CLICKABLE; 4863 viewFlagMasks |= CONTEXT_CLICKABLE; 4864 } 4865 break; 4866 case com.android.internal.R.styleable.View_saveEnabled: 4867 if (!a.getBoolean(attr, true)) { 4868 viewFlagValues |= SAVE_DISABLED; 4869 viewFlagMasks |= SAVE_DISABLED_MASK; 4870 } 4871 break; 4872 case com.android.internal.R.styleable.View_duplicateParentState: 4873 if (a.getBoolean(attr, false)) { 4874 viewFlagValues |= DUPLICATE_PARENT_STATE; 4875 viewFlagMasks |= DUPLICATE_PARENT_STATE; 4876 } 4877 break; 4878 case com.android.internal.R.styleable.View_visibility: 4879 final int visibility = a.getInt(attr, 0); 4880 if (visibility != 0) { 4881 viewFlagValues |= VISIBILITY_FLAGS[visibility]; 4882 viewFlagMasks |= VISIBILITY_MASK; 4883 } 4884 break; 4885 case com.android.internal.R.styleable.View_layoutDirection: 4886 // Clear any layout direction flags (included resolved bits) already set 4887 mPrivateFlags2 &= 4888 ~(PFLAG2_LAYOUT_DIRECTION_MASK | PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK); 4889 // Set the layout direction flags depending on the value of the attribute 4890 final int layoutDirection = a.getInt(attr, -1); 4891 final int value = (layoutDirection != -1) ? 4892 LAYOUT_DIRECTION_FLAGS[layoutDirection] : LAYOUT_DIRECTION_DEFAULT; 4893 mPrivateFlags2 |= (value << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT); 4894 break; 4895 case com.android.internal.R.styleable.View_drawingCacheQuality: 4896 final int cacheQuality = a.getInt(attr, 0); 4897 if (cacheQuality != 0) { 4898 viewFlagValues |= DRAWING_CACHE_QUALITY_FLAGS[cacheQuality]; 4899 viewFlagMasks |= DRAWING_CACHE_QUALITY_MASK; 4900 } 4901 break; 4902 case com.android.internal.R.styleable.View_contentDescription: 4903 setContentDescription(a.getString(attr)); 4904 break; 4905 case com.android.internal.R.styleable.View_accessibilityTraversalBefore: 4906 setAccessibilityTraversalBefore(a.getResourceId(attr, NO_ID)); 4907 break; 4908 case com.android.internal.R.styleable.View_accessibilityTraversalAfter: 4909 setAccessibilityTraversalAfter(a.getResourceId(attr, NO_ID)); 4910 break; 4911 case com.android.internal.R.styleable.View_labelFor: 4912 setLabelFor(a.getResourceId(attr, NO_ID)); 4913 break; 4914 case com.android.internal.R.styleable.View_soundEffectsEnabled: 4915 if (!a.getBoolean(attr, true)) { 4916 viewFlagValues &= ~SOUND_EFFECTS_ENABLED; 4917 viewFlagMasks |= SOUND_EFFECTS_ENABLED; 4918 } 4919 break; 4920 case com.android.internal.R.styleable.View_hapticFeedbackEnabled: 4921 if (!a.getBoolean(attr, true)) { 4922 viewFlagValues &= ~HAPTIC_FEEDBACK_ENABLED; 4923 viewFlagMasks |= HAPTIC_FEEDBACK_ENABLED; 4924 } 4925 break; 4926 case R.styleable.View_scrollbars: 4927 final int scrollbars = a.getInt(attr, SCROLLBARS_NONE); 4928 if (scrollbars != SCROLLBARS_NONE) { 4929 viewFlagValues |= scrollbars; 4930 viewFlagMasks |= SCROLLBARS_MASK; 4931 initializeScrollbars = true; 4932 } 4933 break; 4934 //noinspection deprecation 4935 case R.styleable.View_fadingEdge: 4936 if (targetSdkVersion >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { 4937 // Ignore the attribute starting with ICS 4938 break; 4939 } 4940 // With builds < ICS, fall through and apply fading edges 4941 case R.styleable.View_requiresFadingEdge: 4942 final int fadingEdge = a.getInt(attr, FADING_EDGE_NONE); 4943 if (fadingEdge != FADING_EDGE_NONE) { 4944 viewFlagValues |= fadingEdge; 4945 viewFlagMasks |= FADING_EDGE_MASK; 4946 initializeFadingEdgeInternal(a); 4947 } 4948 break; 4949 case R.styleable.View_scrollbarStyle: 4950 scrollbarStyle = a.getInt(attr, SCROLLBARS_INSIDE_OVERLAY); 4951 if (scrollbarStyle != SCROLLBARS_INSIDE_OVERLAY) { 4952 viewFlagValues |= scrollbarStyle & SCROLLBARS_STYLE_MASK; 4953 viewFlagMasks |= SCROLLBARS_STYLE_MASK; 4954 } 4955 break; 4956 case R.styleable.View_isScrollContainer: 4957 setScrollContainer = true; 4958 if (a.getBoolean(attr, false)) { 4959 setScrollContainer(true); 4960 } 4961 break; 4962 case com.android.internal.R.styleable.View_keepScreenOn: 4963 if (a.getBoolean(attr, false)) { 4964 viewFlagValues |= KEEP_SCREEN_ON; 4965 viewFlagMasks |= KEEP_SCREEN_ON; 4966 } 4967 break; 4968 case R.styleable.View_filterTouchesWhenObscured: 4969 if (a.getBoolean(attr, false)) { 4970 viewFlagValues |= FILTER_TOUCHES_WHEN_OBSCURED; 4971 viewFlagMasks |= FILTER_TOUCHES_WHEN_OBSCURED; 4972 } 4973 break; 4974 case R.styleable.View_nextFocusLeft: 4975 mNextFocusLeftId = a.getResourceId(attr, View.NO_ID); 4976 break; 4977 case R.styleable.View_nextFocusRight: 4978 mNextFocusRightId = a.getResourceId(attr, View.NO_ID); 4979 break; 4980 case R.styleable.View_nextFocusUp: 4981 mNextFocusUpId = a.getResourceId(attr, View.NO_ID); 4982 break; 4983 case R.styleable.View_nextFocusDown: 4984 mNextFocusDownId = a.getResourceId(attr, View.NO_ID); 4985 break; 4986 case R.styleable.View_nextFocusForward: 4987 mNextFocusForwardId = a.getResourceId(attr, View.NO_ID); 4988 break; 4989 case R.styleable.View_nextClusterForward: 4990 mNextClusterForwardId = a.getResourceId(attr, View.NO_ID); 4991 break; 4992 case R.styleable.View_minWidth: 4993 mMinWidth = a.getDimensionPixelSize(attr, 0); 4994 break; 4995 case R.styleable.View_minHeight: 4996 mMinHeight = a.getDimensionPixelSize(attr, 0); 4997 break; 4998 case R.styleable.View_onClick: 4999 if (context.isRestricted()) { 5000 throw new IllegalStateException("The android:onClick attribute cannot " 5001 + "be used within a restricted context"); 5002 } 5003 5004 final String handlerName = a.getString(attr); 5005 if (handlerName != null) { 5006 setOnClickListener(new DeclaredOnClickListener(this, handlerName)); 5007 } 5008 break; 5009 case R.styleable.View_overScrollMode: 5010 overScrollMode = a.getInt(attr, OVER_SCROLL_IF_CONTENT_SCROLLS); 5011 break; 5012 case R.styleable.View_verticalScrollbarPosition: 5013 mVerticalScrollbarPosition = a.getInt(attr, SCROLLBAR_POSITION_DEFAULT); 5014 break; 5015 case R.styleable.View_layerType: 5016 setLayerType(a.getInt(attr, LAYER_TYPE_NONE), null); 5017 break; 5018 case R.styleable.View_textDirection: 5019 // Clear any text direction flag already set 5020 mPrivateFlags2 &= ~PFLAG2_TEXT_DIRECTION_MASK; 5021 // Set the text direction flags depending on the value of the attribute 5022 final int textDirection = a.getInt(attr, -1); 5023 if (textDirection != -1) { 5024 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_FLAGS[textDirection]; 5025 } 5026 break; 5027 case R.styleable.View_textAlignment: 5028 // Clear any text alignment flag already set 5029 mPrivateFlags2 &= ~PFLAG2_TEXT_ALIGNMENT_MASK; 5030 // Set the text alignment flag depending on the value of the attribute 5031 final int textAlignment = a.getInt(attr, TEXT_ALIGNMENT_DEFAULT); 5032 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_FLAGS[textAlignment]; 5033 break; 5034 case R.styleable.View_importantForAccessibility: 5035 setImportantForAccessibility(a.getInt(attr, 5036 IMPORTANT_FOR_ACCESSIBILITY_DEFAULT)); 5037 break; 5038 case R.styleable.View_accessibilityLiveRegion: 5039 setAccessibilityLiveRegion(a.getInt(attr, ACCESSIBILITY_LIVE_REGION_DEFAULT)); 5040 break; 5041 case R.styleable.View_transitionName: 5042 setTransitionName(a.getString(attr)); 5043 break; 5044 case R.styleable.View_nestedScrollingEnabled: 5045 setNestedScrollingEnabled(a.getBoolean(attr, false)); 5046 break; 5047 case R.styleable.View_stateListAnimator: 5048 setStateListAnimator(AnimatorInflater.loadStateListAnimator(context, 5049 a.getResourceId(attr, 0))); 5050 break; 5051 case R.styleable.View_backgroundTint: 5052 // This will get applied later during setBackground(). 5053 if (mBackgroundTint == null) { 5054 mBackgroundTint = new TintInfo(); 5055 } 5056 mBackgroundTint.mTintList = a.getColorStateList( 5057 R.styleable.View_backgroundTint); 5058 mBackgroundTint.mHasTintList = true; 5059 break; 5060 case R.styleable.View_backgroundTintMode: 5061 // This will get applied later during setBackground(). 5062 if (mBackgroundTint == null) { 5063 mBackgroundTint = new TintInfo(); 5064 } 5065 mBackgroundTint.mTintMode = Drawable.parseTintMode(a.getInt( 5066 R.styleable.View_backgroundTintMode, -1), null); 5067 mBackgroundTint.mHasTintMode = true; 5068 break; 5069 case R.styleable.View_outlineProvider: 5070 setOutlineProviderFromAttribute(a.getInt(R.styleable.View_outlineProvider, 5071 PROVIDER_BACKGROUND)); 5072 break; 5073 case R.styleable.View_foreground: 5074 if (targetSdkVersion >= Build.VERSION_CODES.M || this instanceof FrameLayout) { 5075 setForeground(a.getDrawable(attr)); 5076 } 5077 break; 5078 case R.styleable.View_foregroundGravity: 5079 if (targetSdkVersion >= Build.VERSION_CODES.M || this instanceof FrameLayout) { 5080 setForegroundGravity(a.getInt(attr, Gravity.NO_GRAVITY)); 5081 } 5082 break; 5083 case R.styleable.View_foregroundTintMode: 5084 if (targetSdkVersion >= Build.VERSION_CODES.M || this instanceof FrameLayout) { 5085 setForegroundTintMode(Drawable.parseTintMode(a.getInt(attr, -1), null)); 5086 } 5087 break; 5088 case R.styleable.View_foregroundTint: 5089 if (targetSdkVersion >= Build.VERSION_CODES.M || this instanceof FrameLayout) { 5090 setForegroundTintList(a.getColorStateList(attr)); 5091 } 5092 break; 5093 case R.styleable.View_foregroundInsidePadding: 5094 if (targetSdkVersion >= Build.VERSION_CODES.M || this instanceof FrameLayout) { 5095 if (mForegroundInfo == null) { 5096 mForegroundInfo = new ForegroundInfo(); 5097 } 5098 mForegroundInfo.mInsidePadding = a.getBoolean(attr, 5099 mForegroundInfo.mInsidePadding); 5100 } 5101 break; 5102 case R.styleable.View_scrollIndicators: 5103 final int scrollIndicators = 5104 (a.getInt(attr, 0) << SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT) 5105 & SCROLL_INDICATORS_PFLAG3_MASK; 5106 if (scrollIndicators != 0) { 5107 mPrivateFlags3 |= scrollIndicators; 5108 initializeScrollIndicators = true; 5109 } 5110 break; 5111 case R.styleable.View_pointerIcon: 5112 final int resourceId = a.getResourceId(attr, 0); 5113 if (resourceId != 0) { 5114 setPointerIcon(PointerIcon.load( 5115 context.getResources(), resourceId)); 5116 } else { 5117 final int pointerType = a.getInt(attr, PointerIcon.TYPE_NOT_SPECIFIED); 5118 if (pointerType != PointerIcon.TYPE_NOT_SPECIFIED) { 5119 setPointerIcon(PointerIcon.getSystemIcon(context, pointerType)); 5120 } 5121 } 5122 break; 5123 case R.styleable.View_forceHasOverlappingRendering: 5124 if (a.peekValue(attr) != null) { 5125 forceHasOverlappingRendering(a.getBoolean(attr, true)); 5126 } 5127 break; 5128 case R.styleable.View_tooltipText: 5129 setTooltipText(a.getText(attr)); 5130 break; 5131 case R.styleable.View_keyboardNavigationCluster: 5132 if (a.peekValue(attr) != null) { 5133 setKeyboardNavigationCluster(a.getBoolean(attr, true)); 5134 } 5135 break; 5136 case R.styleable.View_focusedByDefault: 5137 if (a.peekValue(attr) != null) { 5138 setFocusedByDefault(a.getBoolean(attr, true)); 5139 } 5140 break; 5141 case R.styleable.View_autofillHints: 5142 if (a.peekValue(attr) != null) { 5143 CharSequence[] rawHints = null; 5144 String rawString = null; 5145 5146 if (a.getType(attr) == TypedValue.TYPE_REFERENCE) { 5147 int resId = a.getResourceId(attr, 0); 5148 5149 try { 5150 rawHints = a.getTextArray(attr); 5151 } catch (Resources.NotFoundException e) { 5152 rawString = getResources().getString(resId); 5153 } 5154 } else { 5155 rawString = a.getString(attr); 5156 } 5157 5158 if (rawHints == null) { 5159 if (rawString == null) { 5160 throw new IllegalArgumentException( 5161 "Could not resolve autofillHints"); 5162 } else { 5163 rawHints = rawString.split(","); 5164 } 5165 } 5166 5167 String[] hints = new String[rawHints.length]; 5168 5169 int numHints = rawHints.length; 5170 for (int rawHintNum = 0; rawHintNum < numHints; rawHintNum++) { 5171 hints[rawHintNum] = rawHints[rawHintNum].toString().trim(); 5172 } 5173 setAutofillHints(hints); 5174 } 5175 break; 5176 case R.styleable.View_importantForAutofill: 5177 if (a.peekValue(attr) != null) { 5178 setImportantForAutofill(a.getInt(attr, IMPORTANT_FOR_AUTOFILL_AUTO)); 5179 } 5180 break; 5181 case R.styleable.View_defaultFocusHighlightEnabled: 5182 if (a.peekValue(attr) != null) { 5183 setDefaultFocusHighlightEnabled(a.getBoolean(attr, true)); 5184 } 5185 break; 5186 } 5187 } 5188 5189 setOverScrollMode(overScrollMode); 5190 5191 // Cache start/end user padding as we cannot fully resolve padding here (we dont have yet 5192 // the resolved layout direction). Those cached values will be used later during padding 5193 // resolution. 5194 mUserPaddingStart = startPadding; 5195 mUserPaddingEnd = endPadding; 5196 5197 if (background != null) { 5198 setBackground(background); 5199 } 5200 5201 // setBackground above will record that padding is currently provided by the background. 5202 // If we have padding specified via xml, record that here instead and use it. 5203 mLeftPaddingDefined = leftPaddingDefined; 5204 mRightPaddingDefined = rightPaddingDefined; 5205 5206 if (padding >= 0) { 5207 leftPadding = padding; 5208 topPadding = padding; 5209 rightPadding = padding; 5210 bottomPadding = padding; 5211 mUserPaddingLeftInitial = padding; 5212 mUserPaddingRightInitial = padding; 5213 } else { 5214 if (paddingHorizontal >= 0) { 5215 leftPadding = paddingHorizontal; 5216 rightPadding = paddingHorizontal; 5217 mUserPaddingLeftInitial = paddingHorizontal; 5218 mUserPaddingRightInitial = paddingHorizontal; 5219 } 5220 if (paddingVertical >= 0) { 5221 topPadding = paddingVertical; 5222 bottomPadding = paddingVertical; 5223 } 5224 } 5225 5226 if (isRtlCompatibilityMode()) { 5227 // RTL compatibility mode: pre Jelly Bean MR1 case OR no RTL support case. 5228 // left / right padding are used if defined (meaning here nothing to do). If they are not 5229 // defined and start / end padding are defined (e.g. in Frameworks resources), then we use 5230 // start / end and resolve them as left / right (layout direction is not taken into account). 5231 // Padding from the background drawable is stored at this point in mUserPaddingLeftInitial 5232 // and mUserPaddingRightInitial) so drawable padding will be used as ultimate default if 5233 // defined. 5234 if (!mLeftPaddingDefined && startPaddingDefined) { 5235 leftPadding = startPadding; 5236 } 5237 mUserPaddingLeftInitial = (leftPadding >= 0) ? leftPadding : mUserPaddingLeftInitial; 5238 if (!mRightPaddingDefined && endPaddingDefined) { 5239 rightPadding = endPadding; 5240 } 5241 mUserPaddingRightInitial = (rightPadding >= 0) ? rightPadding : mUserPaddingRightInitial; 5242 } else { 5243 // Jelly Bean MR1 and after case: if start/end defined, they will override any left/right 5244 // values defined. Otherwise, left /right values are used. 5245 // Padding from the background drawable is stored at this point in mUserPaddingLeftInitial 5246 // and mUserPaddingRightInitial) so drawable padding will be used as ultimate default if 5247 // defined. 5248 final boolean hasRelativePadding = startPaddingDefined || endPaddingDefined; 5249 5250 if (mLeftPaddingDefined && !hasRelativePadding) { 5251 mUserPaddingLeftInitial = leftPadding; 5252 } 5253 if (mRightPaddingDefined && !hasRelativePadding) { 5254 mUserPaddingRightInitial = rightPadding; 5255 } 5256 } 5257 5258 internalSetPadding( 5259 mUserPaddingLeftInitial, 5260 topPadding >= 0 ? topPadding : mPaddingTop, 5261 mUserPaddingRightInitial, 5262 bottomPadding >= 0 ? bottomPadding : mPaddingBottom); 5263 5264 if (viewFlagMasks != 0) { 5265 setFlags(viewFlagValues, viewFlagMasks); 5266 } 5267 5268 if (initializeScrollbars) { 5269 initializeScrollbarsInternal(a); 5270 } 5271 5272 if (initializeScrollIndicators) { 5273 initializeScrollIndicatorsInternal(); 5274 } 5275 5276 a.recycle(); 5277 5278 // Needs to be called after mViewFlags is set 5279 if (scrollbarStyle != SCROLLBARS_INSIDE_OVERLAY) { 5280 recomputePadding(); 5281 } 5282 5283 if (x != 0 || y != 0) { 5284 scrollTo(x, y); 5285 } 5286 5287 if (transformSet) { 5288 setTranslationX(tx); 5289 setTranslationY(ty); 5290 setTranslationZ(tz); 5291 setElevation(elevation); 5292 setRotation(rotation); 5293 setRotationX(rotationX); 5294 setRotationY(rotationY); 5295 setScaleX(sx); 5296 setScaleY(sy); 5297 } 5298 5299 if (!setScrollContainer && (viewFlagValues&SCROLLBARS_VERTICAL) != 0) { 5300 setScrollContainer(true); 5301 } 5302 5303 computeOpaqueFlags(); 5304 } 5305 5306 /** 5307 * An implementation of OnClickListener that attempts to lazily load a 5308 * named click handling method from a parent or ancestor context. 5309 */ 5310 private static class DeclaredOnClickListener implements OnClickListener { 5311 private final View mHostView; 5312 private final String mMethodName; 5313 5314 private Method mResolvedMethod; 5315 private Context mResolvedContext; 5316 5317 public DeclaredOnClickListener(@NonNull View hostView, @NonNull String methodName) { 5318 mHostView = hostView; 5319 mMethodName = methodName; 5320 } 5321 5322 @Override 5323 public void onClick(@NonNull View v) { 5324 if (mResolvedMethod == null) { 5325 resolveMethod(mHostView.getContext(), mMethodName); 5326 } 5327 5328 try { 5329 mResolvedMethod.invoke(mResolvedContext, v); 5330 } catch (IllegalAccessException e) { 5331 throw new IllegalStateException( 5332 "Could not execute non-public method for android:onClick", e); 5333 } catch (InvocationTargetException e) { 5334 throw new IllegalStateException( 5335 "Could not execute method for android:onClick", e); 5336 } 5337 } 5338 5339 @NonNull 5340 private void resolveMethod(@Nullable Context context, @NonNull String name) { 5341 while (context != null) { 5342 try { 5343 if (!context.isRestricted()) { 5344 final Method method = context.getClass().getMethod(mMethodName, View.class); 5345 if (method != null) { 5346 mResolvedMethod = method; 5347 mResolvedContext = context; 5348 return; 5349 } 5350 } 5351 } catch (NoSuchMethodException e) { 5352 // Failed to find method, keep searching up the hierarchy. 5353 } 5354 5355 if (context instanceof ContextWrapper) { 5356 context = ((ContextWrapper) context).getBaseContext(); 5357 } else { 5358 // Can't search up the hierarchy, null out and fail. 5359 context = null; 5360 } 5361 } 5362 5363 final int id = mHostView.getId(); 5364 final String idText = id == NO_ID ? "" : " with id '" 5365 + mHostView.getContext().getResources().getResourceEntryName(id) + "'"; 5366 throw new IllegalStateException("Could not find method " + mMethodName 5367 + "(View) in a parent or ancestor Context for android:onClick " 5368 + "attribute defined on view " + mHostView.getClass() + idText); 5369 } 5370 } 5371 5372 /** 5373 * Non-public constructor for use in testing 5374 */ 5375 View() { 5376 mResources = null; 5377 mRenderNode = RenderNode.create(getClass().getName(), this); 5378 } 5379 5380 final boolean debugDraw() { 5381 return DEBUG_DRAW || mAttachInfo != null && mAttachInfo.mDebugLayout; 5382 } 5383 5384 private static SparseArray<String> getAttributeMap() { 5385 if (mAttributeMap == null) { 5386 mAttributeMap = new SparseArray<>(); 5387 } 5388 return mAttributeMap; 5389 } 5390 5391 private void saveAttributeData(@Nullable AttributeSet attrs, @NonNull TypedArray t) { 5392 final int attrsCount = attrs == null ? 0 : attrs.getAttributeCount(); 5393 final int indexCount = t.getIndexCount(); 5394 final String[] attributes = new String[(attrsCount + indexCount) * 2]; 5395 5396 int i = 0; 5397 5398 // Store raw XML attributes. 5399 for (int j = 0; j < attrsCount; ++j) { 5400 attributes[i] = attrs.getAttributeName(j); 5401 attributes[i + 1] = attrs.getAttributeValue(j); 5402 i += 2; 5403 } 5404 5405 // Store resolved styleable attributes. 5406 final Resources res = t.getResources(); 5407 final SparseArray<String> attributeMap = getAttributeMap(); 5408 for (int j = 0; j < indexCount; ++j) { 5409 final int index = t.getIndex(j); 5410 if (!t.hasValueOrEmpty(index)) { 5411 // Value is undefined. Skip it. 5412 continue; 5413 } 5414 5415 final int resourceId = t.getResourceId(index, 0); 5416 if (resourceId == 0) { 5417 // Value is not a reference. Skip it. 5418 continue; 5419 } 5420 5421 String resourceName = attributeMap.get(resourceId); 5422 if (resourceName == null) { 5423 try { 5424 resourceName = res.getResourceName(resourceId); 5425 } catch (Resources.NotFoundException e) { 5426 resourceName = "0x" + Integer.toHexString(resourceId); 5427 } 5428 attributeMap.put(resourceId, resourceName); 5429 } 5430 5431 attributes[i] = resourceName; 5432 attributes[i + 1] = t.getString(index); 5433 i += 2; 5434 } 5435 5436 // Trim to fit contents. 5437 final String[] trimmed = new String[i]; 5438 System.arraycopy(attributes, 0, trimmed, 0, i); 5439 mAttributes = trimmed; 5440 } 5441 5442 public String toString() { 5443 StringBuilder out = new StringBuilder(128); 5444 out.append(getClass().getName()); 5445 out.append('{'); 5446 out.append(Integer.toHexString(System.identityHashCode(this))); 5447 out.append(' '); 5448 switch (mViewFlags&VISIBILITY_MASK) { 5449 case VISIBLE: out.append('V'); break; 5450 case INVISIBLE: out.append('I'); break; 5451 case GONE: out.append('G'); break; 5452 default: out.append('.'); break; 5453 } 5454 out.append((mViewFlags & FOCUSABLE) == FOCUSABLE ? 'F' : '.'); 5455 out.append((mViewFlags&ENABLED_MASK) == ENABLED ? 'E' : '.'); 5456 out.append((mViewFlags&DRAW_MASK) == WILL_NOT_DRAW ? '.' : 'D'); 5457 out.append((mViewFlags&SCROLLBARS_HORIZONTAL) != 0 ? 'H' : '.'); 5458 out.append((mViewFlags&SCROLLBARS_VERTICAL) != 0 ? 'V' : '.'); 5459 out.append((mViewFlags&CLICKABLE) != 0 ? 'C' : '.'); 5460 out.append((mViewFlags&LONG_CLICKABLE) != 0 ? 'L' : '.'); 5461 out.append((mViewFlags&CONTEXT_CLICKABLE) != 0 ? 'X' : '.'); 5462 out.append(' '); 5463 out.append((mPrivateFlags&PFLAG_IS_ROOT_NAMESPACE) != 0 ? 'R' : '.'); 5464 out.append((mPrivateFlags&PFLAG_FOCUSED) != 0 ? 'F' : '.'); 5465 out.append((mPrivateFlags&PFLAG_SELECTED) != 0 ? 'S' : '.'); 5466 if ((mPrivateFlags&PFLAG_PREPRESSED) != 0) { 5467 out.append('p'); 5468 } else { 5469 out.append((mPrivateFlags&PFLAG_PRESSED) != 0 ? 'P' : '.'); 5470 } 5471 out.append((mPrivateFlags&PFLAG_HOVERED) != 0 ? 'H' : '.'); 5472 out.append((mPrivateFlags&PFLAG_ACTIVATED) != 0 ? 'A' : '.'); 5473 out.append((mPrivateFlags&PFLAG_INVALIDATED) != 0 ? 'I' : '.'); 5474 out.append((mPrivateFlags&PFLAG_DIRTY_MASK) != 0 ? 'D' : '.'); 5475 out.append(' '); 5476 out.append(mLeft); 5477 out.append(','); 5478 out.append(mTop); 5479 out.append('-'); 5480 out.append(mRight); 5481 out.append(','); 5482 out.append(mBottom); 5483 final int id = getId(); 5484 if (id != NO_ID) { 5485 out.append(" #"); 5486 out.append(Integer.toHexString(id)); 5487 final Resources r = mResources; 5488 if (id > 0 && Resources.resourceHasPackage(id) && r != null) { 5489 try { 5490 String pkgname; 5491 switch (id&0xff000000) { 5492 case 0x7f000000: 5493 pkgname="app"; 5494 break; 5495 case 0x01000000: 5496 pkgname="android"; 5497 break; 5498 default: 5499 pkgname = r.getResourcePackageName(id); 5500 break; 5501 } 5502 String typename = r.getResourceTypeName(id); 5503 String entryname = r.getResourceEntryName(id); 5504 out.append(" "); 5505 out.append(pkgname); 5506 out.append(":"); 5507 out.append(typename); 5508 out.append("/"); 5509 out.append(entryname); 5510 } catch (Resources.NotFoundException e) { 5511 } 5512 } 5513 } 5514 out.append("}"); 5515 return out.toString(); 5516 } 5517 5518 /** 5519 * <p> 5520 * Initializes the fading edges from a given set of styled attributes. This 5521 * method should be called by subclasses that need fading edges and when an 5522 * instance of these subclasses is created programmatically rather than 5523 * being inflated from XML. This method is automatically called when the XML 5524 * is inflated. 5525 * </p> 5526 * 5527 * @param a the styled attributes set to initialize the fading edges from 5528 * 5529 * @removed 5530 */ 5531 protected void initializeFadingEdge(TypedArray a) { 5532 // This method probably shouldn't have been included in the SDK to begin with. 5533 // It relies on 'a' having been initialized using an attribute filter array that is 5534 // not publicly available to the SDK. The old method has been renamed 5535 // to initializeFadingEdgeInternal and hidden for framework use only; 5536 // this one initializes using defaults to make it safe to call for apps. 5537 5538 TypedArray arr = mContext.obtainStyledAttributes(com.android.internal.R.styleable.View); 5539 5540 initializeFadingEdgeInternal(arr); 5541 5542 arr.recycle(); 5543 } 5544 5545 /** 5546 * <p> 5547 * Initializes the fading edges from a given set of styled attributes. This 5548 * method should be called by subclasses that need fading edges and when an 5549 * instance of these subclasses is created programmatically rather than 5550 * being inflated from XML. This method is automatically called when the XML 5551 * is inflated. 5552 * </p> 5553 * 5554 * @param a the styled attributes set to initialize the fading edges from 5555 * @hide This is the real method; the public one is shimmed to be safe to call from apps. 5556 */ 5557 protected void initializeFadingEdgeInternal(TypedArray a) { 5558 initScrollCache(); 5559 5560 mScrollCache.fadingEdgeLength = a.getDimensionPixelSize( 5561 R.styleable.View_fadingEdgeLength, 5562 ViewConfiguration.get(mContext).getScaledFadingEdgeLength()); 5563 } 5564 5565 /** 5566 * Returns the size of the vertical faded edges used to indicate that more 5567 * content in this view is visible. 5568 * 5569 * @return The size in pixels of the vertical faded edge or 0 if vertical 5570 * faded edges are not enabled for this view. 5571 * @attr ref android.R.styleable#View_fadingEdgeLength 5572 */ 5573 public int getVerticalFadingEdgeLength() { 5574 if (isVerticalFadingEdgeEnabled()) { 5575 ScrollabilityCache cache = mScrollCache; 5576 if (cache != null) { 5577 return cache.fadingEdgeLength; 5578 } 5579 } 5580 return 0; 5581 } 5582 5583 /** 5584 * Set the size of the faded edge used to indicate that more content in this 5585 * view is available. Will not change whether the fading edge is enabled; use 5586 * {@link #setVerticalFadingEdgeEnabled(boolean)} or 5587 * {@link #setHorizontalFadingEdgeEnabled(boolean)} to enable the fading edge 5588 * for the vertical or horizontal fading edges. 5589 * 5590 * @param length The size in pixels of the faded edge used to indicate that more 5591 * content in this view is visible. 5592 */ 5593 public void setFadingEdgeLength(int length) { 5594 initScrollCache(); 5595 mScrollCache.fadingEdgeLength = length; 5596 } 5597 5598 /** 5599 * Returns the size of the horizontal faded edges used to indicate that more 5600 * content in this view is visible. 5601 * 5602 * @return The size in pixels of the horizontal faded edge or 0 if horizontal 5603 * faded edges are not enabled for this view. 5604 * @attr ref android.R.styleable#View_fadingEdgeLength 5605 */ 5606 public int getHorizontalFadingEdgeLength() { 5607 if (isHorizontalFadingEdgeEnabled()) { 5608 ScrollabilityCache cache = mScrollCache; 5609 if (cache != null) { 5610 return cache.fadingEdgeLength; 5611 } 5612 } 5613 return 0; 5614 } 5615 5616 /** 5617 * Returns the width of the vertical scrollbar. 5618 * 5619 * @return The width in pixels of the vertical scrollbar or 0 if there 5620 * is no vertical scrollbar. 5621 */ 5622 public int getVerticalScrollbarWidth() { 5623 ScrollabilityCache cache = mScrollCache; 5624 if (cache != null) { 5625 ScrollBarDrawable scrollBar = cache.scrollBar; 5626 if (scrollBar != null) { 5627 int size = scrollBar.getSize(true); 5628 if (size <= 0) { 5629 size = cache.scrollBarSize; 5630 } 5631 return size; 5632 } 5633 return 0; 5634 } 5635 return 0; 5636 } 5637 5638 /** 5639 * Returns the height of the horizontal scrollbar. 5640 * 5641 * @return The height in pixels of the horizontal scrollbar or 0 if 5642 * there is no horizontal scrollbar. 5643 */ 5644 protected int getHorizontalScrollbarHeight() { 5645 ScrollabilityCache cache = mScrollCache; 5646 if (cache != null) { 5647 ScrollBarDrawable scrollBar = cache.scrollBar; 5648 if (scrollBar != null) { 5649 int size = scrollBar.getSize(false); 5650 if (size <= 0) { 5651 size = cache.scrollBarSize; 5652 } 5653 return size; 5654 } 5655 return 0; 5656 } 5657 return 0; 5658 } 5659 5660 /** 5661 * <p> 5662 * Initializes the scrollbars from a given set of styled attributes. This 5663 * method should be called by subclasses that need scrollbars and when an 5664 * instance of these subclasses is created programmatically rather than 5665 * being inflated from XML. This method is automatically called when the XML 5666 * is inflated. 5667 * </p> 5668 * 5669 * @param a the styled attributes set to initialize the scrollbars from 5670 * 5671 * @removed 5672 */ 5673 protected void initializeScrollbars(TypedArray a) { 5674 // It's not safe to use this method from apps. The parameter 'a' must have been obtained 5675 // using the View filter array which is not available to the SDK. As such, internal 5676 // framework usage now uses initializeScrollbarsInternal and we grab a default 5677 // TypedArray with the right filter instead here. 5678 TypedArray arr = mContext.obtainStyledAttributes(com.android.internal.R.styleable.View); 5679 5680 initializeScrollbarsInternal(arr); 5681 5682 // We ignored the method parameter. Recycle the one we actually did use. 5683 arr.recycle(); 5684 } 5685 5686 /** 5687 * <p> 5688 * Initializes the scrollbars from a given set of styled attributes. This 5689 * method should be called by subclasses that need scrollbars and when an 5690 * instance of these subclasses is created programmatically rather than 5691 * being inflated from XML. This method is automatically called when the XML 5692 * is inflated. 5693 * </p> 5694 * 5695 * @param a the styled attributes set to initialize the scrollbars from 5696 * @hide 5697 */ 5698 protected void initializeScrollbarsInternal(TypedArray a) { 5699 initScrollCache(); 5700 5701 final ScrollabilityCache scrollabilityCache = mScrollCache; 5702 5703 if (scrollabilityCache.scrollBar == null) { 5704 scrollabilityCache.scrollBar = new ScrollBarDrawable(); 5705 scrollabilityCache.scrollBar.setState(getDrawableState()); 5706 scrollabilityCache.scrollBar.setCallback(this); 5707 } 5708 5709 final boolean fadeScrollbars = a.getBoolean(R.styleable.View_fadeScrollbars, true); 5710 5711 if (!fadeScrollbars) { 5712 scrollabilityCache.state = ScrollabilityCache.ON; 5713 } 5714 scrollabilityCache.fadeScrollBars = fadeScrollbars; 5715 5716 5717 scrollabilityCache.scrollBarFadeDuration = a.getInt( 5718 R.styleable.View_scrollbarFadeDuration, ViewConfiguration 5719 .getScrollBarFadeDuration()); 5720 scrollabilityCache.scrollBarDefaultDelayBeforeFade = a.getInt( 5721 R.styleable.View_scrollbarDefaultDelayBeforeFade, 5722 ViewConfiguration.getScrollDefaultDelay()); 5723 5724 5725 scrollabilityCache.scrollBarSize = a.getDimensionPixelSize( 5726 com.android.internal.R.styleable.View_scrollbarSize, 5727 ViewConfiguration.get(mContext).getScaledScrollBarSize()); 5728 5729 Drawable track = a.getDrawable(R.styleable.View_scrollbarTrackHorizontal); 5730 scrollabilityCache.scrollBar.setHorizontalTrackDrawable(track); 5731 5732 Drawable thumb = a.getDrawable(R.styleable.View_scrollbarThumbHorizontal); 5733 if (thumb != null) { 5734 scrollabilityCache.scrollBar.setHorizontalThumbDrawable(thumb); 5735 } 5736 5737 boolean alwaysDraw = a.getBoolean(R.styleable.View_scrollbarAlwaysDrawHorizontalTrack, 5738 false); 5739 if (alwaysDraw) { 5740 scrollabilityCache.scrollBar.setAlwaysDrawHorizontalTrack(true); 5741 } 5742 5743 track = a.getDrawable(R.styleable.View_scrollbarTrackVertical); 5744 scrollabilityCache.scrollBar.setVerticalTrackDrawable(track); 5745 5746 thumb = a.getDrawable(R.styleable.View_scrollbarThumbVertical); 5747 if (thumb != null) { 5748 scrollabilityCache.scrollBar.setVerticalThumbDrawable(thumb); 5749 } 5750 5751 alwaysDraw = a.getBoolean(R.styleable.View_scrollbarAlwaysDrawVerticalTrack, 5752 false); 5753 if (alwaysDraw) { 5754 scrollabilityCache.scrollBar.setAlwaysDrawVerticalTrack(true); 5755 } 5756 5757 // Apply layout direction to the new Drawables if needed 5758 final int layoutDirection = getLayoutDirection(); 5759 if (track != null) { 5760 track.setLayoutDirection(layoutDirection); 5761 } 5762 if (thumb != null) { 5763 thumb.setLayoutDirection(layoutDirection); 5764 } 5765 5766 // Re-apply user/background padding so that scrollbar(s) get added 5767 resolvePadding(); 5768 } 5769 5770 private void initializeScrollIndicatorsInternal() { 5771 // Some day maybe we'll break this into top/left/start/etc. and let the 5772 // client control it. Until then, you can have any scroll indicator you 5773 // want as long as it's a 1dp foreground-colored rectangle. 5774 if (mScrollIndicatorDrawable == null) { 5775 mScrollIndicatorDrawable = mContext.getDrawable(R.drawable.scroll_indicator_material); 5776 } 5777 } 5778 5779 /** 5780 * <p> 5781 * Initalizes the scrollability cache if necessary. 5782 * </p> 5783 */ 5784 private void initScrollCache() { 5785 if (mScrollCache == null) { 5786 mScrollCache = new ScrollabilityCache(ViewConfiguration.get(mContext), this); 5787 } 5788 } 5789 5790 private ScrollabilityCache getScrollCache() { 5791 initScrollCache(); 5792 return mScrollCache; 5793 } 5794 5795 /** 5796 * Set the position of the vertical scroll bar. Should be one of 5797 * {@link #SCROLLBAR_POSITION_DEFAULT}, {@link #SCROLLBAR_POSITION_LEFT} or 5798 * {@link #SCROLLBAR_POSITION_RIGHT}. 5799 * 5800 * @param position Where the vertical scroll bar should be positioned. 5801 */ 5802 public void setVerticalScrollbarPosition(int position) { 5803 if (mVerticalScrollbarPosition != position) { 5804 mVerticalScrollbarPosition = position; 5805 computeOpaqueFlags(); 5806 resolvePadding(); 5807 } 5808 } 5809 5810 /** 5811 * @return The position where the vertical scroll bar will show, if applicable. 5812 * @see #setVerticalScrollbarPosition(int) 5813 */ 5814 public int getVerticalScrollbarPosition() { 5815 return mVerticalScrollbarPosition; 5816 } 5817 5818 boolean isOnScrollbar(float x, float y) { 5819 if (mScrollCache == null) { 5820 return false; 5821 } 5822 x += getScrollX(); 5823 y += getScrollY(); 5824 if (isVerticalScrollBarEnabled() && !isVerticalScrollBarHidden()) { 5825 final Rect touchBounds = mScrollCache.mScrollBarTouchBounds; 5826 getVerticalScrollBarBounds(null, touchBounds); 5827 if (touchBounds.contains((int) x, (int) y)) { 5828 return true; 5829 } 5830 } 5831 if (isHorizontalScrollBarEnabled()) { 5832 final Rect touchBounds = mScrollCache.mScrollBarTouchBounds; 5833 getHorizontalScrollBarBounds(null, touchBounds); 5834 if (touchBounds.contains((int) x, (int) y)) { 5835 return true; 5836 } 5837 } 5838 return false; 5839 } 5840 5841 boolean isOnScrollbarThumb(float x, float y) { 5842 return isOnVerticalScrollbarThumb(x, y) || isOnHorizontalScrollbarThumb(x, y); 5843 } 5844 5845 private boolean isOnVerticalScrollbarThumb(float x, float y) { 5846 if (mScrollCache == null) { 5847 return false; 5848 } 5849 if (isVerticalScrollBarEnabled() && !isVerticalScrollBarHidden()) { 5850 x += getScrollX(); 5851 y += getScrollY(); 5852 final Rect bounds = mScrollCache.mScrollBarBounds; 5853 final Rect touchBounds = mScrollCache.mScrollBarTouchBounds; 5854 getVerticalScrollBarBounds(bounds, touchBounds); 5855 final int range = computeVerticalScrollRange(); 5856 final int offset = computeVerticalScrollOffset(); 5857 final int extent = computeVerticalScrollExtent(); 5858 final int thumbLength = ScrollBarUtils.getThumbLength(bounds.height(), bounds.width(), 5859 extent, range); 5860 final int thumbOffset = ScrollBarUtils.getThumbOffset(bounds.height(), thumbLength, 5861 extent, range, offset); 5862 final int thumbTop = bounds.top + thumbOffset; 5863 final int adjust = Math.max(mScrollCache.scrollBarMinTouchTarget - thumbLength, 0) / 2; 5864 if (x >= touchBounds.left && x <= touchBounds.right 5865 && y >= thumbTop - adjust && y <= thumbTop + thumbLength + adjust) { 5866 return true; 5867 } 5868 } 5869 return false; 5870 } 5871 5872 private boolean isOnHorizontalScrollbarThumb(float x, float y) { 5873 if (mScrollCache == null) { 5874 return false; 5875 } 5876 if (isHorizontalScrollBarEnabled()) { 5877 x += getScrollX(); 5878 y += getScrollY(); 5879 final Rect bounds = mScrollCache.mScrollBarBounds; 5880 final Rect touchBounds = mScrollCache.mScrollBarTouchBounds; 5881 getHorizontalScrollBarBounds(bounds, touchBounds); 5882 final int range = computeHorizontalScrollRange(); 5883 final int offset = computeHorizontalScrollOffset(); 5884 final int extent = computeHorizontalScrollExtent(); 5885 final int thumbLength = ScrollBarUtils.getThumbLength(bounds.width(), bounds.height(), 5886 extent, range); 5887 final int thumbOffset = ScrollBarUtils.getThumbOffset(bounds.width(), thumbLength, 5888 extent, range, offset); 5889 final int thumbLeft = bounds.left + thumbOffset; 5890 final int adjust = Math.max(mScrollCache.scrollBarMinTouchTarget - thumbLength, 0) / 2; 5891 if (x >= thumbLeft - adjust && x <= thumbLeft + thumbLength + adjust 5892 && y >= touchBounds.top && y <= touchBounds.bottom) { 5893 return true; 5894 } 5895 } 5896 return false; 5897 } 5898 5899 boolean isDraggingScrollBar() { 5900 return mScrollCache != null 5901 && mScrollCache.mScrollBarDraggingState != ScrollabilityCache.NOT_DRAGGING; 5902 } 5903 5904 /** 5905 * Sets the state of all scroll indicators. 5906 * <p> 5907 * See {@link #setScrollIndicators(int, int)} for usage information. 5908 * 5909 * @param indicators a bitmask of indicators that should be enabled, or 5910 * {@code 0} to disable all indicators 5911 * @see #setScrollIndicators(int, int) 5912 * @see #getScrollIndicators() 5913 * @attr ref android.R.styleable#View_scrollIndicators 5914 */ 5915 public void setScrollIndicators(@ScrollIndicators int indicators) { 5916 setScrollIndicators(indicators, 5917 SCROLL_INDICATORS_PFLAG3_MASK >>> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT); 5918 } 5919 5920 /** 5921 * Sets the state of the scroll indicators specified by the mask. To change 5922 * all scroll indicators at once, see {@link #setScrollIndicators(int)}. 5923 * <p> 5924 * When a scroll indicator is enabled, it will be displayed if the view 5925 * can scroll in the direction of the indicator. 5926 * <p> 5927 * Multiple indicator types may be enabled or disabled by passing the 5928 * logical OR of the desired types. If multiple types are specified, they 5929 * will all be set to the same enabled state. 5930 * <p> 5931 * For example, to enable the top scroll indicatorExample: {@code setScrollIndicators 5932 * 5933 * @param indicators the indicator direction, or the logical OR of multiple 5934 * indicator directions. One or more of: 5935 * <ul> 5936 * <li>{@link #SCROLL_INDICATOR_TOP}</li> 5937 * <li>{@link #SCROLL_INDICATOR_BOTTOM}</li> 5938 * <li>{@link #SCROLL_INDICATOR_LEFT}</li> 5939 * <li>{@link #SCROLL_INDICATOR_RIGHT}</li> 5940 * <li>{@link #SCROLL_INDICATOR_START}</li> 5941 * <li>{@link #SCROLL_INDICATOR_END}</li> 5942 * </ul> 5943 * @see #setScrollIndicators(int) 5944 * @see #getScrollIndicators() 5945 * @attr ref android.R.styleable#View_scrollIndicators 5946 */ 5947 public void setScrollIndicators(@ScrollIndicators int indicators, @ScrollIndicators int mask) { 5948 // Shift and sanitize mask. 5949 mask <<= SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 5950 mask &= SCROLL_INDICATORS_PFLAG3_MASK; 5951 5952 // Shift and mask indicators. 5953 indicators <<= SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 5954 indicators &= mask; 5955 5956 // Merge with non-masked flags. 5957 final int updatedFlags = indicators | (mPrivateFlags3 & ~mask); 5958 5959 if (mPrivateFlags3 != updatedFlags) { 5960 mPrivateFlags3 = updatedFlags; 5961 5962 if (indicators != 0) { 5963 initializeScrollIndicatorsInternal(); 5964 } 5965 invalidate(); 5966 } 5967 } 5968 5969 /** 5970 * Returns a bitmask representing the enabled scroll indicators. 5971 * <p> 5972 * For example, if the top and left scroll indicators are enabled and all 5973 * other indicators are disabled, the return value will be 5974 * {@code View.SCROLL_INDICATOR_TOP | View.SCROLL_INDICATOR_LEFT}. 5975 * <p> 5976 * To check whether the bottom scroll indicator is enabled, use the value 5977 * of {@code (getScrollIndicators() & View.SCROLL_INDICATOR_BOTTOM) != 0}. 5978 * 5979 * @return a bitmask representing the enabled scroll indicators 5980 */ 5981 @ScrollIndicators 5982 public int getScrollIndicators() { 5983 return (mPrivateFlags3 & SCROLL_INDICATORS_PFLAG3_MASK) 5984 >>> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 5985 } 5986 5987 ListenerInfo getListenerInfo() { 5988 if (mListenerInfo != null) { 5989 return mListenerInfo; 5990 } 5991 mListenerInfo = new ListenerInfo(); 5992 return mListenerInfo; 5993 } 5994 5995 /** 5996 * Register a callback to be invoked when the scroll X or Y positions of 5997 * this view change. 5998 * <p> 5999 * <b>Note:</b> Some views handle scrolling independently from View and may 6000 * have their own separate listeners for scroll-type events. For example, 6001 * {@link android.widget.ListView ListView} allows clients to register an 6002 * {@link android.widget.ListView#setOnScrollListener(android.widget.AbsListView.OnScrollListener) AbsListView.OnScrollListener} 6003 * to listen for changes in list scroll position. 6004 * 6005 * @param l The listener to notify when the scroll X or Y position changes. 6006 * @see android.view.View#getScrollX() 6007 * @see android.view.View#getScrollY() 6008 */ 6009 public void setOnScrollChangeListener(OnScrollChangeListener l) { 6010 getListenerInfo().mOnScrollChangeListener = l; 6011 } 6012 6013 /** 6014 * Register a callback to be invoked when focus of this view changed. 6015 * 6016 * @param l The callback that will run. 6017 */ 6018 public void setOnFocusChangeListener(OnFocusChangeListener l) { 6019 getListenerInfo().mOnFocusChangeListener = l; 6020 } 6021 6022 /** 6023 * Add a listener that will be called when the bounds of the view change due to 6024 * layout processing. 6025 * 6026 * @param listener The listener that will be called when layout bounds change. 6027 */ 6028 public void addOnLayoutChangeListener(OnLayoutChangeListener listener) { 6029 ListenerInfo li = getListenerInfo(); 6030 if (li.mOnLayoutChangeListeners == null) { 6031 li.mOnLayoutChangeListeners = new ArrayList<OnLayoutChangeListener>(); 6032 } 6033 if (!li.mOnLayoutChangeListeners.contains(listener)) { 6034 li.mOnLayoutChangeListeners.add(listener); 6035 } 6036 } 6037 6038 /** 6039 * Remove a listener for layout changes. 6040 * 6041 * @param listener The listener for layout bounds change. 6042 */ 6043 public void removeOnLayoutChangeListener(OnLayoutChangeListener listener) { 6044 ListenerInfo li = mListenerInfo; 6045 if (li == null || li.mOnLayoutChangeListeners == null) { 6046 return; 6047 } 6048 li.mOnLayoutChangeListeners.remove(listener); 6049 } 6050 6051 /** 6052 * Add a listener for attach state changes. 6053 * 6054 * This listener will be called whenever this view is attached or detached 6055 * from a window. Remove the listener using 6056 * {@link #removeOnAttachStateChangeListener(OnAttachStateChangeListener)}. 6057 * 6058 * @param listener Listener to attach 6059 * @see #removeOnAttachStateChangeListener(OnAttachStateChangeListener) 6060 */ 6061 public void addOnAttachStateChangeListener(OnAttachStateChangeListener listener) { 6062 ListenerInfo li = getListenerInfo(); 6063 if (li.mOnAttachStateChangeListeners == null) { 6064 li.mOnAttachStateChangeListeners 6065 = new CopyOnWriteArrayList<OnAttachStateChangeListener>(); 6066 } 6067 li.mOnAttachStateChangeListeners.add(listener); 6068 } 6069 6070 /** 6071 * Remove a listener for attach state changes. The listener will receive no further 6072 * notification of window attach/detach events. 6073 * 6074 * @param listener Listener to remove 6075 * @see #addOnAttachStateChangeListener(OnAttachStateChangeListener) 6076 */ 6077 public void removeOnAttachStateChangeListener(OnAttachStateChangeListener listener) { 6078 ListenerInfo li = mListenerInfo; 6079 if (li == null || li.mOnAttachStateChangeListeners == null) { 6080 return; 6081 } 6082 li.mOnAttachStateChangeListeners.remove(listener); 6083 } 6084 6085 /** 6086 * Returns the focus-change callback registered for this view. 6087 * 6088 * @return The callback, or null if one is not registered. 6089 */ 6090 public OnFocusChangeListener getOnFocusChangeListener() { 6091 ListenerInfo li = mListenerInfo; 6092 return li != null ? li.mOnFocusChangeListener : null; 6093 } 6094 6095 /** 6096 * Register a callback to be invoked when this view is clicked. If this view is not 6097 * clickable, it becomes clickable. 6098 * 6099 * @param l The callback that will run 6100 * 6101 * @see #setClickable(boolean) 6102 */ 6103 public void setOnClickListener(@Nullable OnClickListener l) { 6104 if (!isClickable()) { 6105 setClickable(true); 6106 } 6107 getListenerInfo().mOnClickListener = l; 6108 } 6109 6110 /** 6111 * Return whether this view has an attached OnClickListener. Returns 6112 * true if there is a listener, false if there is none. 6113 */ 6114 public boolean hasOnClickListeners() { 6115 ListenerInfo li = mListenerInfo; 6116 return (li != null && li.mOnClickListener != null); 6117 } 6118 6119 /** 6120 * Register a callback to be invoked when this view is clicked and held. If this view is not 6121 * long clickable, it becomes long clickable. 6122 * 6123 * @param l The callback that will run 6124 * 6125 * @see #setLongClickable(boolean) 6126 */ 6127 public void setOnLongClickListener(@Nullable OnLongClickListener l) { 6128 if (!isLongClickable()) { 6129 setLongClickable(true); 6130 } 6131 getListenerInfo().mOnLongClickListener = l; 6132 } 6133 6134 /** 6135 * Register a callback to be invoked when this view is context clicked. If the view is not 6136 * context clickable, it becomes context clickable. 6137 * 6138 * @param l The callback that will run 6139 * @see #setContextClickable(boolean) 6140 */ 6141 public void setOnContextClickListener(@Nullable OnContextClickListener l) { 6142 if (!isContextClickable()) { 6143 setContextClickable(true); 6144 } 6145 getListenerInfo().mOnContextClickListener = l; 6146 } 6147 6148 /** 6149 * Register a callback to be invoked when the context menu for this view is 6150 * being built. If this view is not long clickable, it becomes long clickable. 6151 * 6152 * @param l The callback that will run 6153 * 6154 */ 6155 public void setOnCreateContextMenuListener(OnCreateContextMenuListener l) { 6156 if (!isLongClickable()) { 6157 setLongClickable(true); 6158 } 6159 getListenerInfo().mOnCreateContextMenuListener = l; 6160 } 6161 6162 /** 6163 * Set an observer to collect stats for each frame rendered for this view. 6164 * 6165 * @hide 6166 */ 6167 public void addFrameMetricsListener(Window window, 6168 Window.OnFrameMetricsAvailableListener listener, 6169 Handler handler) { 6170 if (mAttachInfo != null) { 6171 if (mAttachInfo.mThreadedRenderer != null) { 6172 if (mFrameMetricsObservers == null) { 6173 mFrameMetricsObservers = new ArrayList<>(); 6174 } 6175 6176 FrameMetricsObserver fmo = new FrameMetricsObserver(window, 6177 handler.getLooper(), listener); 6178 mFrameMetricsObservers.add(fmo); 6179 mAttachInfo.mThreadedRenderer.addFrameMetricsObserver(fmo); 6180 } else { 6181 Log.w(VIEW_LOG_TAG, "View not hardware-accelerated. Unable to observe frame stats"); 6182 } 6183 } else { 6184 if (mFrameMetricsObservers == null) { 6185 mFrameMetricsObservers = new ArrayList<>(); 6186 } 6187 6188 FrameMetricsObserver fmo = new FrameMetricsObserver(window, 6189 handler.getLooper(), listener); 6190 mFrameMetricsObservers.add(fmo); 6191 } 6192 } 6193 6194 /** 6195 * Remove observer configured to collect frame stats for this view. 6196 * 6197 * @hide 6198 */ 6199 public void removeFrameMetricsListener( 6200 Window.OnFrameMetricsAvailableListener listener) { 6201 ThreadedRenderer renderer = getThreadedRenderer(); 6202 FrameMetricsObserver fmo = findFrameMetricsObserver(listener); 6203 if (fmo == null) { 6204 throw new IllegalArgumentException( 6205 "attempt to remove OnFrameMetricsAvailableListener that was never added"); 6206 } 6207 6208 if (mFrameMetricsObservers != null) { 6209 mFrameMetricsObservers.remove(fmo); 6210 if (renderer != null) { 6211 renderer.removeFrameMetricsObserver(fmo); 6212 } 6213 } 6214 } 6215 6216 private void registerPendingFrameMetricsObservers() { 6217 if (mFrameMetricsObservers != null) { 6218 ThreadedRenderer renderer = getThreadedRenderer(); 6219 if (renderer != null) { 6220 for (FrameMetricsObserver fmo : mFrameMetricsObservers) { 6221 renderer.addFrameMetricsObserver(fmo); 6222 } 6223 } else { 6224 Log.w(VIEW_LOG_TAG, "View not hardware-accelerated. Unable to observe frame stats"); 6225 } 6226 } 6227 } 6228 6229 private FrameMetricsObserver findFrameMetricsObserver( 6230 Window.OnFrameMetricsAvailableListener listener) { 6231 for (int i = 0; i < mFrameMetricsObservers.size(); i++) { 6232 FrameMetricsObserver observer = mFrameMetricsObservers.get(i); 6233 if (observer.mListener == listener) { 6234 return observer; 6235 } 6236 } 6237 6238 return null; 6239 } 6240 6241 /** 6242 * Call this view's OnClickListener, if it is defined. Performs all normal 6243 * actions associated with clicking: reporting accessibility event, playing 6244 * a sound, etc. 6245 * 6246 * @return True there was an assigned OnClickListener that was called, false 6247 * otherwise is returned. 6248 */ 6249 public boolean performClick() { 6250 final boolean result; 6251 final ListenerInfo li = mListenerInfo; 6252 if (li != null && li.mOnClickListener != null) { 6253 playSoundEffect(SoundEffectConstants.CLICK); 6254 li.mOnClickListener.onClick(this); 6255 result = true; 6256 } else { 6257 result = false; 6258 } 6259 6260 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED); 6261 6262 notifyEnterOrExitForAutoFillIfNeeded(true); 6263 6264 return result; 6265 } 6266 6267 /** 6268 * Directly call any attached OnClickListener. Unlike {@link #performClick()}, 6269 * this only calls the listener, and does not do any associated clicking 6270 * actions like reporting an accessibility event. 6271 * 6272 * @return True there was an assigned OnClickListener that was called, false 6273 * otherwise is returned. 6274 */ 6275 public boolean callOnClick() { 6276 ListenerInfo li = mListenerInfo; 6277 if (li != null && li.mOnClickListener != null) { 6278 li.mOnClickListener.onClick(this); 6279 return true; 6280 } 6281 return false; 6282 } 6283 6284 /** 6285 * Calls this view's OnLongClickListener, if it is defined. Invokes the 6286 * context menu if the OnLongClickListener did not consume the event. 6287 * 6288 * @return {@code true} if one of the above receivers consumed the event, 6289 * {@code false} otherwise 6290 */ 6291 public boolean performLongClick() { 6292 return performLongClickInternal(mLongClickX, mLongClickY); 6293 } 6294 6295 /** 6296 * Calls this view's OnLongClickListener, if it is defined. Invokes the 6297 * context menu if the OnLongClickListener did not consume the event, 6298 * anchoring it to an (x,y) coordinate. 6299 * 6300 * @param x x coordinate of the anchoring touch event, or {@link Float#NaN} 6301 * to disable anchoring 6302 * @param y y coordinate of the anchoring touch event, or {@link Float#NaN} 6303 * to disable anchoring 6304 * @return {@code true} if one of the above receivers consumed the event, 6305 * {@code false} otherwise 6306 */ 6307 public boolean performLongClick(float x, float y) { 6308 mLongClickX = x; 6309 mLongClickY = y; 6310 final boolean handled = performLongClick(); 6311 mLongClickX = Float.NaN; 6312 mLongClickY = Float.NaN; 6313 return handled; 6314 } 6315 6316 /** 6317 * Calls this view's OnLongClickListener, if it is defined. Invokes the 6318 * context menu if the OnLongClickListener did not consume the event, 6319 * optionally anchoring it to an (x,y) coordinate. 6320 * 6321 * @param x x coordinate of the anchoring touch event, or {@link Float#NaN} 6322 * to disable anchoring 6323 * @param y y coordinate of the anchoring touch event, or {@link Float#NaN} 6324 * to disable anchoring 6325 * @return {@code true} if one of the above receivers consumed the event, 6326 * {@code false} otherwise 6327 */ 6328 private boolean performLongClickInternal(float x, float y) { 6329 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_LONG_CLICKED); 6330 6331 boolean handled = false; 6332 final ListenerInfo li = mListenerInfo; 6333 if (li != null && li.mOnLongClickListener != null) { 6334 handled = li.mOnLongClickListener.onLongClick(View.this); 6335 } 6336 if (!handled) { 6337 final boolean isAnchored = !Float.isNaN(x) && !Float.isNaN(y); 6338 handled = isAnchored ? showContextMenu(x, y) : showContextMenu(); 6339 } 6340 if ((mViewFlags & TOOLTIP) == TOOLTIP) { 6341 if (!handled) { 6342 handled = showLongClickTooltip((int) x, (int) y); 6343 } 6344 } 6345 if (handled) { 6346 performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); 6347 } 6348 return handled; 6349 } 6350 6351 /** 6352 * Call this view's OnContextClickListener, if it is defined. 6353 * 6354 * @param x the x coordinate of the context click 6355 * @param y the y coordinate of the context click 6356 * @return True if there was an assigned OnContextClickListener that consumed the event, false 6357 * otherwise. 6358 */ 6359 public boolean performContextClick(float x, float y) { 6360 return performContextClick(); 6361 } 6362 6363 /** 6364 * Call this view's OnContextClickListener, if it is defined. 6365 * 6366 * @return True if there was an assigned OnContextClickListener that consumed the event, false 6367 * otherwise. 6368 */ 6369 public boolean performContextClick() { 6370 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CONTEXT_CLICKED); 6371 6372 boolean handled = false; 6373 ListenerInfo li = mListenerInfo; 6374 if (li != null && li.mOnContextClickListener != null) { 6375 handled = li.mOnContextClickListener.onContextClick(View.this); 6376 } 6377 if (handled) { 6378 performHapticFeedback(HapticFeedbackConstants.CONTEXT_CLICK); 6379 } 6380 return handled; 6381 } 6382 6383 /** 6384 * Performs button-related actions during a touch down event. 6385 * 6386 * @param event The event. 6387 * @return True if the down was consumed. 6388 * 6389 * @hide 6390 */ 6391 protected boolean performButtonActionOnTouchDown(MotionEvent event) { 6392 if (event.isFromSource(InputDevice.SOURCE_MOUSE) && 6393 (event.getButtonState() & MotionEvent.BUTTON_SECONDARY) != 0) { 6394 showContextMenu(event.getX(), event.getY()); 6395 mPrivateFlags |= PFLAG_CANCEL_NEXT_UP_EVENT; 6396 return true; 6397 } 6398 return false; 6399 } 6400 6401 /** 6402 * Shows the context menu for this view. 6403 * 6404 * @return {@code true} if the context menu was shown, {@code false} 6405 * otherwise 6406 * @see #showContextMenu(float, float) 6407 */ 6408 public boolean showContextMenu() { 6409 return getParent().showContextMenuForChild(this); 6410 } 6411 6412 /** 6413 * Shows the context menu for this view anchored to the specified 6414 * view-relative coordinate. 6415 * 6416 * @param x the X coordinate in pixels relative to the view to which the 6417 * menu should be anchored, or {@link Float#NaN} to disable anchoring 6418 * @param y the Y coordinate in pixels relative to the view to which the 6419 * menu should be anchored, or {@link Float#NaN} to disable anchoring 6420 * @return {@code true} if the context menu was shown, {@code false} 6421 * otherwise 6422 */ 6423 public boolean showContextMenu(float x, float y) { 6424 return getParent().showContextMenuForChild(this, x, y); 6425 } 6426 6427 /** 6428 * Start an action mode with the default type {@link ActionMode#TYPE_PRIMARY}. 6429 * 6430 * @param callback Callback that will control the lifecycle of the action mode 6431 * @return The new action mode if it is started, null otherwise 6432 * 6433 * @see ActionMode 6434 * @see #startActionMode(android.view.ActionMode.Callback, int) 6435 */ 6436 public ActionMode startActionMode(ActionMode.Callback callback) { 6437 return startActionMode(callback, ActionMode.TYPE_PRIMARY); 6438 } 6439 6440 /** 6441 * Start an action mode with the given type. 6442 * 6443 * @param callback Callback that will control the lifecycle of the action mode 6444 * @param type One of {@link ActionMode#TYPE_PRIMARY} or {@link ActionMode#TYPE_FLOATING}. 6445 * @return The new action mode if it is started, null otherwise 6446 * 6447 * @see ActionMode 6448 */ 6449 public ActionMode startActionMode(ActionMode.Callback callback, int type) { 6450 ViewParent parent = getParent(); 6451 if (parent == null) return null; 6452 try { 6453 return parent.startActionModeForChild(this, callback, type); 6454 } catch (AbstractMethodError ame) { 6455 // Older implementations of custom views might not implement this. 6456 return parent.startActionModeForChild(this, callback); 6457 } 6458 } 6459 6460 /** 6461 * Call {@link Context#startActivityForResult(String, Intent, int, Bundle)} for the View's 6462 * Context, creating a unique View identifier to retrieve the result. 6463 * 6464 * @param intent The Intent to be started. 6465 * @param requestCode The request code to use. 6466 * @hide 6467 */ 6468 public void startActivityForResult(Intent intent, int requestCode) { 6469 mStartActivityRequestWho = "@android:view:" + System.identityHashCode(this); 6470 getContext().startActivityForResult(mStartActivityRequestWho, intent, requestCode, null); 6471 } 6472 6473 /** 6474 * If this View corresponds to the calling who, dispatches the activity result. 6475 * @param who The identifier for the targeted View to receive the result. 6476 * @param requestCode The integer request code originally supplied to 6477 * startActivityForResult(), allowing you to identify who this 6478 * result came from. 6479 * @param resultCode The integer result code returned by the child activity 6480 * through its setResult(). 6481 * @param data An Intent, which can return result data to the caller 6482 * (various data can be attached to Intent "extras"). 6483 * @return {@code true} if the activity result was dispatched. 6484 * @hide 6485 */ 6486 public boolean dispatchActivityResult( 6487 String who, int requestCode, int resultCode, Intent data) { 6488 if (mStartActivityRequestWho != null && mStartActivityRequestWho.equals(who)) { 6489 onActivityResult(requestCode, resultCode, data); 6490 mStartActivityRequestWho = null; 6491 return true; 6492 } 6493 return false; 6494 } 6495 6496 /** 6497 * Receive the result from a previous call to {@link #startActivityForResult(Intent, int)}. 6498 * 6499 * @param requestCode The integer request code originally supplied to 6500 * startActivityForResult(), allowing you to identify who this 6501 * result came from. 6502 * @param resultCode The integer result code returned by the child activity 6503 * through its setResult(). 6504 * @param data An Intent, which can return result data to the caller 6505 * (various data can be attached to Intent "extras"). 6506 * @hide 6507 */ 6508 public void onActivityResult(int requestCode, int resultCode, Intent data) { 6509 // Do nothing. 6510 } 6511 6512 /** 6513 * Register a callback to be invoked when a hardware key is pressed in this view. 6514 * Key presses in software input methods will generally not trigger the methods of 6515 * this listener. 6516 * @param l the key listener to attach to this view 6517 */ 6518 public void setOnKeyListener(OnKeyListener l) { 6519 getListenerInfo().mOnKeyListener = l; 6520 } 6521 6522 /** 6523 * Register a callback to be invoked when a touch event is sent to this view. 6524 * @param l the touch listener to attach to this view 6525 */ 6526 public void setOnTouchListener(OnTouchListener l) { 6527 getListenerInfo().mOnTouchListener = l; 6528 } 6529 6530 /** 6531 * Register a callback to be invoked when a generic motion event is sent to this view. 6532 * @param l the generic motion listener to attach to this view 6533 */ 6534 public void setOnGenericMotionListener(OnGenericMotionListener l) { 6535 getListenerInfo().mOnGenericMotionListener = l; 6536 } 6537 6538 /** 6539 * Register a callback to be invoked when a hover event is sent to this view. 6540 * @param l the hover listener to attach to this view 6541 */ 6542 public void setOnHoverListener(OnHoverListener l) { 6543 getListenerInfo().mOnHoverListener = l; 6544 } 6545 6546 /** 6547 * Register a drag event listener callback object for this View. The parameter is 6548 * an implementation of {@link android.view.View.OnDragListener}. To send a drag event to a 6549 * View, the system calls the 6550 * {@link android.view.View.OnDragListener#onDrag(View,DragEvent)} method. 6551 * @param l An implementation of {@link android.view.View.OnDragListener}. 6552 */ 6553 public void setOnDragListener(OnDragListener l) { 6554 getListenerInfo().mOnDragListener = l; 6555 } 6556 6557 /** 6558 * Give this view focus. This will cause 6559 * {@link #onFocusChanged(boolean, int, android.graphics.Rect)} to be called. 6560 * 6561 * Note: this does not check whether this {@link View} should get focus, it just 6562 * gives it focus no matter what. It should only be called internally by framework 6563 * code that knows what it is doing, namely {@link #requestFocus(int, Rect)}. 6564 * 6565 * @param direction values are {@link View#FOCUS_UP}, {@link View#FOCUS_DOWN}, 6566 * {@link View#FOCUS_LEFT} or {@link View#FOCUS_RIGHT}. This is the direction which 6567 * focus moved when requestFocus() is called. It may not always 6568 * apply, in which case use the default View.FOCUS_DOWN. 6569 * @param previouslyFocusedRect The rectangle of the view that had focus 6570 * prior in this View's coordinate system. 6571 */ 6572 void handleFocusGainInternal(@FocusRealDirection int direction, Rect previouslyFocusedRect) { 6573 if (DBG) { 6574 System.out.println(this + " requestFocus()"); 6575 } 6576 6577 if ((mPrivateFlags & PFLAG_FOCUSED) == 0) { 6578 mPrivateFlags |= PFLAG_FOCUSED; 6579 6580 View oldFocus = (mAttachInfo != null) ? getRootView().findFocus() : null; 6581 6582 if (mParent != null) { 6583 mParent.requestChildFocus(this, this); 6584 updateFocusedInCluster(oldFocus, direction); 6585 } 6586 6587 if (mAttachInfo != null) { 6588 mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(oldFocus, this); 6589 } 6590 6591 onFocusChanged(true, direction, previouslyFocusedRect); 6592 refreshDrawableState(); 6593 } 6594 } 6595 6596 /** 6597 * Sets this view's preference for reveal behavior when it gains focus. 6598 * 6599 * <p>When set to true, this is a signal to ancestor views in the hierarchy that 6600 * this view would prefer to be brought fully into view when it gains focus. 6601 * For example, a text field that a user is meant to type into. Other views such 6602 * as scrolling containers may prefer to opt-out of this behavior.</p> 6603 * 6604 * <p>The default value for views is true, though subclasses may change this 6605 * based on their preferred behavior.</p> 6606 * 6607 * @param revealOnFocus true to request reveal on focus in ancestors, false otherwise 6608 * 6609 * @see #getRevealOnFocusHint() 6610 */ 6611 public final void setRevealOnFocusHint(boolean revealOnFocus) { 6612 if (revealOnFocus) { 6613 mPrivateFlags3 &= ~PFLAG3_NO_REVEAL_ON_FOCUS; 6614 } else { 6615 mPrivateFlags3 |= PFLAG3_NO_REVEAL_ON_FOCUS; 6616 } 6617 } 6618 6619 /** 6620 * Returns this view's preference for reveal behavior when it gains focus. 6621 * 6622 * <p>When this method returns true for a child view requesting focus, ancestor 6623 * views responding to a focus change in {@link ViewParent#requestChildFocus(View, View)} 6624 * should make a best effort to make the newly focused child fully visible to the user. 6625 * When it returns false, ancestor views should preferably not disrupt scroll positioning or 6626 * other properties affecting visibility to the user as part of the focus change.</p> 6627 * 6628 * @return true if this view would prefer to become fully visible when it gains focus, 6629 * false if it would prefer not to disrupt scroll positioning 6630 * 6631 * @see #setRevealOnFocusHint(boolean) 6632 */ 6633 public final boolean getRevealOnFocusHint() { 6634 return (mPrivateFlags3 & PFLAG3_NO_REVEAL_ON_FOCUS) == 0; 6635 } 6636 6637 /** 6638 * Populates <code>outRect</code> with the hotspot bounds. By default, 6639 * the hotspot bounds are identical to the screen bounds. 6640 * 6641 * @param outRect rect to populate with hotspot bounds 6642 * @hide Only for internal use by views and widgets. 6643 */ 6644 public void getHotspotBounds(Rect outRect) { 6645 final Drawable background = getBackground(); 6646 if (background != null) { 6647 background.getHotspotBounds(outRect); 6648 } else { 6649 getBoundsOnScreen(outRect); 6650 } 6651 } 6652 6653 /** 6654 * Request that a rectangle of this view be visible on the screen, 6655 * scrolling if necessary just enough. 6656 * 6657 * <p>A View should call this if it maintains some notion of which part 6658 * of its content is interesting. For example, a text editing view 6659 * should call this when its cursor moves. 6660 * <p>The Rectangle passed into this method should be in the View's content coordinate space. 6661 * It should not be affected by which part of the View is currently visible or its scroll 6662 * position. 6663 * 6664 * @param rectangle The rectangle in the View's content coordinate space 6665 * @return Whether any parent scrolled. 6666 */ 6667 public boolean requestRectangleOnScreen(Rect rectangle) { 6668 return requestRectangleOnScreen(rectangle, false); 6669 } 6670 6671 /** 6672 * Request that a rectangle of this view be visible on the screen, 6673 * scrolling if necessary just enough. 6674 * 6675 * <p>A View should call this if it maintains some notion of which part 6676 * of its content is interesting. For example, a text editing view 6677 * should call this when its cursor moves. 6678 * <p>The Rectangle passed into this method should be in the View's content coordinate space. 6679 * It should not be affected by which part of the View is currently visible or its scroll 6680 * position. 6681 * <p>When <code>immediate</code> is set to true, scrolling will not be 6682 * animated. 6683 * 6684 * @param rectangle The rectangle in the View's content coordinate space 6685 * @param immediate True to forbid animated scrolling, false otherwise 6686 * @return Whether any parent scrolled. 6687 */ 6688 public boolean requestRectangleOnScreen(Rect rectangle, boolean immediate) { 6689 if (mParent == null) { 6690 return false; 6691 } 6692 6693 View child = this; 6694 6695 RectF position = (mAttachInfo != null) ? mAttachInfo.mTmpTransformRect : new RectF(); 6696 position.set(rectangle); 6697 6698 ViewParent parent = mParent; 6699 boolean scrolled = false; 6700 while (parent != null) { 6701 rectangle.set((int) position.left, (int) position.top, 6702 (int) position.right, (int) position.bottom); 6703 6704 scrolled |= parent.requestChildRectangleOnScreen(child, rectangle, immediate); 6705 6706 if (!(parent instanceof View)) { 6707 break; 6708 } 6709 6710 // move it from child's content coordinate space to parent's content coordinate space 6711 position.offset(child.mLeft - child.getScrollX(), child.mTop -child.getScrollY()); 6712 6713 child = (View) parent; 6714 parent = child.getParent(); 6715 } 6716 6717 return scrolled; 6718 } 6719 6720 /** 6721 * Called when this view wants to give up focus. If focus is cleared 6722 * {@link #onFocusChanged(boolean, int, android.graphics.Rect)} is called. 6723 * <p> 6724 * <strong>Note:</strong> When a View clears focus the framework is trying 6725 * to give focus to the first focusable View from the top. Hence, if this 6726 * View is the first from the top that can take focus, then all callbacks 6727 * related to clearing focus will be invoked after which the framework will 6728 * give focus to this view. 6729 * </p> 6730 */ 6731 public void clearFocus() { 6732 if (DBG) { 6733 System.out.println(this + " clearFocus()"); 6734 } 6735 6736 clearFocusInternal(null, true, true); 6737 } 6738 6739 /** 6740 * Clears focus from the view, optionally propagating the change up through 6741 * the parent hierarchy and requesting that the root view place new focus. 6742 * 6743 * @param propagate whether to propagate the change up through the parent 6744 * hierarchy 6745 * @param refocus when propagate is true, specifies whether to request the 6746 * root view place new focus 6747 */ 6748 void clearFocusInternal(View focused, boolean propagate, boolean refocus) { 6749 if ((mPrivateFlags & PFLAG_FOCUSED) != 0) { 6750 mPrivateFlags &= ~PFLAG_FOCUSED; 6751 6752 if (propagate && mParent != null) { 6753 mParent.clearChildFocus(this); 6754 } 6755 6756 onFocusChanged(false, 0, null); 6757 refreshDrawableState(); 6758 6759 if (propagate && (!refocus || !rootViewRequestFocus())) { 6760 notifyGlobalFocusCleared(this); 6761 } 6762 } 6763 } 6764 6765 void notifyGlobalFocusCleared(View oldFocus) { 6766 if (oldFocus != null && mAttachInfo != null) { 6767 mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(oldFocus, null); 6768 } 6769 } 6770 6771 boolean rootViewRequestFocus() { 6772 final View root = getRootView(); 6773 return root != null && root.requestFocus(); 6774 } 6775 6776 /** 6777 * Called internally by the view system when a new view is getting focus. 6778 * This is what clears the old focus. 6779 * <p> 6780 * <b>NOTE:</b> The parent view's focused child must be updated manually 6781 * after calling this method. Otherwise, the view hierarchy may be left in 6782 * an inconstent state. 6783 */ 6784 void unFocus(View focused) { 6785 if (DBG) { 6786 System.out.println(this + " unFocus()"); 6787 } 6788 6789 clearFocusInternal(focused, false, false); 6790 } 6791 6792 /** 6793 * Returns true if this view has focus itself, or is the ancestor of the 6794 * view that has focus. 6795 * 6796 * @return True if this view has or contains focus, false otherwise. 6797 */ 6798 @ViewDebug.ExportedProperty(category = "focus") 6799 public boolean hasFocus() { 6800 return (mPrivateFlags & PFLAG_FOCUSED) != 0; 6801 } 6802 6803 /** 6804 * Returns true if this view is focusable or if it contains a reachable View 6805 * for which {@link #hasFocusable()} returns {@code true}. A "reachable hasFocusable()" 6806 * is a view whose parents do not block descendants focus. 6807 * Only {@link #VISIBLE} views are considered focusable. 6808 * 6809 * <p>As of {@link Build.VERSION_CODES#O} views that are determined to be focusable 6810 * through {@link #FOCUSABLE_AUTO} will also cause this method to return {@code true}. 6811 * Apps that declare a {@link android.content.pm.ApplicationInfo#targetSdkVersion} of 6812 * earlier than {@link Build.VERSION_CODES#O} will continue to see this method return 6813 * {@code false} for views not explicitly marked as focusable. 6814 * Use {@link #hasExplicitFocusable()} if you require the pre-{@link Build.VERSION_CODES#O} 6815 * behavior.</p> 6816 * 6817 * @return {@code true} if the view is focusable or if the view contains a focusable 6818 * view, {@code false} otherwise 6819 * 6820 * @see ViewGroup#FOCUS_BLOCK_DESCENDANTS 6821 * @see ViewGroup#getTouchscreenBlocksFocus() 6822 * @see #hasExplicitFocusable() 6823 */ 6824 public boolean hasFocusable() { 6825 return hasFocusable(!sHasFocusableExcludeAutoFocusable, false); 6826 } 6827 6828 /** 6829 * Returns true if this view is focusable or if it contains a reachable View 6830 * for which {@link #hasExplicitFocusable()} returns {@code true}. 6831 * A "reachable hasExplicitFocusable()" is a view whose parents do not block descendants focus. 6832 * Only {@link #VISIBLE} views for which {@link #getFocusable()} would return 6833 * {@link #FOCUSABLE} are considered focusable. 6834 * 6835 * <p>This method preserves the pre-{@link Build.VERSION_CODES#O} behavior of 6836 * {@link #hasFocusable()} in that only views explicitly set focusable will cause 6837 * this method to return true. A view set to {@link #FOCUSABLE_AUTO} that resolves 6838 * to focusable will not.</p> 6839 * 6840 * @return {@code true} if the view is focusable or if the view contains a focusable 6841 * view, {@code false} otherwise 6842 * 6843 * @see #hasFocusable() 6844 */ 6845 public boolean hasExplicitFocusable() { 6846 return hasFocusable(false, true); 6847 } 6848 6849 boolean hasFocusable(boolean allowAutoFocus, boolean dispatchExplicit) { 6850 if (!isFocusableInTouchMode()) { 6851 for (ViewParent p = mParent; p instanceof ViewGroup; p = p.getParent()) { 6852 final ViewGroup g = (ViewGroup) p; 6853 if (g.shouldBlockFocusForTouchscreen()) { 6854 return false; 6855 } 6856 } 6857 } 6858 6859 // Invisible and gone views are never focusable. 6860 if ((mViewFlags & VISIBILITY_MASK) != VISIBLE) { 6861 return false; 6862 } 6863 6864 // Only use effective focusable value when allowed. 6865 if ((allowAutoFocus || getFocusable() != FOCUSABLE_AUTO) && isFocusable()) { 6866 return true; 6867 } 6868 6869 return false; 6870 } 6871 6872 /** 6873 * Called by the view system when the focus state of this view changes. 6874 * When the focus change event is caused by directional navigation, direction 6875 * and previouslyFocusedRect provide insight into where the focus is coming from. 6876 * When overriding, be sure to call up through to the super class so that 6877 * the standard focus handling will occur. 6878 * 6879 * @param gainFocus True if the View has focus; false otherwise. 6880 * @param direction The direction focus has moved when requestFocus() 6881 * is called to give this view focus. Values are 6882 * {@link #FOCUS_UP}, {@link #FOCUS_DOWN}, {@link #FOCUS_LEFT}, 6883 * {@link #FOCUS_RIGHT}, {@link #FOCUS_FORWARD}, or {@link #FOCUS_BACKWARD}. 6884 * It may not always apply, in which case use the default. 6885 * @param previouslyFocusedRect The rectangle, in this view's coordinate 6886 * system, of the previously focused view. If applicable, this will be 6887 * passed in as finer grained information about where the focus is coming 6888 * from (in addition to direction). Will be <code>null</code> otherwise. 6889 */ 6890 @CallSuper 6891 protected void onFocusChanged(boolean gainFocus, @FocusDirection int direction, 6892 @Nullable Rect previouslyFocusedRect) { 6893 if (gainFocus) { 6894 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED); 6895 } else { 6896 notifyViewAccessibilityStateChangedIfNeeded( 6897 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 6898 } 6899 6900 // Here we check whether we still need the default focus highlight, and switch it on/off. 6901 switchDefaultFocusHighlight(); 6902 6903 InputMethodManager imm = InputMethodManager.peekInstance(); 6904 if (!gainFocus) { 6905 if (isPressed()) { 6906 setPressed(false); 6907 } 6908 if (imm != null && mAttachInfo != null && mAttachInfo.mHasWindowFocus) { 6909 imm.focusOut(this); 6910 } 6911 onFocusLost(); 6912 } else if (imm != null && mAttachInfo != null && mAttachInfo.mHasWindowFocus) { 6913 imm.focusIn(this); 6914 } 6915 6916 invalidate(true); 6917 ListenerInfo li = mListenerInfo; 6918 if (li != null && li.mOnFocusChangeListener != null) { 6919 li.mOnFocusChangeListener.onFocusChange(this, gainFocus); 6920 } 6921 6922 if (mAttachInfo != null) { 6923 mAttachInfo.mKeyDispatchState.reset(this); 6924 } 6925 6926 notifyEnterOrExitForAutoFillIfNeeded(gainFocus); 6927 } 6928 6929 private void notifyEnterOrExitForAutoFillIfNeeded(boolean enter) { 6930 if (isAutofillable() && isAttachedToWindow()) { 6931 AutofillManager afm = getAutofillManager(); 6932 if (afm != null) { 6933 if (enter && hasWindowFocus() && isFocused()) { 6934 // We have not been laid out yet, hence cannot evaluate 6935 // whether this view is visible to the user, we will do 6936 // the evaluation once layout is complete. 6937 if (!isLaidOut()) { 6938 mPrivateFlags3 |= PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT; 6939 } else if (isVisibleToUser()) { 6940 afm.notifyViewEntered(this); 6941 } 6942 } else if (!hasWindowFocus() || !isFocused()) { 6943 afm.notifyViewExited(this); 6944 } 6945 } 6946 } 6947 } 6948 6949 /** 6950 * Sends an accessibility event of the given type. If accessibility is 6951 * not enabled this method has no effect. The default implementation calls 6952 * {@link #onInitializeAccessibilityEvent(AccessibilityEvent)} first 6953 * to populate information about the event source (this View), then calls 6954 * {@link #dispatchPopulateAccessibilityEvent(AccessibilityEvent)} to 6955 * populate the text content of the event source including its descendants, 6956 * and last calls 6957 * {@link ViewParent#requestSendAccessibilityEvent(View, AccessibilityEvent)} 6958 * on its parent to request sending of the event to interested parties. 6959 * <p> 6960 * If an {@link AccessibilityDelegate} has been specified via calling 6961 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 6962 * {@link AccessibilityDelegate#sendAccessibilityEvent(View, int)} is 6963 * responsible for handling this call. 6964 * </p> 6965 * 6966 * @param eventType The type of the event to send, as defined by several types from 6967 * {@link android.view.accessibility.AccessibilityEvent}, such as 6968 * {@link android.view.accessibility.AccessibilityEvent#TYPE_VIEW_CLICKED} or 6969 * {@link android.view.accessibility.AccessibilityEvent#TYPE_VIEW_HOVER_ENTER}. 6970 * 6971 * @see #onInitializeAccessibilityEvent(AccessibilityEvent) 6972 * @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent) 6973 * @see ViewParent#requestSendAccessibilityEvent(View, AccessibilityEvent) 6974 * @see AccessibilityDelegate 6975 */ 6976 public void sendAccessibilityEvent(int eventType) { 6977 if (mAccessibilityDelegate != null) { 6978 mAccessibilityDelegate.sendAccessibilityEvent(this, eventType); 6979 } else { 6980 sendAccessibilityEventInternal(eventType); 6981 } 6982 } 6983 6984 /** 6985 * Convenience method for sending a {@link AccessibilityEvent#TYPE_ANNOUNCEMENT} 6986 * {@link AccessibilityEvent} to make an announcement which is related to some 6987 * sort of a context change for which none of the events representing UI transitions 6988 * is a good fit. For example, announcing a new page in a book. If accessibility 6989 * is not enabled this method does nothing. 6990 * 6991 * @param text The announcement text. 6992 */ 6993 public void announceForAccessibility(CharSequence text) { 6994 if (AccessibilityManager.getInstance(mContext).isEnabled() && mParent != null) { 6995 AccessibilityEvent event = AccessibilityEvent.obtain( 6996 AccessibilityEvent.TYPE_ANNOUNCEMENT); 6997 onInitializeAccessibilityEvent(event); 6998 event.getText().add(text); 6999 event.setContentDescription(null); 7000 mParent.requestSendAccessibilityEvent(this, event); 7001 } 7002 } 7003 7004 /** 7005 * @see #sendAccessibilityEvent(int) 7006 * 7007 * Note: Called from the default {@link AccessibilityDelegate}. 7008 * 7009 * @hide 7010 */ 7011 public void sendAccessibilityEventInternal(int eventType) { 7012 if (AccessibilityManager.getInstance(mContext).isEnabled()) { 7013 sendAccessibilityEventUnchecked(AccessibilityEvent.obtain(eventType)); 7014 } 7015 } 7016 7017 /** 7018 * This method behaves exactly as {@link #sendAccessibilityEvent(int)} but 7019 * takes as an argument an empty {@link AccessibilityEvent} and does not 7020 * perform a check whether accessibility is enabled. 7021 * <p> 7022 * If an {@link AccessibilityDelegate} has been specified via calling 7023 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 7024 * {@link AccessibilityDelegate#sendAccessibilityEventUnchecked(View, AccessibilityEvent)} 7025 * is responsible for handling this call. 7026 * </p> 7027 * 7028 * @param event The event to send. 7029 * 7030 * @see #sendAccessibilityEvent(int) 7031 */ 7032 public void sendAccessibilityEventUnchecked(AccessibilityEvent event) { 7033 if (mAccessibilityDelegate != null) { 7034 mAccessibilityDelegate.sendAccessibilityEventUnchecked(this, event); 7035 } else { 7036 sendAccessibilityEventUncheckedInternal(event); 7037 } 7038 } 7039 7040 /** 7041 * @see #sendAccessibilityEventUnchecked(AccessibilityEvent) 7042 * 7043 * Note: Called from the default {@link AccessibilityDelegate}. 7044 * 7045 * @hide 7046 */ 7047 public void sendAccessibilityEventUncheckedInternal(AccessibilityEvent event) { 7048 if (!isShown()) { 7049 return; 7050 } 7051 onInitializeAccessibilityEvent(event); 7052 // Only a subset of accessibility events populates text content. 7053 if ((event.getEventType() & POPULATING_ACCESSIBILITY_EVENT_TYPES) != 0) { 7054 dispatchPopulateAccessibilityEvent(event); 7055 } 7056 // In the beginning we called #isShown(), so we know that getParent() is not null. 7057 ViewParent parent = getParent(); 7058 if (parent != null) { 7059 getParent().requestSendAccessibilityEvent(this, event); 7060 } 7061 } 7062 7063 /** 7064 * Dispatches an {@link AccessibilityEvent} to the {@link View} first and then 7065 * to its children for adding their text content to the event. Note that the 7066 * event text is populated in a separate dispatch path since we add to the 7067 * event not only the text of the source but also the text of all its descendants. 7068 * A typical implementation will call 7069 * {@link #onPopulateAccessibilityEvent(AccessibilityEvent)} on the this view 7070 * and then call the {@link #dispatchPopulateAccessibilityEvent(AccessibilityEvent)} 7071 * on each child. Override this method if custom population of the event text 7072 * content is required. 7073 * <p> 7074 * If an {@link AccessibilityDelegate} has been specified via calling 7075 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 7076 * {@link AccessibilityDelegate#dispatchPopulateAccessibilityEvent(View, AccessibilityEvent)} 7077 * is responsible for handling this call. 7078 * </p> 7079 * <p> 7080 * <em>Note:</em> Accessibility events of certain types are not dispatched for 7081 * populating the event text via this method. For details refer to {@link AccessibilityEvent}. 7082 * </p> 7083 * 7084 * @param event The event. 7085 * 7086 * @return True if the event population was completed. 7087 */ 7088 public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) { 7089 if (mAccessibilityDelegate != null) { 7090 return mAccessibilityDelegate.dispatchPopulateAccessibilityEvent(this, event); 7091 } else { 7092 return dispatchPopulateAccessibilityEventInternal(event); 7093 } 7094 } 7095 7096 /** 7097 * @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent) 7098 * 7099 * Note: Called from the default {@link AccessibilityDelegate}. 7100 * 7101 * @hide 7102 */ 7103 public boolean dispatchPopulateAccessibilityEventInternal(AccessibilityEvent event) { 7104 onPopulateAccessibilityEvent(event); 7105 return false; 7106 } 7107 7108 /** 7109 * Called from {@link #dispatchPopulateAccessibilityEvent(AccessibilityEvent)} 7110 * giving a chance to this View to populate the accessibility event with its 7111 * text content. While this method is free to modify event 7112 * attributes other than text content, doing so should normally be performed in 7113 * {@link #onInitializeAccessibilityEvent(AccessibilityEvent)}. 7114 * <p> 7115 * Example: Adding formatted date string to an accessibility event in addition 7116 * to the text added by the super implementation: 7117 * <pre> public void onPopulateAccessibilityEvent(AccessibilityEvent event) { 7118 * super.onPopulateAccessibilityEvent(event); 7119 * final int flags = DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_WEEKDAY; 7120 * String selectedDateUtterance = DateUtils.formatDateTime(mContext, 7121 * mCurrentDate.getTimeInMillis(), flags); 7122 * event.getText().add(selectedDateUtterance); 7123 * }</pre> 7124 * <p> 7125 * If an {@link AccessibilityDelegate} has been specified via calling 7126 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 7127 * {@link AccessibilityDelegate#onPopulateAccessibilityEvent(View, AccessibilityEvent)} 7128 * is responsible for handling this call. 7129 * </p> 7130 * <p class="note"><strong>Note:</strong> Always call the super implementation before adding 7131 * information to the event, in case the default implementation has basic information to add. 7132 * </p> 7133 * 7134 * @param event The accessibility event which to populate. 7135 * 7136 * @see #sendAccessibilityEvent(int) 7137 * @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent) 7138 */ 7139 @CallSuper 7140 public void onPopulateAccessibilityEvent(AccessibilityEvent event) { 7141 if (mAccessibilityDelegate != null) { 7142 mAccessibilityDelegate.onPopulateAccessibilityEvent(this, event); 7143 } else { 7144 onPopulateAccessibilityEventInternal(event); 7145 } 7146 } 7147 7148 /** 7149 * @see #onPopulateAccessibilityEvent(AccessibilityEvent) 7150 * 7151 * Note: Called from the default {@link AccessibilityDelegate}. 7152 * 7153 * @hide 7154 */ 7155 public void onPopulateAccessibilityEventInternal(AccessibilityEvent event) { 7156 } 7157 7158 /** 7159 * Initializes an {@link AccessibilityEvent} with information about 7160 * this View which is the event source. In other words, the source of 7161 * an accessibility event is the view whose state change triggered firing 7162 * the event. 7163 * <p> 7164 * Example: Setting the password property of an event in addition 7165 * to properties set by the super implementation: 7166 * <pre> public void onInitializeAccessibilityEvent(AccessibilityEvent event) { 7167 * super.onInitializeAccessibilityEvent(event); 7168 * event.setPassword(true); 7169 * }</pre> 7170 * <p> 7171 * If an {@link AccessibilityDelegate} has been specified via calling 7172 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 7173 * {@link AccessibilityDelegate#onInitializeAccessibilityEvent(View, AccessibilityEvent)} 7174 * is responsible for handling this call. 7175 * </p> 7176 * <p class="note"><strong>Note:</strong> Always call the super implementation before adding 7177 * information to the event, in case the default implementation has basic information to add. 7178 * </p> 7179 * @param event The event to initialize. 7180 * 7181 * @see #sendAccessibilityEvent(int) 7182 * @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent) 7183 */ 7184 @CallSuper 7185 public void onInitializeAccessibilityEvent(AccessibilityEvent event) { 7186 if (mAccessibilityDelegate != null) { 7187 mAccessibilityDelegate.onInitializeAccessibilityEvent(this, event); 7188 } else { 7189 onInitializeAccessibilityEventInternal(event); 7190 } 7191 } 7192 7193 /** 7194 * @see #onInitializeAccessibilityEvent(AccessibilityEvent) 7195 * 7196 * Note: Called from the default {@link AccessibilityDelegate}. 7197 * 7198 * @hide 7199 */ 7200 public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) { 7201 event.setSource(this); 7202 event.setClassName(getAccessibilityClassName()); 7203 event.setPackageName(getContext().getPackageName()); 7204 event.setEnabled(isEnabled()); 7205 event.setContentDescription(mContentDescription); 7206 7207 switch (event.getEventType()) { 7208 case AccessibilityEvent.TYPE_VIEW_FOCUSED: { 7209 ArrayList<View> focusablesTempList = (mAttachInfo != null) 7210 ? mAttachInfo.mTempArrayList : new ArrayList<View>(); 7211 getRootView().addFocusables(focusablesTempList, View.FOCUS_FORWARD, FOCUSABLES_ALL); 7212 event.setItemCount(focusablesTempList.size()); 7213 event.setCurrentItemIndex(focusablesTempList.indexOf(this)); 7214 if (mAttachInfo != null) { 7215 focusablesTempList.clear(); 7216 } 7217 } break; 7218 case AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED: { 7219 CharSequence text = getIterableTextForAccessibility(); 7220 if (text != null && text.length() > 0) { 7221 event.setFromIndex(getAccessibilitySelectionStart()); 7222 event.setToIndex(getAccessibilitySelectionEnd()); 7223 event.setItemCount(text.length()); 7224 } 7225 } break; 7226 } 7227 } 7228 7229 /** 7230 * Returns an {@link AccessibilityNodeInfo} representing this view from the 7231 * point of view of an {@link android.accessibilityservice.AccessibilityService}. 7232 * This method is responsible for obtaining an accessibility node info from a 7233 * pool of reusable instances and calling 7234 * {@link #onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} on this view to 7235 * initialize the former. 7236 * <p> 7237 * Note: The client is responsible for recycling the obtained instance by calling 7238 * {@link AccessibilityNodeInfo#recycle()} to minimize object creation. 7239 * </p> 7240 * 7241 * @return A populated {@link AccessibilityNodeInfo}. 7242 * 7243 * @see AccessibilityNodeInfo 7244 */ 7245 public AccessibilityNodeInfo createAccessibilityNodeInfo() { 7246 if (mAccessibilityDelegate != null) { 7247 return mAccessibilityDelegate.createAccessibilityNodeInfo(this); 7248 } else { 7249 return createAccessibilityNodeInfoInternal(); 7250 } 7251 } 7252 7253 /** 7254 * @see #createAccessibilityNodeInfo() 7255 * 7256 * @hide 7257 */ 7258 public AccessibilityNodeInfo createAccessibilityNodeInfoInternal() { 7259 AccessibilityNodeProvider provider = getAccessibilityNodeProvider(); 7260 if (provider != null) { 7261 return provider.createAccessibilityNodeInfo(AccessibilityNodeProvider.HOST_VIEW_ID); 7262 } else { 7263 AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain(this); 7264 onInitializeAccessibilityNodeInfo(info); 7265 return info; 7266 } 7267 } 7268 7269 /** 7270 * Initializes an {@link AccessibilityNodeInfo} with information about this view. 7271 * The base implementation sets: 7272 * <ul> 7273 * <li>{@link AccessibilityNodeInfo#setParent(View)},</li> 7274 * <li>{@link AccessibilityNodeInfo#setBoundsInParent(Rect)},</li> 7275 * <li>{@link AccessibilityNodeInfo#setBoundsInScreen(Rect)},</li> 7276 * <li>{@link AccessibilityNodeInfo#setPackageName(CharSequence)},</li> 7277 * <li>{@link AccessibilityNodeInfo#setClassName(CharSequence)},</li> 7278 * <li>{@link AccessibilityNodeInfo#setContentDescription(CharSequence)},</li> 7279 * <li>{@link AccessibilityNodeInfo#setEnabled(boolean)},</li> 7280 * <li>{@link AccessibilityNodeInfo#setClickable(boolean)},</li> 7281 * <li>{@link AccessibilityNodeInfo#setFocusable(boolean)},</li> 7282 * <li>{@link AccessibilityNodeInfo#setFocused(boolean)},</li> 7283 * <li>{@link AccessibilityNodeInfo#setLongClickable(boolean)},</li> 7284 * <li>{@link AccessibilityNodeInfo#setSelected(boolean)},</li> 7285 * <li>{@link AccessibilityNodeInfo#setContextClickable(boolean)}</li> 7286 * </ul> 7287 * <p> 7288 * Subclasses should override this method, call the super implementation, 7289 * and set additional attributes. 7290 * </p> 7291 * <p> 7292 * If an {@link AccessibilityDelegate} has been specified via calling 7293 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 7294 * {@link AccessibilityDelegate#onInitializeAccessibilityNodeInfo(View, AccessibilityNodeInfo)} 7295 * is responsible for handling this call. 7296 * </p> 7297 * 7298 * @param info The instance to initialize. 7299 */ 7300 @CallSuper 7301 public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { 7302 if (mAccessibilityDelegate != null) { 7303 mAccessibilityDelegate.onInitializeAccessibilityNodeInfo(this, info); 7304 } else { 7305 onInitializeAccessibilityNodeInfoInternal(info); 7306 } 7307 } 7308 7309 /** 7310 * Gets the location of this view in screen coordinates. 7311 * 7312 * @param outRect The output location 7313 * @hide 7314 */ 7315 public void getBoundsOnScreen(Rect outRect) { 7316 getBoundsOnScreen(outRect, false); 7317 } 7318 7319 /** 7320 * Gets the location of this view in screen coordinates. 7321 * 7322 * @param outRect The output location 7323 * @param clipToParent Whether to clip child bounds to the parent ones. 7324 * @hide 7325 */ 7326 public void getBoundsOnScreen(Rect outRect, boolean clipToParent) { 7327 if (mAttachInfo == null) { 7328 return; 7329 } 7330 7331 RectF position = mAttachInfo.mTmpTransformRect; 7332 position.set(0, 0, mRight - mLeft, mBottom - mTop); 7333 mapRectFromViewToScreenCoords(position, clipToParent); 7334 outRect.set(Math.round(position.left), Math.round(position.top), 7335 Math.round(position.right), Math.round(position.bottom)); 7336 } 7337 7338 /** 7339 * Map a rectangle from view-relative coordinates to screen-relative coordinates 7340 * 7341 * @param rect The rectangle to be mapped 7342 * @param clipToParent Whether to clip child bounds to the parent ones. 7343 * @hide 7344 */ 7345 public void mapRectFromViewToScreenCoords(RectF rect, boolean clipToParent) { 7346 if (!hasIdentityMatrix()) { 7347 getMatrix().mapRect(rect); 7348 } 7349 7350 rect.offset(mLeft, mTop); 7351 7352 ViewParent parent = mParent; 7353 while (parent instanceof View) { 7354 View parentView = (View) parent; 7355 7356 rect.offset(-parentView.mScrollX, -parentView.mScrollY); 7357 7358 if (clipToParent) { 7359 rect.left = Math.max(rect.left, 0); 7360 rect.top = Math.max(rect.top, 0); 7361 rect.right = Math.min(rect.right, parentView.getWidth()); 7362 rect.bottom = Math.min(rect.bottom, parentView.getHeight()); 7363 } 7364 7365 if (!parentView.hasIdentityMatrix()) { 7366 parentView.getMatrix().mapRect(rect); 7367 } 7368 7369 rect.offset(parentView.mLeft, parentView.mTop); 7370 7371 parent = parentView.mParent; 7372 } 7373 7374 if (parent instanceof ViewRootImpl) { 7375 ViewRootImpl viewRootImpl = (ViewRootImpl) parent; 7376 rect.offset(0, -viewRootImpl.mCurScrollY); 7377 } 7378 7379 rect.offset(mAttachInfo.mWindowLeft, mAttachInfo.mWindowTop); 7380 } 7381 7382 /** 7383 * Return the class name of this object to be used for accessibility purposes. 7384 * Subclasses should only override this if they are implementing something that 7385 * should be seen as a completely new class of view when used by accessibility, 7386 * unrelated to the class it is deriving from. This is used to fill in 7387 * {@link AccessibilityNodeInfo#setClassName AccessibilityNodeInfo.setClassName}. 7388 */ 7389 public CharSequence getAccessibilityClassName() { 7390 return View.class.getName(); 7391 } 7392 7393 /** 7394 * Called when assist structure is being retrieved from a view as part of 7395 * {@link android.app.Activity#onProvideAssistData Activity.onProvideAssistData}. 7396 * @param structure Fill in with structured view data. The default implementation 7397 * fills in all data that can be inferred from the view itself. 7398 */ 7399 public void onProvideStructure(ViewStructure structure) { 7400 onProvideStructureForAssistOrAutofill(structure, false, 0); 7401 } 7402 7403 /** 7404 * Populates a {@link ViewStructure} to fullfil an autofill request. 7405 * 7406 * <p>The structure should contain at least the following properties: 7407 * <ul> 7408 * <li>Autofill id ({@link ViewStructure#setAutofillId(AutofillId, int)}). 7409 * <li>Autofill type ({@link ViewStructure#setAutofillType(int)}). 7410 * <li>Autofill value ({@link ViewStructure#setAutofillValue(AutofillValue)}). 7411 * <li>Whether the data is sensitive ({@link ViewStructure#setDataIsSensitive(boolean)}). 7412 * </ul> 7413 * 7414 * <p>It's also recommended to set the following properties - the more properties the structure 7415 * has, the higher the changes of an {@link android.service.autofill.AutofillService} properly 7416 * using the structure: 7417 * 7418 * <ul> 7419 * <li>Autofill hints ({@link ViewStructure#setAutofillHints(String[])}). 7420 * <li>Autofill options ({@link ViewStructure#setAutofillOptions(CharSequence[])}) when the 7421 * view can only be filled with predefined values (typically used when the autofill type 7422 * is {@link #AUTOFILL_TYPE_LIST}). 7423 * <li>Resource id ({@link ViewStructure#setId(int, String, String, String)}). 7424 * <li>Class name ({@link ViewStructure#setClassName(String)}). 7425 * <li>Content description ({@link ViewStructure#setContentDescription(CharSequence)}). 7426 * <li>Visual properties such as visibility ({@link ViewStructure#setVisibility(int)}), 7427 * dimensions ({@link ViewStructure#setDimens(int, int, int, int, int, int)}), and 7428 * opacity ({@link ViewStructure#setOpaque(boolean)}). 7429 * <li>For views representing text fields, text properties such as the text itself 7430 * ({@link ViewStructure#setText(CharSequence)}), text hints 7431 * ({@link ViewStructure#setHint(CharSequence)}, input type 7432 * ({@link ViewStructure#setInputType(int)}), 7433 * <li>For views representing HTML nodes, its web domain 7434 * ({@link ViewStructure#setWebDomain(String)}) and HTML properties 7435 * (({@link ViewStructure#setHtmlInfo(android.view.ViewStructure.HtmlInfo)}). 7436 * </ul> 7437 * 7438 * <p>The default implementation of this method already sets most of these properties based on 7439 * related {@link View} methods (for example, the autofill id is set using 7440 * {@link #getAutofillId()}, the autofill type set using {@link #getAutofillType()}, etc.), 7441 * and views in the standard Android widgets library also override it to set their 7442 * relevant properties (for example, {@link android.widget.TextView} already sets the text 7443 * properties), so it's recommended to only override this method 7444 * (and call {@code super.onProvideAutofillStructure()}) when: 7445 * 7446 * <ul> 7447 * <li>The view contents does not include PII (Personally Identifiable Information), so it 7448 * can call {@link ViewStructure#setDataIsSensitive(boolean)} passing {@code false}. 7449 * <li>The view can only be autofilled with predefined options, so it can call 7450 * {@link ViewStructure#setAutofillOptions(CharSequence[])}. 7451 * </ul> 7452 * 7453 * <p><b>NOTE:</b> the {@code left} and {@code top} values set in 7454 * {@link ViewStructure#setDimens(int, int, int, int, int, int)} must be relative to the next 7455 * {@link ViewGroup#isImportantForAutofill()} predecessor view included in the structure. 7456 * 7457 * <p>Views support the Autofill Framework mainly by: 7458 * <ul> 7459 * <li>Providing the metadata defining what the view means and how it can be autofilled. 7460 * <li>Notifying the Android System when the view value changed by calling 7461 * {@link AutofillManager#notifyValueChanged(View)}. 7462 * <li>Implementing the methods that autofill the view. 7463 * </ul> 7464 * <p>This method is responsible for the former; {@link #autofill(AutofillValue)} is responsible 7465 * for the latter. 7466 * 7467 * @param structure fill in with structured view data for autofill purposes. 7468 * @param flags optional flags. 7469 * 7470 * @see #AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS 7471 */ 7472 public void onProvideAutofillStructure(ViewStructure structure, @AutofillFlags int flags) { 7473 onProvideStructureForAssistOrAutofill(structure, true, flags); 7474 } 7475 7476 private void onProvideStructureForAssistOrAutofill(ViewStructure structure, 7477 boolean forAutofill, @AutofillFlags int flags) { 7478 final int id = mID; 7479 if (id != NO_ID && !isViewIdGenerated(id)) { 7480 String pkg, type, entry; 7481 try { 7482 final Resources res = getResources(); 7483 entry = res.getResourceEntryName(id); 7484 type = res.getResourceTypeName(id); 7485 pkg = res.getResourcePackageName(id); 7486 } catch (Resources.NotFoundException e) { 7487 entry = type = pkg = null; 7488 } 7489 structure.setId(id, pkg, type, entry); 7490 } else { 7491 structure.setId(id, null, null, null); 7492 } 7493 7494 if (forAutofill) { 7495 final @AutofillType int autofillType = getAutofillType(); 7496 // Don't need to fill autofill info if view does not support it. 7497 // For example, only TextViews that are editable support autofill 7498 if (autofillType != AUTOFILL_TYPE_NONE) { 7499 structure.setAutofillType(autofillType); 7500 structure.setAutofillHints(getAutofillHints()); 7501 structure.setAutofillValue(getAutofillValue()); 7502 } 7503 } 7504 7505 int ignoredParentLeft = 0; 7506 int ignoredParentTop = 0; 7507 if (forAutofill && (flags & AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS) == 0) { 7508 View parentGroup = null; 7509 7510 ViewParent viewParent = getParent(); 7511 if (viewParent instanceof View) { 7512 parentGroup = (View) viewParent; 7513 } 7514 7515 while (parentGroup != null && !parentGroup.isImportantForAutofill()) { 7516 ignoredParentLeft += parentGroup.mLeft; 7517 ignoredParentTop += parentGroup.mTop; 7518 7519 viewParent = parentGroup.getParent(); 7520 if (viewParent instanceof View) { 7521 parentGroup = (View) viewParent; 7522 } else { 7523 break; 7524 } 7525 } 7526 } 7527 7528 structure.setDimens(ignoredParentLeft + mLeft, ignoredParentTop + mTop, mScrollX, mScrollY, 7529 mRight - mLeft, mBottom - mTop); 7530 if (!forAutofill) { 7531 if (!hasIdentityMatrix()) { 7532 structure.setTransformation(getMatrix()); 7533 } 7534 structure.setElevation(getZ()); 7535 } 7536 structure.setVisibility(getVisibility()); 7537 structure.setEnabled(isEnabled()); 7538 if (isClickable()) { 7539 structure.setClickable(true); 7540 } 7541 if (isFocusable()) { 7542 structure.setFocusable(true); 7543 } 7544 if (isFocused()) { 7545 structure.setFocused(true); 7546 } 7547 if (isAccessibilityFocused()) { 7548 structure.setAccessibilityFocused(true); 7549 } 7550 if (isSelected()) { 7551 structure.setSelected(true); 7552 } 7553 if (isActivated()) { 7554 structure.setActivated(true); 7555 } 7556 if (isLongClickable()) { 7557 structure.setLongClickable(true); 7558 } 7559 if (this instanceof Checkable) { 7560 structure.setCheckable(true); 7561 if (((Checkable)this).isChecked()) { 7562 structure.setChecked(true); 7563 } 7564 } 7565 if (isOpaque()) { 7566 structure.setOpaque(true); 7567 } 7568 if (isContextClickable()) { 7569 structure.setContextClickable(true); 7570 } 7571 structure.setClassName(getAccessibilityClassName().toString()); 7572 structure.setContentDescription(getContentDescription()); 7573 } 7574 7575 /** 7576 * Called when assist structure is being retrieved from a view as part of 7577 * {@link android.app.Activity#onProvideAssistData Activity.onProvideAssistData} to 7578 * generate additional virtual structure under this view. The defaullt implementation 7579 * uses {@link #getAccessibilityNodeProvider()} to try to generate this from the 7580 * view's virtual accessibility nodes, if any. You can override this for a more 7581 * optimal implementation providing this data. 7582 */ 7583 public void onProvideVirtualStructure(ViewStructure structure) { 7584 AccessibilityNodeProvider provider = getAccessibilityNodeProvider(); 7585 if (provider != null) { 7586 AccessibilityNodeInfo info = createAccessibilityNodeInfo(); 7587 structure.setChildCount(1); 7588 ViewStructure root = structure.newChild(0); 7589 populateVirtualStructure(root, provider, info); 7590 info.recycle(); 7591 } 7592 } 7593 7594 /** 7595 * Populates a {@link ViewStructure} containing virtual children to fullfil an autofill 7596 * request. 7597 * 7598 * <p>This method should be used when the view manages a virtual structure under this view. For 7599 * example, a view that draws input fields using {@link #draw(Canvas)}. 7600 * 7601 * <p>When implementing this method, subclasses must follow the rules below: 7602 * 7603 * <ul> 7604 * <li>Add virtual children by calling the {@link ViewStructure#newChild(int)} or 7605 * {@link ViewStructure#asyncNewChild(int)} methods, where the {@code id} is an unique id 7606 * identifying the children in the virtual structure. 7607 * <li>The children hierarchy can have multiple levels if necessary, but ideally it should 7608 * exclude intermediate levels that are irrelevant for autofill; that would improve the 7609 * autofill performance. 7610 * <li>Also implement {@link #autofill(SparseArray)} to autofill the virtual 7611 * children. 7612 * <li>Set the autofill properties of the child structure as defined by 7613 * {@link #onProvideAutofillStructure(ViewStructure, int)}, using 7614 * {@link ViewStructure#setAutofillId(AutofillId, int)} to set its autofill id. 7615 * <li>Call {@link android.view.autofill.AutofillManager#notifyViewEntered(View, int, Rect)} 7616 * and/or {@link android.view.autofill.AutofillManager#notifyViewExited(View, int)} 7617 * when the focused virtual child changed. 7618 * <li>Call 7619 * {@link android.view.autofill.AutofillManager#notifyValueChanged(View, int, AutofillValue)} 7620 * when the value of a virtual child changed. 7621 * <li>Call {@link AutofillManager#commit()} when the autofill context of the view structure 7622 * changed and the current context should be committed (for example, when the user tapped 7623 * a {@code SUBMIT} button in an HTML page). 7624 * <li>Call {@link AutofillManager#cancel()} when the autofill context of the view structure 7625 * changed and the current context should be canceled (for example, when the user tapped 7626 * a {@code CANCEL} button in an HTML page). 7627 * <li>Provide ways for users to manually request autofill by calling 7628 * {@link AutofillManager#requestAutofill(View, int, Rect)}. 7629 * <li>The {@code left} and {@code top} values set in 7630 * {@link ViewStructure#setDimens(int, int, int, int, int, int)} must be relative to the 7631 * next {@link ViewGroup#isImportantForAutofill()} predecessor view included in the 7632 * structure. 7633 * </ul> 7634 * 7635 * <p>Views with virtual children support the Autofill Framework mainly by: 7636 * <ul> 7637 * <li>Providing the metadata defining what the virtual children mean and how they can be 7638 * autofilled. 7639 * <li>Implementing the methods that autofill the virtual children. 7640 * </ul> 7641 * <p>This method is responsible for the former; {@link #autofill(SparseArray)} is responsible 7642 * for the latter. 7643 * 7644 * @param structure fill in with virtual children data for autofill purposes. 7645 * @param flags optional flags. 7646 * 7647 * @see #AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS 7648 */ 7649 public void onProvideAutofillVirtualStructure(ViewStructure structure, int flags) { 7650 } 7651 7652 /** 7653 * Automatically fills the content of this view with the {@code value}. 7654 * 7655 * <p>Views support the Autofill Framework mainly by: 7656 * <ul> 7657 * <li>Providing the metadata defining what the view means and how it can be autofilled. 7658 * <li>Implementing the methods that autofill the view. 7659 * </ul> 7660 * <p>{@link #onProvideAutofillStructure(ViewStructure, int)} is responsible for the former, 7661 * this method is responsible for latter. 7662 * 7663 * <p>This method does nothing by default, but when overridden it typically: 7664 * <ol> 7665 * <li>Checks if the provided value matches the expected type (which is defined by 7666 * {@link #getAutofillType()}). 7667 * <li>Checks if the view is editable - if it isn't, it should return right away. 7668 * <li>Call the proper getter method on {@link AutofillValue} to fetch the actual value. 7669 * <li>Pass the actual value to the equivalent setter in the view. 7670 * </ol> 7671 * 7672 * <p>For example, a text-field view could implement the method this way: 7673 * 7674 * <pre class="prettyprint"> 7675 * @Override 7676 * public void autofill(AutofillValue value) { 7677 * if (!value.isText() || !this.isEditable()) { 7678 * return; 7679 * } 7680 * CharSequence text = value.getTextValue(); 7681 * if (text != null) { 7682 * this.setText(text); 7683 * } 7684 * } 7685 * </pre> 7686 * 7687 * <p>If the value is updated asynchronously, the next call to 7688 * {@link AutofillManager#notifyValueChanged(View)} must happen <b>after</b> the value was 7689 * changed to the autofilled value. If not, the view will not be considered autofilled. 7690 * 7691 * @param value value to be autofilled. 7692 */ 7693 public void autofill(@SuppressWarnings("unused") AutofillValue value) { 7694 } 7695 7696 /** 7697 * Automatically fills the content of the virtual children within this view. 7698 * 7699 * <p>Views with virtual children support the Autofill Framework mainly by: 7700 * <ul> 7701 * <li>Providing the metadata defining what the virtual children mean and how they can be 7702 * autofilled. 7703 * <li>Implementing the methods that autofill the virtual children. 7704 * </ul> 7705 * <p>{@link #onProvideAutofillVirtualStructure(ViewStructure, int)} is responsible for the 7706 * former, this method is responsible for the latter - see {@link #autofill(AutofillValue)} and 7707 * {@link #onProvideAutofillVirtualStructure(ViewStructure, int)} for more info about autofill. 7708 * 7709 * <p>If a child value is updated asynchronously, the next call to 7710 * {@link AutofillManager#notifyValueChanged(View, int, AutofillValue)} must happen 7711 * <b>after</b> the value was changed to the autofilled value. If not, the child will not be 7712 * considered autofilled. 7713 * 7714 * <p><b>NOTE:</b> to indicate that a virtual view was autofilled, 7715 * <code>?android:attr/autofilledHighlight</code> should be drawn over it until the data 7716 * changes. 7717 * 7718 * @param values map of values to be autofilled, keyed by virtual child id. 7719 * 7720 * @attr ref android.R.styleable#Theme_autofilledHighlight 7721 */ 7722 public void autofill(@NonNull @SuppressWarnings("unused") SparseArray<AutofillValue> values) { 7723 } 7724 7725 /** 7726 * Gets the unique identifier of this view in the screen, for autofill purposes. 7727 * 7728 * @return The View's autofill id. 7729 */ 7730 public final AutofillId getAutofillId() { 7731 if (mAutofillId == null) { 7732 // The autofill id needs to be unique, but its value doesn't matter, 7733 // so it's better to reuse the accessibility id to save space. 7734 mAutofillId = new AutofillId(getAutofillViewId()); 7735 } 7736 return mAutofillId; 7737 } 7738 7739 /** 7740 * Describes the autofill type of this view, so an 7741 * {@link android.service.autofill.AutofillService} can create the proper {@link AutofillValue} 7742 * when autofilling the view. 7743 * 7744 * <p>By default returns {@link #AUTOFILL_TYPE_NONE}, but views should override it to properly 7745 * support the Autofill Framework. 7746 * 7747 * @return either {@link #AUTOFILL_TYPE_NONE}, {@link #AUTOFILL_TYPE_TEXT}, 7748 * {@link #AUTOFILL_TYPE_LIST}, {@link #AUTOFILL_TYPE_DATE}, or {@link #AUTOFILL_TYPE_TOGGLE}. 7749 * 7750 * @see #onProvideAutofillStructure(ViewStructure, int) 7751 * @see #autofill(AutofillValue) 7752 */ 7753 public @AutofillType int getAutofillType() { 7754 return AUTOFILL_TYPE_NONE; 7755 } 7756 7757 /** 7758 * Gets the hints that help an {@link android.service.autofill.AutofillService} determine how 7759 * to autofill the view with the user's data. 7760 * 7761 * <p>See {@link #setAutofillHints(String...)} for more info about these hints. 7762 * 7763 * @return The hints set via the attribute or {@link #setAutofillHints(String...)}, or 7764 * {@code null} if no hints were set. 7765 * 7766 * @attr ref android.R.styleable#View_autofillHints 7767 */ 7768 @ViewDebug.ExportedProperty() 7769 @Nullable public String[] getAutofillHints() { 7770 return mAutofillHints; 7771 } 7772 7773 /** 7774 * @hide 7775 */ 7776 public boolean isAutofilled() { 7777 return (mPrivateFlags3 & PFLAG3_IS_AUTOFILLED) != 0; 7778 } 7779 7780 /** 7781 * Gets the {@link View}'s current autofill value. 7782 * 7783 * <p>By default returns {@code null}, but views should override it to properly support the 7784 * Autofill Framework. 7785 * 7786 * @see #onProvideAutofillStructure(ViewStructure, int) 7787 * @see #autofill(AutofillValue) 7788 */ 7789 @Nullable 7790 public AutofillValue getAutofillValue() { 7791 return null; 7792 } 7793 7794 /** 7795 * Gets the mode for determining whether this view is important for autofill. 7796 * 7797 * <p>See {@link #setImportantForAutofill(int)} and {@link #isImportantForAutofill()} for more 7798 * info about this mode. 7799 * 7800 * @return {@link #IMPORTANT_FOR_AUTOFILL_AUTO} by default, or value passed to 7801 * {@link #setImportantForAutofill(int)}. 7802 * 7803 * @attr ref android.R.styleable#View_importantForAutofill 7804 */ 7805 @ViewDebug.ExportedProperty(mapping = { 7806 @ViewDebug.IntToString(from = IMPORTANT_FOR_AUTOFILL_AUTO, to = "auto"), 7807 @ViewDebug.IntToString(from = IMPORTANT_FOR_AUTOFILL_YES, to = "yes"), 7808 @ViewDebug.IntToString(from = IMPORTANT_FOR_AUTOFILL_NO, to = "no"), 7809 @ViewDebug.IntToString(from = IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS, 7810 to = "yesExcludeDescendants"), 7811 @ViewDebug.IntToString(from = IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS, 7812 to = "noExcludeDescendants")}) 7813 public @AutofillImportance int getImportantForAutofill() { 7814 return (mPrivateFlags3 7815 & PFLAG3_IMPORTANT_FOR_AUTOFILL_MASK) >> PFLAG3_IMPORTANT_FOR_AUTOFILL_SHIFT; 7816 } 7817 7818 /** 7819 * Sets the mode for determining whether this view is considered important for autofill. 7820 * 7821 * <p>The platform determines the importance for autofill automatically but you 7822 * can use this method to customize the behavior. For example: 7823 * 7824 * <ol> 7825 * <li>When the view contents is irrelevant for autofill (for example, a text field used in a 7826 * "Captcha" challenge), it should be {@link #IMPORTANT_FOR_AUTOFILL_NO}. 7827 * <li>When both the view and its children are irrelevant for autofill (for example, the root 7828 * view of an activity containing a spreadhseet editor), it should be 7829 * {@link #IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS}. 7830 * <li>When the view content is relevant for autofill but its children aren't (for example, 7831 * a credit card expiration date represented by a custom view that overrides the proper 7832 * autofill methods and has 2 children representing the month and year), it should 7833 * be {@link #IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS}. 7834 * </ol> 7835 * 7836 * <p><b>NOTE:</strong> setting the mode as does {@link #IMPORTANT_FOR_AUTOFILL_NO} or 7837 * {@link #IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS} does not guarantee the view (and its 7838 * children) will be always be considered not important; for example, when the user explicitly 7839 * makes an autofill request, all views are considered important. See 7840 * {@link #isImportantForAutofill()} for more details about how the View's importance for 7841 * autofill is used. 7842 * 7843 * @param mode {@link #IMPORTANT_FOR_AUTOFILL_AUTO}, {@link #IMPORTANT_FOR_AUTOFILL_YES}, 7844 * {@link #IMPORTANT_FOR_AUTOFILL_NO}, {@link #IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS}, 7845 * or {@link #IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS}. 7846 * 7847 * @attr ref android.R.styleable#View_importantForAutofill 7848 */ 7849 public void setImportantForAutofill(@AutofillImportance int mode) { 7850 mPrivateFlags3 &= ~PFLAG3_IMPORTANT_FOR_AUTOFILL_MASK; 7851 mPrivateFlags3 |= (mode << PFLAG3_IMPORTANT_FOR_AUTOFILL_SHIFT) 7852 & PFLAG3_IMPORTANT_FOR_AUTOFILL_MASK; 7853 } 7854 7855 /** 7856 * Hints the Android System whether the {@link android.app.assist.AssistStructure.ViewNode} 7857 * associated with this view is considered important for autofill purposes. 7858 * 7859 * <p>Generally speaking, a view is important for autofill if: 7860 * <ol> 7861 * <li>The view can be autofilled by an {@link android.service.autofill.AutofillService}. 7862 * <li>The view contents can help an {@link android.service.autofill.AutofillService} 7863 * determine how other views can be autofilled. 7864 * <ol> 7865 * 7866 * <p>For example, view containers should typically return {@code false} for performance reasons 7867 * (since the important info is provided by their children), but if its properties have relevant 7868 * information (for example, a resource id called {@code credentials}, it should return 7869 * {@code true}. On the other hand, views representing labels or editable fields should 7870 * typically return {@code true}, but in some cases they could return {@code false} 7871 * (for example, if they're part of a "Captcha" mechanism). 7872 * 7873 * <p>The value returned by this method depends on the value returned by 7874 * {@link #getImportantForAutofill()}: 7875 * 7876 * <ol> 7877 * <li>if it returns {@link #IMPORTANT_FOR_AUTOFILL_YES} or 7878 * {@link #IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS}, then it returns {@code true} 7879 * <li>if it returns {@link #IMPORTANT_FOR_AUTOFILL_NO} or 7880 * {@link #IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS}, then it returns {@code false} 7881 * <li>if it returns {@link #IMPORTANT_FOR_AUTOFILL_AUTO}, then it uses some simple heuristics 7882 * that can return {@code true} in some cases (like a container with a resource id), 7883 * but {@code false} in most. 7884 * <li>otherwise, it returns {@code false}. 7885 * </ol> 7886 * 7887 * <p>When a view is considered important for autofill: 7888 * <ul> 7889 * <li>The view might automatically trigger an autofill request when focused on. 7890 * <li>The contents of the view are included in the {@link ViewStructure} used in an autofill 7891 * request. 7892 * </ul> 7893 * 7894 * <p>On the other hand, when a view is considered not important for autofill: 7895 * <ul> 7896 * <li>The view never automatically triggers autofill requests, but it can trigger a manual 7897 * request through {@link AutofillManager#requestAutofill(View)}. 7898 * <li>The contents of the view are not included in the {@link ViewStructure} used in an 7899 * autofill request, unless the request has the 7900 * {@link #AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS} flag. 7901 * </ul> 7902 * 7903 * @return whether the view is considered important for autofill. 7904 * 7905 * @see #setImportantForAutofill(int) 7906 * @see #IMPORTANT_FOR_AUTOFILL_AUTO 7907 * @see #IMPORTANT_FOR_AUTOFILL_YES 7908 * @see #IMPORTANT_FOR_AUTOFILL_NO 7909 * @see #IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS 7910 * @see #IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS 7911 * @see AutofillManager#requestAutofill(View) 7912 */ 7913 public final boolean isImportantForAutofill() { 7914 // Check parent mode to ensure we're not hidden. 7915 ViewParent parent = mParent; 7916 while (parent instanceof View) { 7917 final int parentImportance = ((View) parent).getImportantForAutofill(); 7918 if (parentImportance == IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS 7919 || parentImportance == IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS) { 7920 return false; 7921 } 7922 parent = parent.getParent(); 7923 } 7924 7925 final int importance = getImportantForAutofill(); 7926 7927 // First, check the explicit states. 7928 if (importance == IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS 7929 || importance == IMPORTANT_FOR_AUTOFILL_YES) { 7930 return true; 7931 } 7932 if (importance == IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS 7933 || importance == IMPORTANT_FOR_AUTOFILL_NO) { 7934 return false; 7935 } 7936 7937 // Then use some heuristics to handle AUTO. 7938 7939 // Always include views that have an explicit resource id. 7940 final int id = mID; 7941 if (id != NO_ID && !isViewIdGenerated(id)) { 7942 final Resources res = getResources(); 7943 String entry = null; 7944 String pkg = null; 7945 try { 7946 entry = res.getResourceEntryName(id); 7947 pkg = res.getResourcePackageName(id); 7948 } catch (Resources.NotFoundException e) { 7949 // ignore 7950 } 7951 if (entry != null && pkg != null && pkg.equals(mContext.getPackageName())) { 7952 return true; 7953 } 7954 } 7955 7956 // Otherwise, assume it's not important... 7957 return false; 7958 } 7959 7960 @Nullable 7961 private AutofillManager getAutofillManager() { 7962 return mContext.getSystemService(AutofillManager.class); 7963 } 7964 7965 private boolean isAutofillable() { 7966 return getAutofillType() != AUTOFILL_TYPE_NONE && isImportantForAutofill() 7967 && getAutofillViewId() > LAST_APP_AUTOFILL_ID; 7968 } 7969 7970 private void populateVirtualStructure(ViewStructure structure, 7971 AccessibilityNodeProvider provider, AccessibilityNodeInfo info) { 7972 structure.setId(AccessibilityNodeInfo.getVirtualDescendantId(info.getSourceNodeId()), 7973 null, null, null); 7974 Rect rect = structure.getTempRect(); 7975 info.getBoundsInParent(rect); 7976 structure.setDimens(rect.left, rect.top, 0, 0, rect.width(), rect.height()); 7977 structure.setVisibility(VISIBLE); 7978 structure.setEnabled(info.isEnabled()); 7979 if (info.isClickable()) { 7980 structure.setClickable(true); 7981 } 7982 if (info.isFocusable()) { 7983 structure.setFocusable(true); 7984 } 7985 if (info.isFocused()) { 7986 structure.setFocused(true); 7987 } 7988 if (info.isAccessibilityFocused()) { 7989 structure.setAccessibilityFocused(true); 7990 } 7991 if (info.isSelected()) { 7992 structure.setSelected(true); 7993 } 7994 if (info.isLongClickable()) { 7995 structure.setLongClickable(true); 7996 } 7997 if (info.isCheckable()) { 7998 structure.setCheckable(true); 7999 if (info.isChecked()) { 8000 structure.setChecked(true); 8001 } 8002 } 8003 if (info.isContextClickable()) { 8004 structure.setContextClickable(true); 8005 } 8006 CharSequence cname = info.getClassName(); 8007 structure.setClassName(cname != null ? cname.toString() : null); 8008 structure.setContentDescription(info.getContentDescription()); 8009 if ((info.getText() != null || info.getError() != null)) { 8010 structure.setText(info.getText(), info.getTextSelectionStart(), 8011 info.getTextSelectionEnd()); 8012 } 8013 final int NCHILDREN = info.getChildCount(); 8014 if (NCHILDREN > 0) { 8015 structure.setChildCount(NCHILDREN); 8016 for (int i=0; i<NCHILDREN; i++) { 8017 AccessibilityNodeInfo cinfo = provider.createAccessibilityNodeInfo( 8018 AccessibilityNodeInfo.getVirtualDescendantId(info.getChildId(i))); 8019 ViewStructure child = structure.newChild(i); 8020 populateVirtualStructure(child, provider, cinfo); 8021 cinfo.recycle(); 8022 } 8023 } 8024 } 8025 8026 /** 8027 * Dispatch creation of {@link ViewStructure} down the hierarchy. The default 8028 * implementation calls {@link #onProvideStructure} and 8029 * {@link #onProvideVirtualStructure}. 8030 */ 8031 public void dispatchProvideStructure(ViewStructure structure) { 8032 dispatchProvideStructureForAssistOrAutofill(structure, false, 0); 8033 } 8034 8035 /** 8036 * Dispatches creation of a {@link ViewStructure}s for autofill purposes down the hierarchy, 8037 * when an Assist structure is being created as part of an autofill request. 8038 * 8039 * <p>The default implementation does the following: 8040 * <ul> 8041 * <li>Sets the {@link AutofillId} in the structure. 8042 * <li>Calls {@link #onProvideAutofillStructure(ViewStructure, int)}. 8043 * <li>Calls {@link #onProvideAutofillVirtualStructure(ViewStructure, int)}. 8044 * </ul> 8045 * 8046 * <p>Typically, this method should only be overridden by subclasses that provide a view 8047 * hierarchy (such as {@link ViewGroup}) - other classes should override 8048 * {@link #onProvideAutofillStructure(ViewStructure, int)} or 8049 * {@link #onProvideAutofillVirtualStructure(ViewStructure, int)} instead. 8050 * 8051 * <p>When overridden, it must: 8052 * 8053 * <ul> 8054 * <li>Either call 8055 * {@code super.dispatchProvideAutofillStructure(structure, flags)} or explicitly 8056 * set the {@link AutofillId} in the structure (for example, by calling 8057 * {@code structure.setAutofillId(getAutofillId())}). 8058 * <li>Decide how to handle the {@link #AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS} flag - when 8059 * set, all views in the structure should be considered important for autofill, 8060 * regardless of what {@link #isImportantForAutofill()} returns. We encourage you to 8061 * respect this flag to provide a better user experience - this flag is typically used 8062 * when an user explicitly requested autofill. If the flag is not set, 8063 * then only views marked as important for autofill should be included in the 8064 * structure - skipping non-important views optimizes the overall autofill performance. 8065 * </ul> 8066 * 8067 * @param structure fill in with structured view data for autofill purposes. 8068 * @param flags optional flags. 8069 * 8070 * @see #AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS 8071 */ 8072 public void dispatchProvideAutofillStructure(@NonNull ViewStructure structure, 8073 @AutofillFlags int flags) { 8074 dispatchProvideStructureForAssistOrAutofill(structure, true, flags); 8075 } 8076 8077 private void dispatchProvideStructureForAssistOrAutofill(ViewStructure structure, 8078 boolean forAutofill, @AutofillFlags int flags) { 8079 if (forAutofill) { 8080 structure.setAutofillId(getAutofillId()); 8081 if (!isLaidOut()) { 8082 Log.w(VIEW_LOG_TAG, "dispatchProvideAutofillStructure(): not laid out, ignoring"); 8083 return; 8084 } 8085 onProvideAutofillStructure(structure, flags); 8086 onProvideAutofillVirtualStructure(structure, flags); 8087 } else if (!isAssistBlocked()) { 8088 onProvideStructure(structure); 8089 onProvideVirtualStructure(structure); 8090 } else { 8091 structure.setClassName(getAccessibilityClassName().toString()); 8092 structure.setAssistBlocked(true); 8093 } 8094 } 8095 8096 /** 8097 * @see #onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo) 8098 * 8099 * Note: Called from the default {@link AccessibilityDelegate}. 8100 * 8101 * @hide 8102 */ 8103 public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) { 8104 if (mAttachInfo == null) { 8105 return; 8106 } 8107 8108 Rect bounds = mAttachInfo.mTmpInvalRect; 8109 8110 getDrawingRect(bounds); 8111 info.setBoundsInParent(bounds); 8112 8113 getBoundsOnScreen(bounds, true); 8114 info.setBoundsInScreen(bounds); 8115 8116 ViewParent parent = getParentForAccessibility(); 8117 if (parent instanceof View) { 8118 info.setParent((View) parent); 8119 } 8120 8121 if (mID != View.NO_ID) { 8122 View rootView = getRootView(); 8123 if (rootView == null) { 8124 rootView = this; 8125 } 8126 8127 View label = rootView.findLabelForView(this, mID); 8128 if (label != null) { 8129 info.setLabeledBy(label); 8130 } 8131 8132 if ((mAttachInfo.mAccessibilityFetchFlags 8133 & AccessibilityNodeInfo.FLAG_REPORT_VIEW_IDS) != 0 8134 && Resources.resourceHasPackage(mID)) { 8135 try { 8136 String viewId = getResources().getResourceName(mID); 8137 info.setViewIdResourceName(viewId); 8138 } catch (Resources.NotFoundException nfe) { 8139 /* ignore */ 8140 } 8141 } 8142 } 8143 8144 if (mLabelForId != View.NO_ID) { 8145 View rootView = getRootView(); 8146 if (rootView == null) { 8147 rootView = this; 8148 } 8149 View labeled = rootView.findViewInsideOutShouldExist(this, mLabelForId); 8150 if (labeled != null) { 8151 info.setLabelFor(labeled); 8152 } 8153 } 8154 8155 if (mAccessibilityTraversalBeforeId != View.NO_ID) { 8156 View rootView = getRootView(); 8157 if (rootView == null) { 8158 rootView = this; 8159 } 8160 View next = rootView.findViewInsideOutShouldExist(this, 8161 mAccessibilityTraversalBeforeId); 8162 if (next != null && next.includeForAccessibility()) { 8163 info.setTraversalBefore(next); 8164 } 8165 } 8166 8167 if (mAccessibilityTraversalAfterId != View.NO_ID) { 8168 View rootView = getRootView(); 8169 if (rootView == null) { 8170 rootView = this; 8171 } 8172 View next = rootView.findViewInsideOutShouldExist(this, 8173 mAccessibilityTraversalAfterId); 8174 if (next != null && next.includeForAccessibility()) { 8175 info.setTraversalAfter(next); 8176 } 8177 } 8178 8179 info.setVisibleToUser(isVisibleToUser()); 8180 8181 info.setImportantForAccessibility(isImportantForAccessibility()); 8182 info.setPackageName(mContext.getPackageName()); 8183 info.setClassName(getAccessibilityClassName()); 8184 info.setContentDescription(getContentDescription()); 8185 8186 info.setEnabled(isEnabled()); 8187 info.setClickable(isClickable()); 8188 info.setFocusable(isFocusable()); 8189 info.setFocused(isFocused()); 8190 info.setAccessibilityFocused(isAccessibilityFocused()); 8191 info.setSelected(isSelected()); 8192 info.setLongClickable(isLongClickable()); 8193 info.setContextClickable(isContextClickable()); 8194 info.setLiveRegion(getAccessibilityLiveRegion()); 8195 8196 // TODO: These make sense only if we are in an AdapterView but all 8197 // views can be selected. Maybe from accessibility perspective 8198 // we should report as selectable view in an AdapterView. 8199 info.addAction(AccessibilityNodeInfo.ACTION_SELECT); 8200 info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_SELECTION); 8201 8202 if (isFocusable()) { 8203 if (isFocused()) { 8204 info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_FOCUS); 8205 } else { 8206 info.addAction(AccessibilityNodeInfo.ACTION_FOCUS); 8207 } 8208 } 8209 8210 if (!isAccessibilityFocused()) { 8211 info.addAction(AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS); 8212 } else { 8213 info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS); 8214 } 8215 8216 if (isClickable() && isEnabled()) { 8217 info.addAction(AccessibilityNodeInfo.ACTION_CLICK); 8218 } 8219 8220 if (isLongClickable() && isEnabled()) { 8221 info.addAction(AccessibilityNodeInfo.ACTION_LONG_CLICK); 8222 } 8223 8224 if (isContextClickable() && isEnabled()) { 8225 info.addAction(AccessibilityAction.ACTION_CONTEXT_CLICK); 8226 } 8227 8228 CharSequence text = getIterableTextForAccessibility(); 8229 if (text != null && text.length() > 0) { 8230 info.setTextSelection(getAccessibilitySelectionStart(), getAccessibilitySelectionEnd()); 8231 8232 info.addAction(AccessibilityNodeInfo.ACTION_SET_SELECTION); 8233 info.addAction(AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY); 8234 info.addAction(AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY); 8235 info.setMovementGranularities(AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER 8236 | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD 8237 | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH); 8238 } 8239 8240 info.addAction(AccessibilityAction.ACTION_SHOW_ON_SCREEN); 8241 populateAccessibilityNodeInfoDrawingOrderInParent(info); 8242 } 8243 8244 /** 8245 * Adds extra data to an {@link AccessibilityNodeInfo} based on an explicit request for the 8246 * additional data. 8247 * <p> 8248 * This method only needs overloading if the node is marked as having extra data available. 8249 * </p> 8250 * 8251 * @param info The info to which to add the extra data. Never {@code null}. 8252 * @param extraDataKey A key specifying the type of extra data to add to the info. The 8253 * extra data should be added to the {@link Bundle} returned by 8254 * the info's {@link AccessibilityNodeInfo#getExtras} method. Never 8255 * {@code null}. 8256 * @param arguments A {@link Bundle} holding any arguments relevant for this request. May be 8257 * {@code null} if the service provided no arguments. 8258 * 8259 * @see AccessibilityNodeInfo#setAvailableExtraData(List) 8260 */ 8261 public void addExtraDataToAccessibilityNodeInfo( 8262 @NonNull AccessibilityNodeInfo info, @NonNull String extraDataKey, 8263 @Nullable Bundle arguments) { 8264 } 8265 8266 /** 8267 * Determine the order in which this view will be drawn relative to its siblings for a11y 8268 * 8269 * @param info The info whose drawing order should be populated 8270 */ 8271 private void populateAccessibilityNodeInfoDrawingOrderInParent(AccessibilityNodeInfo info) { 8272 /* 8273 * If the view's bounds haven't been set yet, layout has not completed. In that situation, 8274 * drawing order may not be well-defined, and some Views with custom drawing order may 8275 * not be initialized sufficiently to respond properly getChildDrawingOrder. 8276 */ 8277 if ((mPrivateFlags & PFLAG_HAS_BOUNDS) == 0) { 8278 info.setDrawingOrder(0); 8279 return; 8280 } 8281 int drawingOrderInParent = 1; 8282 // Iterate up the hierarchy if parents are not important for a11y 8283 View viewAtDrawingLevel = this; 8284 final ViewParent parent = getParentForAccessibility(); 8285 while (viewAtDrawingLevel != parent) { 8286 final ViewParent currentParent = viewAtDrawingLevel.getParent(); 8287 if (!(currentParent instanceof ViewGroup)) { 8288 // Should only happen for the Decor 8289 drawingOrderInParent = 0; 8290 break; 8291 } else { 8292 final ViewGroup parentGroup = (ViewGroup) currentParent; 8293 final int childCount = parentGroup.getChildCount(); 8294 if (childCount > 1) { 8295 List<View> preorderedList = parentGroup.buildOrderedChildList(); 8296 if (preorderedList != null) { 8297 final int childDrawIndex = preorderedList.indexOf(viewAtDrawingLevel); 8298 for (int i = 0; i < childDrawIndex; i++) { 8299 drawingOrderInParent += numViewsForAccessibility(preorderedList.get(i)); 8300 } 8301 } else { 8302 final int childIndex = parentGroup.indexOfChild(viewAtDrawingLevel); 8303 final boolean customOrder = parentGroup.isChildrenDrawingOrderEnabled(); 8304 final int childDrawIndex = ((childIndex >= 0) && customOrder) ? parentGroup 8305 .getChildDrawingOrder(childCount, childIndex) : childIndex; 8306 final int numChildrenToIterate = customOrder ? childCount : childDrawIndex; 8307 if (childDrawIndex != 0) { 8308 for (int i = 0; i < numChildrenToIterate; i++) { 8309 final int otherDrawIndex = (customOrder ? 8310 parentGroup.getChildDrawingOrder(childCount, i) : i); 8311 if (otherDrawIndex < childDrawIndex) { 8312 drawingOrderInParent += 8313 numViewsForAccessibility(parentGroup.getChildAt(i)); 8314 } 8315 } 8316 } 8317 } 8318 } 8319 } 8320 viewAtDrawingLevel = (View) currentParent; 8321 } 8322 info.setDrawingOrder(drawingOrderInParent); 8323 } 8324 8325 private static int numViewsForAccessibility(View view) { 8326 if (view != null) { 8327 if (view.includeForAccessibility()) { 8328 return 1; 8329 } else if (view instanceof ViewGroup) { 8330 return ((ViewGroup) view).getNumChildrenForAccessibility(); 8331 } 8332 } 8333 return 0; 8334 } 8335 8336 private View findLabelForView(View view, int labeledId) { 8337 if (mMatchLabelForPredicate == null) { 8338 mMatchLabelForPredicate = new MatchLabelForPredicate(); 8339 } 8340 mMatchLabelForPredicate.mLabeledId = labeledId; 8341 return findViewByPredicateInsideOut(view, mMatchLabelForPredicate); 8342 } 8343 8344 /** 8345 * Computes whether this view is visible to the user. Such a view is 8346 * attached, visible, all its predecessors are visible, it is not clipped 8347 * entirely by its predecessors, and has an alpha greater than zero. 8348 * 8349 * @return Whether the view is visible on the screen. 8350 * 8351 * @hide 8352 */ 8353 protected boolean isVisibleToUser() { 8354 return isVisibleToUser(null); 8355 } 8356 8357 /** 8358 * Computes whether the given portion of this view is visible to the user. 8359 * Such a view is attached, visible, all its predecessors are visible, 8360 * has an alpha greater than zero, and the specified portion is not 8361 * clipped entirely by its predecessors. 8362 * 8363 * @param boundInView the portion of the view to test; coordinates should be relative; may be 8364 * <code>null</code>, and the entire view will be tested in this case. 8365 * When <code>true</code> is returned by the function, the actual visible 8366 * region will be stored in this parameter; that is, if boundInView is fully 8367 * contained within the view, no modification will be made, otherwise regions 8368 * outside of the visible area of the view will be clipped. 8369 * 8370 * @return Whether the specified portion of the view is visible on the screen. 8371 * 8372 * @hide 8373 */ 8374 protected boolean isVisibleToUser(Rect boundInView) { 8375 if (mAttachInfo != null) { 8376 // Attached to invisible window means this view is not visible. 8377 if (mAttachInfo.mWindowVisibility != View.VISIBLE) { 8378 return false; 8379 } 8380 // An invisible predecessor or one with alpha zero means 8381 // that this view is not visible to the user. 8382 Object current = this; 8383 while (current instanceof View) { 8384 View view = (View) current; 8385 // We have attach info so this view is attached and there is no 8386 // need to check whether we reach to ViewRootImpl on the way up. 8387 if (view.getAlpha() <= 0 || view.getTransitionAlpha() <= 0 || 8388 view.getVisibility() != VISIBLE) { 8389 return false; 8390 } 8391 current = view.mParent; 8392 } 8393 // Check if the view is entirely covered by its predecessors. 8394 Rect visibleRect = mAttachInfo.mTmpInvalRect; 8395 Point offset = mAttachInfo.mPoint; 8396 if (!getGlobalVisibleRect(visibleRect, offset)) { 8397 return false; 8398 } 8399 // Check if the visible portion intersects the rectangle of interest. 8400 if (boundInView != null) { 8401 visibleRect.offset(-offset.x, -offset.y); 8402 return boundInView.intersect(visibleRect); 8403 } 8404 return true; 8405 } 8406 return false; 8407 } 8408 8409 /** 8410 * Returns the delegate for implementing accessibility support via 8411 * composition. For more details see {@link AccessibilityDelegate}. 8412 * 8413 * @return The delegate, or null if none set. 8414 * 8415 * @hide 8416 */ 8417 public AccessibilityDelegate getAccessibilityDelegate() { 8418 return mAccessibilityDelegate; 8419 } 8420 8421 /** 8422 * Sets a delegate for implementing accessibility support via composition 8423 * (as opposed to inheritance). For more details, see 8424 * {@link AccessibilityDelegate}. 8425 * <p> 8426 * <strong>Note:</strong> On platform versions prior to 8427 * {@link android.os.Build.VERSION_CODES#M API 23}, delegate methods on 8428 * views in the {@code android.widget.*} package are called <i>before</i> 8429 * host methods. This prevents certain properties such as class name from 8430 * being modified by overriding 8431 * {@link AccessibilityDelegate#onInitializeAccessibilityNodeInfo(View, AccessibilityNodeInfo)}, 8432 * as any changes will be overwritten by the host class. 8433 * <p> 8434 * Starting in {@link android.os.Build.VERSION_CODES#M API 23}, delegate 8435 * methods are called <i>after</i> host methods, which all properties to be 8436 * modified without being overwritten by the host class. 8437 * 8438 * @param delegate the object to which accessibility method calls should be 8439 * delegated 8440 * @see AccessibilityDelegate 8441 */ 8442 public void setAccessibilityDelegate(@Nullable AccessibilityDelegate delegate) { 8443 mAccessibilityDelegate = delegate; 8444 } 8445 8446 /** 8447 * Gets the provider for managing a virtual view hierarchy rooted at this View 8448 * and reported to {@link android.accessibilityservice.AccessibilityService}s 8449 * that explore the window content. 8450 * <p> 8451 * If this method returns an instance, this instance is responsible for managing 8452 * {@link AccessibilityNodeInfo}s describing the virtual sub-tree rooted at this 8453 * View including the one representing the View itself. Similarly the returned 8454 * instance is responsible for performing accessibility actions on any virtual 8455 * view or the root view itself. 8456 * </p> 8457 * <p> 8458 * If an {@link AccessibilityDelegate} has been specified via calling 8459 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 8460 * {@link AccessibilityDelegate#getAccessibilityNodeProvider(View)} 8461 * is responsible for handling this call. 8462 * </p> 8463 * 8464 * @return The provider. 8465 * 8466 * @see AccessibilityNodeProvider 8467 */ 8468 public AccessibilityNodeProvider getAccessibilityNodeProvider() { 8469 if (mAccessibilityDelegate != null) { 8470 return mAccessibilityDelegate.getAccessibilityNodeProvider(this); 8471 } else { 8472 return null; 8473 } 8474 } 8475 8476 /** 8477 * Gets the unique identifier of this view on the screen for accessibility purposes. 8478 * 8479 * @return The view accessibility id. 8480 * 8481 * @hide 8482 */ 8483 public int getAccessibilityViewId() { 8484 if (mAccessibilityViewId == NO_ID) { 8485 mAccessibilityViewId = sNextAccessibilityViewId++; 8486 } 8487 return mAccessibilityViewId; 8488 } 8489 8490 /** 8491 * Gets the unique identifier of this view on the screen for autofill purposes. 8492 * 8493 * @return The view autofill id. 8494 * 8495 * @hide 8496 */ 8497 public int getAutofillViewId() { 8498 if (mAutofillViewId == NO_ID) { 8499 mAutofillViewId = mContext.getNextAutofillId(); 8500 } 8501 return mAutofillViewId; 8502 } 8503 8504 /** 8505 * Gets the unique identifier of the window in which this View reseides. 8506 * 8507 * @return The window accessibility id. 8508 * 8509 * @hide 8510 */ 8511 public int getAccessibilityWindowId() { 8512 return mAttachInfo != null ? mAttachInfo.mAccessibilityWindowId 8513 : AccessibilityWindowInfo.UNDEFINED_WINDOW_ID; 8514 } 8515 8516 /** 8517 * Returns the {@link View}'s content description. 8518 * <p> 8519 * <strong>Note:</strong> Do not override this method, as it will have no 8520 * effect on the content description presented to accessibility services. 8521 * You must call {@link #setContentDescription(CharSequence)} to modify the 8522 * content description. 8523 * 8524 * @return the content description 8525 * @see #setContentDescription(CharSequence) 8526 * @attr ref android.R.styleable#View_contentDescription 8527 */ 8528 @ViewDebug.ExportedProperty(category = "accessibility") 8529 public CharSequence getContentDescription() { 8530 return mContentDescription; 8531 } 8532 8533 /** 8534 * Sets the {@link View}'s content description. 8535 * <p> 8536 * A content description briefly describes the view and is primarily used 8537 * for accessibility support to determine how a view should be presented to 8538 * the user. In the case of a view with no textual representation, such as 8539 * {@link android.widget.ImageButton}, a useful content description 8540 * explains what the view does. For example, an image button with a phone 8541 * icon that is used to place a call may use "Call" as its content 8542 * description. An image of a floppy disk that is used to save a file may 8543 * use "Save". 8544 * 8545 * @param contentDescription The content description. 8546 * @see #getContentDescription() 8547 * @attr ref android.R.styleable#View_contentDescription 8548 */ 8549 @RemotableViewMethod 8550 public void setContentDescription(CharSequence contentDescription) { 8551 if (mContentDescription == null) { 8552 if (contentDescription == null) { 8553 return; 8554 } 8555 } else if (mContentDescription.equals(contentDescription)) { 8556 return; 8557 } 8558 mContentDescription = contentDescription; 8559 final boolean nonEmptyDesc = contentDescription != null && contentDescription.length() > 0; 8560 if (nonEmptyDesc && getImportantForAccessibility() == IMPORTANT_FOR_ACCESSIBILITY_AUTO) { 8561 setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES); 8562 notifySubtreeAccessibilityStateChangedIfNeeded(); 8563 } else { 8564 notifyViewAccessibilityStateChangedIfNeeded( 8565 AccessibilityEvent.CONTENT_CHANGE_TYPE_CONTENT_DESCRIPTION); 8566 } 8567 } 8568 8569 /** 8570 * Sets the id of a view before which this one is visited in accessibility traversal. 8571 * A screen-reader must visit the content of this view before the content of the one 8572 * it precedes. For example, if view B is set to be before view A, then a screen-reader 8573 * will traverse the entire content of B before traversing the entire content of A, 8574 * regardles of what traversal strategy it is using. 8575 * <p> 8576 * Views that do not have specified before/after relationships are traversed in order 8577 * determined by the screen-reader. 8578 * </p> 8579 * <p> 8580 * Setting that this view is before a view that is not important for accessibility 8581 * or if this view is not important for accessibility will have no effect as the 8582 * screen-reader is not aware of unimportant views. 8583 * </p> 8584 * 8585 * @param beforeId The id of a view this one precedes in accessibility traversal. 8586 * 8587 * @attr ref android.R.styleable#View_accessibilityTraversalBefore 8588 * 8589 * @see #setImportantForAccessibility(int) 8590 */ 8591 @RemotableViewMethod 8592 public void setAccessibilityTraversalBefore(int beforeId) { 8593 if (mAccessibilityTraversalBeforeId == beforeId) { 8594 return; 8595 } 8596 mAccessibilityTraversalBeforeId = beforeId; 8597 notifyViewAccessibilityStateChangedIfNeeded( 8598 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 8599 } 8600 8601 /** 8602 * Gets the id of a view before which this one is visited in accessibility traversal. 8603 * 8604 * @return The id of a view this one precedes in accessibility traversal if 8605 * specified, otherwise {@link #NO_ID}. 8606 * 8607 * @see #setAccessibilityTraversalBefore(int) 8608 */ 8609 public int getAccessibilityTraversalBefore() { 8610 return mAccessibilityTraversalBeforeId; 8611 } 8612 8613 /** 8614 * Sets the id of a view after which this one is visited in accessibility traversal. 8615 * A screen-reader must visit the content of the other view before the content of this 8616 * one. For example, if view B is set to be after view A, then a screen-reader 8617 * will traverse the entire content of A before traversing the entire content of B, 8618 * regardles of what traversal strategy it is using. 8619 * <p> 8620 * Views that do not have specified before/after relationships are traversed in order 8621 * determined by the screen-reader. 8622 * </p> 8623 * <p> 8624 * Setting that this view is after a view that is not important for accessibility 8625 * or if this view is not important for accessibility will have no effect as the 8626 * screen-reader is not aware of unimportant views. 8627 * </p> 8628 * 8629 * @param afterId The id of a view this one succedees in accessibility traversal. 8630 * 8631 * @attr ref android.R.styleable#View_accessibilityTraversalAfter 8632 * 8633 * @see #setImportantForAccessibility(int) 8634 */ 8635 @RemotableViewMethod 8636 public void setAccessibilityTraversalAfter(int afterId) { 8637 if (mAccessibilityTraversalAfterId == afterId) { 8638 return; 8639 } 8640 mAccessibilityTraversalAfterId = afterId; 8641 notifyViewAccessibilityStateChangedIfNeeded( 8642 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 8643 } 8644 8645 /** 8646 * Gets the id of a view after which this one is visited in accessibility traversal. 8647 * 8648 * @return The id of a view this one succeedes in accessibility traversal if 8649 * specified, otherwise {@link #NO_ID}. 8650 * 8651 * @see #setAccessibilityTraversalAfter(int) 8652 */ 8653 public int getAccessibilityTraversalAfter() { 8654 return mAccessibilityTraversalAfterId; 8655 } 8656 8657 /** 8658 * Gets the id of a view for which this view serves as a label for 8659 * accessibility purposes. 8660 * 8661 * @return The labeled view id. 8662 */ 8663 @ViewDebug.ExportedProperty(category = "accessibility") 8664 public int getLabelFor() { 8665 return mLabelForId; 8666 } 8667 8668 /** 8669 * Sets the id of a view for which this view serves as a label for 8670 * accessibility purposes. 8671 * 8672 * @param id The labeled view id. 8673 */ 8674 @RemotableViewMethod 8675 public void setLabelFor(@IdRes int id) { 8676 if (mLabelForId == id) { 8677 return; 8678 } 8679 mLabelForId = id; 8680 if (mLabelForId != View.NO_ID 8681 && mID == View.NO_ID) { 8682 mID = generateViewId(); 8683 } 8684 notifyViewAccessibilityStateChangedIfNeeded( 8685 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 8686 } 8687 8688 /** 8689 * Invoked whenever this view loses focus, either by losing window focus or by losing 8690 * focus within its window. This method can be used to clear any state tied to the 8691 * focus. For instance, if a button is held pressed with the trackball and the window 8692 * loses focus, this method can be used to cancel the press. 8693 * 8694 * Subclasses of View overriding this method should always call super.onFocusLost(). 8695 * 8696 * @see #onFocusChanged(boolean, int, android.graphics.Rect) 8697 * @see #onWindowFocusChanged(boolean) 8698 * 8699 * @hide pending API council approval 8700 */ 8701 @CallSuper 8702 protected void onFocusLost() { 8703 resetPressedState(); 8704 } 8705 8706 private void resetPressedState() { 8707 if ((mViewFlags & ENABLED_MASK) == DISABLED) { 8708 return; 8709 } 8710 8711 if (isPressed()) { 8712 setPressed(false); 8713 8714 if (!mHasPerformedLongPress) { 8715 removeLongPressCallback(); 8716 } 8717 } 8718 } 8719 8720 /** 8721 * Returns true if this view has focus 8722 * 8723 * @return True if this view has focus, false otherwise. 8724 */ 8725 @ViewDebug.ExportedProperty(category = "focus") 8726 public boolean isFocused() { 8727 return (mPrivateFlags & PFLAG_FOCUSED) != 0; 8728 } 8729 8730 /** 8731 * Find the view in the hierarchy rooted at this view that currently has 8732 * focus. 8733 * 8734 * @return The view that currently has focus, or null if no focused view can 8735 * be found. 8736 */ 8737 public View findFocus() { 8738 return (mPrivateFlags & PFLAG_FOCUSED) != 0 ? this : null; 8739 } 8740 8741 /** 8742 * Indicates whether this view is one of the set of scrollable containers in 8743 * its window. 8744 * 8745 * @return whether this view is one of the set of scrollable containers in 8746 * its window 8747 * 8748 * @attr ref android.R.styleable#View_isScrollContainer 8749 */ 8750 public boolean isScrollContainer() { 8751 return (mPrivateFlags & PFLAG_SCROLL_CONTAINER_ADDED) != 0; 8752 } 8753 8754 /** 8755 * Change whether this view is one of the set of scrollable containers in 8756 * its window. This will be used to determine whether the window can 8757 * resize or must pan when a soft input area is open -- scrollable 8758 * containers allow the window to use resize mode since the container 8759 * will appropriately shrink. 8760 * 8761 * @attr ref android.R.styleable#View_isScrollContainer 8762 */ 8763 public void setScrollContainer(boolean isScrollContainer) { 8764 if (isScrollContainer) { 8765 if (mAttachInfo != null && (mPrivateFlags&PFLAG_SCROLL_CONTAINER_ADDED) == 0) { 8766 mAttachInfo.mScrollContainers.add(this); 8767 mPrivateFlags |= PFLAG_SCROLL_CONTAINER_ADDED; 8768 } 8769 mPrivateFlags |= PFLAG_SCROLL_CONTAINER; 8770 } else { 8771 if ((mPrivateFlags&PFLAG_SCROLL_CONTAINER_ADDED) != 0) { 8772 mAttachInfo.mScrollContainers.remove(this); 8773 } 8774 mPrivateFlags &= ~(PFLAG_SCROLL_CONTAINER|PFLAG_SCROLL_CONTAINER_ADDED); 8775 } 8776 } 8777 8778 /** 8779 * Returns the quality of the drawing cache. 8780 * 8781 * @return One of {@link #DRAWING_CACHE_QUALITY_AUTO}, 8782 * {@link #DRAWING_CACHE_QUALITY_LOW}, or {@link #DRAWING_CACHE_QUALITY_HIGH} 8783 * 8784 * @see #setDrawingCacheQuality(int) 8785 * @see #setDrawingCacheEnabled(boolean) 8786 * @see #isDrawingCacheEnabled() 8787 * 8788 * @attr ref android.R.styleable#View_drawingCacheQuality 8789 */ 8790 @DrawingCacheQuality 8791 public int getDrawingCacheQuality() { 8792 return mViewFlags & DRAWING_CACHE_QUALITY_MASK; 8793 } 8794 8795 /** 8796 * Set the drawing cache quality of this view. This value is used only when the 8797 * drawing cache is enabled 8798 * 8799 * @param quality One of {@link #DRAWING_CACHE_QUALITY_AUTO}, 8800 * {@link #DRAWING_CACHE_QUALITY_LOW}, or {@link #DRAWING_CACHE_QUALITY_HIGH} 8801 * 8802 * @see #getDrawingCacheQuality() 8803 * @see #setDrawingCacheEnabled(boolean) 8804 * @see #isDrawingCacheEnabled() 8805 * 8806 * @attr ref android.R.styleable#View_drawingCacheQuality 8807 */ 8808 public void setDrawingCacheQuality(@DrawingCacheQuality int quality) { 8809 setFlags(quality, DRAWING_CACHE_QUALITY_MASK); 8810 } 8811 8812 /** 8813 * Returns whether the screen should remain on, corresponding to the current 8814 * value of {@link #KEEP_SCREEN_ON}. 8815 * 8816 * @return Returns true if {@link #KEEP_SCREEN_ON} is set. 8817 * 8818 * @see #setKeepScreenOn(boolean) 8819 * 8820 * @attr ref android.R.styleable#View_keepScreenOn 8821 */ 8822 public boolean getKeepScreenOn() { 8823 return (mViewFlags & KEEP_SCREEN_ON) != 0; 8824 } 8825 8826 /** 8827 * Controls whether the screen should remain on, modifying the 8828 * value of {@link #KEEP_SCREEN_ON}. 8829 * 8830 * @param keepScreenOn Supply true to set {@link #KEEP_SCREEN_ON}. 8831 * 8832 * @see #getKeepScreenOn() 8833 * 8834 * @attr ref android.R.styleable#View_keepScreenOn 8835 */ 8836 public void setKeepScreenOn(boolean keepScreenOn) { 8837 setFlags(keepScreenOn ? KEEP_SCREEN_ON : 0, KEEP_SCREEN_ON); 8838 } 8839 8840 /** 8841 * Gets the id of the view to use when the next focus is {@link #FOCUS_LEFT}. 8842 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically. 8843 * 8844 * @attr ref android.R.styleable#View_nextFocusLeft 8845 */ 8846 public int getNextFocusLeftId() { 8847 return mNextFocusLeftId; 8848 } 8849 8850 /** 8851 * Sets the id of the view to use when the next focus is {@link #FOCUS_LEFT}. 8852 * @param nextFocusLeftId The next focus ID, or {@link #NO_ID} if the framework should 8853 * decide automatically. 8854 * 8855 * @attr ref android.R.styleable#View_nextFocusLeft 8856 */ 8857 public void setNextFocusLeftId(int nextFocusLeftId) { 8858 mNextFocusLeftId = nextFocusLeftId; 8859 } 8860 8861 /** 8862 * Gets the id of the view to use when the next focus is {@link #FOCUS_RIGHT}. 8863 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically. 8864 * 8865 * @attr ref android.R.styleable#View_nextFocusRight 8866 */ 8867 public int getNextFocusRightId() { 8868 return mNextFocusRightId; 8869 } 8870 8871 /** 8872 * Sets the id of the view to use when the next focus is {@link #FOCUS_RIGHT}. 8873 * @param nextFocusRightId The next focus ID, or {@link #NO_ID} if the framework should 8874 * decide automatically. 8875 * 8876 * @attr ref android.R.styleable#View_nextFocusRight 8877 */ 8878 public void setNextFocusRightId(int nextFocusRightId) { 8879 mNextFocusRightId = nextFocusRightId; 8880 } 8881 8882 /** 8883 * Gets the id of the view to use when the next focus is {@link #FOCUS_UP}. 8884 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically. 8885 * 8886 * @attr ref android.R.styleable#View_nextFocusUp 8887 */ 8888 public int getNextFocusUpId() { 8889 return mNextFocusUpId; 8890 } 8891 8892 /** 8893 * Sets the id of the view to use when the next focus is {@link #FOCUS_UP}. 8894 * @param nextFocusUpId The next focus ID, or {@link #NO_ID} if the framework should 8895 * decide automatically. 8896 * 8897 * @attr ref android.R.styleable#View_nextFocusUp 8898 */ 8899 public void setNextFocusUpId(int nextFocusUpId) { 8900 mNextFocusUpId = nextFocusUpId; 8901 } 8902 8903 /** 8904 * Gets the id of the view to use when the next focus is {@link #FOCUS_DOWN}. 8905 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically. 8906 * 8907 * @attr ref android.R.styleable#View_nextFocusDown 8908 */ 8909 public int getNextFocusDownId() { 8910 return mNextFocusDownId; 8911 } 8912 8913 /** 8914 * Sets the id of the view to use when the next focus is {@link #FOCUS_DOWN}. 8915 * @param nextFocusDownId The next focus ID, or {@link #NO_ID} if the framework should 8916 * decide automatically. 8917 * 8918 * @attr ref android.R.styleable#View_nextFocusDown 8919 */ 8920 public void setNextFocusDownId(int nextFocusDownId) { 8921 mNextFocusDownId = nextFocusDownId; 8922 } 8923 8924 /** 8925 * Gets the id of the view to use when the next focus is {@link #FOCUS_FORWARD}. 8926 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically. 8927 * 8928 * @attr ref android.R.styleable#View_nextFocusForward 8929 */ 8930 public int getNextFocusForwardId() { 8931 return mNextFocusForwardId; 8932 } 8933 8934 /** 8935 * Sets the id of the view to use when the next focus is {@link #FOCUS_FORWARD}. 8936 * @param nextFocusForwardId The next focus ID, or {@link #NO_ID} if the framework should 8937 * decide automatically. 8938 * 8939 * @attr ref android.R.styleable#View_nextFocusForward 8940 */ 8941 public void setNextFocusForwardId(int nextFocusForwardId) { 8942 mNextFocusForwardId = nextFocusForwardId; 8943 } 8944 8945 /** 8946 * Gets the id of the root of the next keyboard navigation cluster. 8947 * @return The next keyboard navigation cluster ID, or {@link #NO_ID} if the framework should 8948 * decide automatically. 8949 * 8950 * @attr ref android.R.styleable#View_nextClusterForward 8951 */ 8952 public int getNextClusterForwardId() { 8953 return mNextClusterForwardId; 8954 } 8955 8956 /** 8957 * Sets the id of the view to use as the root of the next keyboard navigation cluster. 8958 * @param nextClusterForwardId The next cluster ID, or {@link #NO_ID} if the framework should 8959 * decide automatically. 8960 * 8961 * @attr ref android.R.styleable#View_nextClusterForward 8962 */ 8963 public void setNextClusterForwardId(int nextClusterForwardId) { 8964 mNextClusterForwardId = nextClusterForwardId; 8965 } 8966 8967 /** 8968 * Returns the visibility of this view and all of its ancestors 8969 * 8970 * @return True if this view and all of its ancestors are {@link #VISIBLE} 8971 */ 8972 public boolean isShown() { 8973 View current = this; 8974 //noinspection ConstantConditions 8975 do { 8976 if ((current.mViewFlags & VISIBILITY_MASK) != VISIBLE) { 8977 return false; 8978 } 8979 ViewParent parent = current.mParent; 8980 if (parent == null) { 8981 return false; // We are not attached to the view root 8982 } 8983 if (!(parent instanceof View)) { 8984 return true; 8985 } 8986 current = (View) parent; 8987 } while (current != null); 8988 8989 return false; 8990 } 8991 8992 /** 8993 * Called by the view hierarchy when the content insets for a window have 8994 * changed, to allow it to adjust its content to fit within those windows. 8995 * The content insets tell you the space that the status bar, input method, 8996 * and other system windows infringe on the application's window. 8997 * 8998 * <p>You do not normally need to deal with this function, since the default 8999 * window decoration given to applications takes care of applying it to the 9000 * content of the window. If you use {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN} 9001 * or {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION} this will not be the case, 9002 * and your content can be placed under those system elements. You can then 9003 * use this method within your view hierarchy if you have parts of your UI 9004 * which you would like to ensure are not being covered. 9005 * 9006 * <p>The default implementation of this method simply applies the content 9007 * insets to the view's padding, consuming that content (modifying the 9008 * insets to be 0), and returning true. This behavior is off by default, but can 9009 * be enabled through {@link #setFitsSystemWindows(boolean)}. 9010 * 9011 * <p>This function's traversal down the hierarchy is depth-first. The same content 9012 * insets object is propagated down the hierarchy, so any changes made to it will 9013 * be seen by all following views (including potentially ones above in 9014 * the hierarchy since this is a depth-first traversal). The first view 9015 * that returns true will abort the entire traversal. 9016 * 9017 * <p>The default implementation works well for a situation where it is 9018 * used with a container that covers the entire window, allowing it to 9019 * apply the appropriate insets to its content on all edges. If you need 9020 * a more complicated layout (such as two different views fitting system 9021 * windows, one on the top of the window, and one on the bottom), 9022 * you can override the method and handle the insets however you would like. 9023 * Note that the insets provided by the framework are always relative to the 9024 * far edges of the window, not accounting for the location of the called view 9025 * within that window. (In fact when this method is called you do not yet know 9026 * where the layout will place the view, as it is done before layout happens.) 9027 * 9028 * <p>Note: unlike many View methods, there is no dispatch phase to this 9029 * call. If you are overriding it in a ViewGroup and want to allow the 9030 * call to continue to your children, you must be sure to call the super 9031 * implementation. 9032 * 9033 * <p>Here is a sample layout that makes use of fitting system windows 9034 * to have controls for a video view placed inside of the window decorations 9035 * that it hides and shows. This can be used with code like the second 9036 * sample (video player) shown in {@link #setSystemUiVisibility(int)}. 9037 * 9038 * {@sample development/samples/ApiDemos/res/layout/video_player.xml complete} 9039 * 9040 * @param insets Current content insets of the window. Prior to 9041 * {@link android.os.Build.VERSION_CODES#JELLY_BEAN} you must not modify 9042 * the insets or else you and Android will be unhappy. 9043 * 9044 * @return {@code true} if this view applied the insets and it should not 9045 * continue propagating further down the hierarchy, {@code false} otherwise. 9046 * @see #getFitsSystemWindows() 9047 * @see #setFitsSystemWindows(boolean) 9048 * @see #setSystemUiVisibility(int) 9049 * 9050 * @deprecated As of API 20 use {@link #dispatchApplyWindowInsets(WindowInsets)} to apply 9051 * insets to views. Views should override {@link #onApplyWindowInsets(WindowInsets)} or use 9052 * {@link #setOnApplyWindowInsetsListener(android.view.View.OnApplyWindowInsetsListener)} 9053 * to implement handling their own insets. 9054 */ 9055 @Deprecated 9056 protected boolean fitSystemWindows(Rect insets) { 9057 if ((mPrivateFlags3 & PFLAG3_APPLYING_INSETS) == 0) { 9058 if (insets == null) { 9059 // Null insets by definition have already been consumed. 9060 // This call cannot apply insets since there are none to apply, 9061 // so return false. 9062 return false; 9063 } 9064 // If we're not in the process of dispatching the newer apply insets call, 9065 // that means we're not in the compatibility path. Dispatch into the newer 9066 // apply insets path and take things from there. 9067 try { 9068 mPrivateFlags3 |= PFLAG3_FITTING_SYSTEM_WINDOWS; 9069 return dispatchApplyWindowInsets(new WindowInsets(insets)).isConsumed(); 9070 } finally { 9071 mPrivateFlags3 &= ~PFLAG3_FITTING_SYSTEM_WINDOWS; 9072 } 9073 } else { 9074 // We're being called from the newer apply insets path. 9075 // Perform the standard fallback behavior. 9076 return fitSystemWindowsInt(insets); 9077 } 9078 } 9079 9080 private boolean fitSystemWindowsInt(Rect insets) { 9081 if ((mViewFlags & FITS_SYSTEM_WINDOWS) == FITS_SYSTEM_WINDOWS) { 9082 mUserPaddingStart = UNDEFINED_PADDING; 9083 mUserPaddingEnd = UNDEFINED_PADDING; 9084 Rect localInsets = sThreadLocal.get(); 9085 if (localInsets == null) { 9086 localInsets = new Rect(); 9087 sThreadLocal.set(localInsets); 9088 } 9089 boolean res = computeFitSystemWindows(insets, localInsets); 9090 mUserPaddingLeftInitial = localInsets.left; 9091 mUserPaddingRightInitial = localInsets.right; 9092 internalSetPadding(localInsets.left, localInsets.top, 9093 localInsets.right, localInsets.bottom); 9094 return res; 9095 } 9096 return false; 9097 } 9098 9099 /** 9100 * Called when the view should apply {@link WindowInsets} according to its internal policy. 9101 * 9102 * <p>This method should be overridden by views that wish to apply a policy different from or 9103 * in addition to the default behavior. Clients that wish to force a view subtree 9104 * to apply insets should call {@link #dispatchApplyWindowInsets(WindowInsets)}.</p> 9105 * 9106 * <p>Clients may supply an {@link OnApplyWindowInsetsListener} to a view. If one is set 9107 * it will be called during dispatch instead of this method. The listener may optionally 9108 * call this method from its own implementation if it wishes to apply the view's default 9109 * insets policy in addition to its own.</p> 9110 * 9111 * <p>Implementations of this method should either return the insets parameter unchanged 9112 * or a new {@link WindowInsets} cloned from the supplied insets with any insets consumed 9113 * that this view applied itself. This allows new inset types added in future platform 9114 * versions to pass through existing implementations unchanged without being erroneously 9115 * consumed.</p> 9116 * 9117 * <p>By default if a view's {@link #setFitsSystemWindows(boolean) fitsSystemWindows} 9118 * property is set then the view will consume the system window insets and apply them 9119 * as padding for the view.</p> 9120 * 9121 * @param insets Insets to apply 9122 * @return The supplied insets with any applied insets consumed 9123 */ 9124 public WindowInsets onApplyWindowInsets(WindowInsets insets) { 9125 if ((mPrivateFlags3 & PFLAG3_FITTING_SYSTEM_WINDOWS) == 0) { 9126 // We weren't called from within a direct call to fitSystemWindows, 9127 // call into it as a fallback in case we're in a class that overrides it 9128 // and has logic to perform. 9129 if (fitSystemWindows(insets.getSystemWindowInsets())) { 9130 return insets.consumeSystemWindowInsets(); 9131 } 9132 } else { 9133 // We were called from within a direct call to fitSystemWindows. 9134 if (fitSystemWindowsInt(insets.getSystemWindowInsets())) { 9135 return insets.consumeSystemWindowInsets(); 9136 } 9137 } 9138 return insets; 9139 } 9140 9141 /** 9142 * Set an {@link OnApplyWindowInsetsListener} to take over the policy for applying 9143 * window insets to this view. The listener's 9144 * {@link OnApplyWindowInsetsListener#onApplyWindowInsets(View, WindowInsets) onApplyWindowInsets} 9145 * method will be called instead of the view's 9146 * {@link #onApplyWindowInsets(WindowInsets) onApplyWindowInsets} method. 9147 * 9148 * @param listener Listener to set 9149 * 9150 * @see #onApplyWindowInsets(WindowInsets) 9151 */ 9152 public void setOnApplyWindowInsetsListener(OnApplyWindowInsetsListener listener) { 9153 getListenerInfo().mOnApplyWindowInsetsListener = listener; 9154 } 9155 9156 /** 9157 * Request to apply the given window insets to this view or another view in its subtree. 9158 * 9159 * <p>This method should be called by clients wishing to apply insets corresponding to areas 9160 * obscured by window decorations or overlays. This can include the status and navigation bars, 9161 * action bars, input methods and more. New inset categories may be added in the future. 9162 * The method returns the insets provided minus any that were applied by this view or its 9163 * children.</p> 9164 * 9165 * <p>Clients wishing to provide custom behavior should override the 9166 * {@link #onApplyWindowInsets(WindowInsets)} method or alternatively provide a 9167 * {@link OnApplyWindowInsetsListener} via the 9168 * {@link #setOnApplyWindowInsetsListener(View.OnApplyWindowInsetsListener) setOnApplyWindowInsetsListener} 9169 * method.</p> 9170 * 9171 * <p>This method replaces the older {@link #fitSystemWindows(Rect) fitSystemWindows} method. 9172 * </p> 9173 * 9174 * @param insets Insets to apply 9175 * @return The provided insets minus the insets that were consumed 9176 */ 9177 public WindowInsets dispatchApplyWindowInsets(WindowInsets insets) { 9178 try { 9179 mPrivateFlags3 |= PFLAG3_APPLYING_INSETS; 9180 if (mListenerInfo != null && mListenerInfo.mOnApplyWindowInsetsListener != null) { 9181 return mListenerInfo.mOnApplyWindowInsetsListener.onApplyWindowInsets(this, insets); 9182 } else { 9183 return onApplyWindowInsets(insets); 9184 } 9185 } finally { 9186 mPrivateFlags3 &= ~PFLAG3_APPLYING_INSETS; 9187 } 9188 } 9189 9190 /** 9191 * Compute the view's coordinate within the surface. 9192 * 9193 * <p>Computes the coordinates of this view in its surface. The argument 9194 * must be an array of two integers. After the method returns, the array 9195 * contains the x and y location in that order.</p> 9196 * @hide 9197 * @param location an array of two integers in which to hold the coordinates 9198 */ 9199 public void getLocationInSurface(@Size(2) int[] location) { 9200 getLocationInWindow(location); 9201 if (mAttachInfo != null && mAttachInfo.mViewRootImpl != null) { 9202 location[0] += mAttachInfo.mViewRootImpl.mWindowAttributes.surfaceInsets.left; 9203 location[1] += mAttachInfo.mViewRootImpl.mWindowAttributes.surfaceInsets.top; 9204 } 9205 } 9206 9207 /** 9208 * Provide original WindowInsets that are dispatched to the view hierarchy. The insets are 9209 * only available if the view is attached. 9210 * 9211 * @return WindowInsets from the top of the view hierarchy or null if View is detached 9212 */ 9213 public WindowInsets getRootWindowInsets() { 9214 if (mAttachInfo != null) { 9215 return mAttachInfo.mViewRootImpl.getWindowInsets(false /* forceConstruct */); 9216 } 9217 return null; 9218 } 9219 9220 /** 9221 * @hide Compute the insets that should be consumed by this view and the ones 9222 * that should propagate to those under it. 9223 */ 9224 protected boolean computeFitSystemWindows(Rect inoutInsets, Rect outLocalInsets) { 9225 if ((mViewFlags & OPTIONAL_FITS_SYSTEM_WINDOWS) == 0 9226 || mAttachInfo == null 9227 || ((mAttachInfo.mSystemUiVisibility & SYSTEM_UI_LAYOUT_FLAGS) == 0 9228 && !mAttachInfo.mOverscanRequested)) { 9229 outLocalInsets.set(inoutInsets); 9230 inoutInsets.set(0, 0, 0, 0); 9231 return true; 9232 } else { 9233 // The application wants to take care of fitting system window for 9234 // the content... however we still need to take care of any overscan here. 9235 final Rect overscan = mAttachInfo.mOverscanInsets; 9236 outLocalInsets.set(overscan); 9237 inoutInsets.left -= overscan.left; 9238 inoutInsets.top -= overscan.top; 9239 inoutInsets.right -= overscan.right; 9240 inoutInsets.bottom -= overscan.bottom; 9241 return false; 9242 } 9243 } 9244 9245 /** 9246 * Compute insets that should be consumed by this view and the ones that should propagate 9247 * to those under it. 9248 * 9249 * @param in Insets currently being processed by this View, likely received as a parameter 9250 * to {@link #onApplyWindowInsets(WindowInsets)}. 9251 * @param outLocalInsets A Rect that will receive the insets that should be consumed 9252 * by this view 9253 * @return Insets that should be passed along to views under this one 9254 */ 9255 public WindowInsets computeSystemWindowInsets(WindowInsets in, Rect outLocalInsets) { 9256 if ((mViewFlags & OPTIONAL_FITS_SYSTEM_WINDOWS) == 0 9257 || mAttachInfo == null 9258 || (mAttachInfo.mSystemUiVisibility & SYSTEM_UI_LAYOUT_FLAGS) == 0) { 9259 outLocalInsets.set(in.getSystemWindowInsets()); 9260 return in.consumeSystemWindowInsets(); 9261 } else { 9262 outLocalInsets.set(0, 0, 0, 0); 9263 return in; 9264 } 9265 } 9266 9267 /** 9268 * Sets whether or not this view should account for system screen decorations 9269 * such as the status bar and inset its content; that is, controlling whether 9270 * the default implementation of {@link #fitSystemWindows(Rect)} will be 9271 * executed. See that method for more details. 9272 * 9273 * <p>Note that if you are providing your own implementation of 9274 * {@link #fitSystemWindows(Rect)}, then there is no need to set this 9275 * flag to true -- your implementation will be overriding the default 9276 * implementation that checks this flag. 9277 * 9278 * @param fitSystemWindows If true, then the default implementation of 9279 * {@link #fitSystemWindows(Rect)} will be executed. 9280 * 9281 * @attr ref android.R.styleable#View_fitsSystemWindows 9282 * @see #getFitsSystemWindows() 9283 * @see #fitSystemWindows(Rect) 9284 * @see #setSystemUiVisibility(int) 9285 */ 9286 public void setFitsSystemWindows(boolean fitSystemWindows) { 9287 setFlags(fitSystemWindows ? FITS_SYSTEM_WINDOWS : 0, FITS_SYSTEM_WINDOWS); 9288 } 9289 9290 /** 9291 * Check for state of {@link #setFitsSystemWindows(boolean)}. If this method 9292 * returns {@code true}, the default implementation of {@link #fitSystemWindows(Rect)} 9293 * will be executed. 9294 * 9295 * @return {@code true} if the default implementation of 9296 * {@link #fitSystemWindows(Rect)} will be executed. 9297 * 9298 * @attr ref android.R.styleable#View_fitsSystemWindows 9299 * @see #setFitsSystemWindows(boolean) 9300 * @see #fitSystemWindows(Rect) 9301 * @see #setSystemUiVisibility(int) 9302 */ 9303 @ViewDebug.ExportedProperty 9304 public boolean getFitsSystemWindows() { 9305 return (mViewFlags & FITS_SYSTEM_WINDOWS) == FITS_SYSTEM_WINDOWS; 9306 } 9307 9308 /** @hide */ 9309 public boolean fitsSystemWindows() { 9310 return getFitsSystemWindows(); 9311 } 9312 9313 /** 9314 * Ask that a new dispatch of {@link #fitSystemWindows(Rect)} be performed. 9315 * @deprecated Use {@link #requestApplyInsets()} for newer platform versions. 9316 */ 9317 @Deprecated 9318 public void requestFitSystemWindows() { 9319 if (mParent != null) { 9320 mParent.requestFitSystemWindows(); 9321 } 9322 } 9323 9324 /** 9325 * Ask that a new dispatch of {@link #onApplyWindowInsets(WindowInsets)} be performed. 9326 */ 9327 public void requestApplyInsets() { 9328 requestFitSystemWindows(); 9329 } 9330 9331 /** 9332 * For use by PhoneWindow to make its own system window fitting optional. 9333 * @hide 9334 */ 9335 public void makeOptionalFitsSystemWindows() { 9336 setFlags(OPTIONAL_FITS_SYSTEM_WINDOWS, OPTIONAL_FITS_SYSTEM_WINDOWS); 9337 } 9338 9339 /** 9340 * Returns the outsets, which areas of the device that aren't a surface, but we would like to 9341 * treat them as such. 9342 * @hide 9343 */ 9344 public void getOutsets(Rect outOutsetRect) { 9345 if (mAttachInfo != null) { 9346 outOutsetRect.set(mAttachInfo.mOutsets); 9347 } else { 9348 outOutsetRect.setEmpty(); 9349 } 9350 } 9351 9352 /** 9353 * Returns the visibility status for this view. 9354 * 9355 * @return One of {@link #VISIBLE}, {@link #INVISIBLE}, or {@link #GONE}. 9356 * @attr ref android.R.styleable#View_visibility 9357 */ 9358 @ViewDebug.ExportedProperty(mapping = { 9359 @ViewDebug.IntToString(from = VISIBLE, to = "VISIBLE"), 9360 @ViewDebug.IntToString(from = INVISIBLE, to = "INVISIBLE"), 9361 @ViewDebug.IntToString(from = GONE, to = "GONE") 9362 }) 9363 @Visibility 9364 public int getVisibility() { 9365 return mViewFlags & VISIBILITY_MASK; 9366 } 9367 9368 /** 9369 * Set the visibility state of this view. 9370 * 9371 * @param visibility One of {@link #VISIBLE}, {@link #INVISIBLE}, or {@link #GONE}. 9372 * @attr ref android.R.styleable#View_visibility 9373 */ 9374 @RemotableViewMethod 9375 public void setVisibility(@Visibility int visibility) { 9376 setFlags(visibility, VISIBILITY_MASK); 9377 } 9378 9379 /** 9380 * Returns the enabled status for this view. The interpretation of the 9381 * enabled state varies by subclass. 9382 * 9383 * @return True if this view is enabled, false otherwise. 9384 */ 9385 @ViewDebug.ExportedProperty 9386 public boolean isEnabled() { 9387 return (mViewFlags & ENABLED_MASK) == ENABLED; 9388 } 9389 9390 /** 9391 * Set the enabled state of this view. The interpretation of the enabled 9392 * state varies by subclass. 9393 * 9394 * @param enabled True if this view is enabled, false otherwise. 9395 */ 9396 @RemotableViewMethod 9397 public void setEnabled(boolean enabled) { 9398 if (enabled == isEnabled()) return; 9399 9400 setFlags(enabled ? ENABLED : DISABLED, ENABLED_MASK); 9401 9402 /* 9403 * The View most likely has to change its appearance, so refresh 9404 * the drawable state. 9405 */ 9406 refreshDrawableState(); 9407 9408 // Invalidate too, since the default behavior for views is to be 9409 // be drawn at 50% alpha rather than to change the drawable. 9410 invalidate(true); 9411 9412 if (!enabled) { 9413 cancelPendingInputEvents(); 9414 } 9415 } 9416 9417 /** 9418 * Set whether this view can receive the focus. 9419 * <p> 9420 * Setting this to false will also ensure that this view is not focusable 9421 * in touch mode. 9422 * 9423 * @param focusable If true, this view can receive the focus. 9424 * 9425 * @see #setFocusableInTouchMode(boolean) 9426 * @see #setFocusable(int) 9427 * @attr ref android.R.styleable#View_focusable 9428 */ 9429 public void setFocusable(boolean focusable) { 9430 setFocusable(focusable ? FOCUSABLE : NOT_FOCUSABLE); 9431 } 9432 9433 /** 9434 * Sets whether this view can receive focus. 9435 * <p> 9436 * Setting this to {@link #FOCUSABLE_AUTO} tells the framework to determine focusability 9437 * automatically based on the view's interactivity. This is the default. 9438 * <p> 9439 * Setting this to NOT_FOCUSABLE will ensure that this view is also not focusable 9440 * in touch mode. 9441 * 9442 * @param focusable One of {@link #NOT_FOCUSABLE}, {@link #FOCUSABLE}, 9443 * or {@link #FOCUSABLE_AUTO}. 9444 * @see #setFocusableInTouchMode(boolean) 9445 * @attr ref android.R.styleable#View_focusable 9446 */ 9447 public void setFocusable(@Focusable int focusable) { 9448 if ((focusable & (FOCUSABLE_AUTO | FOCUSABLE)) == 0) { 9449 setFlags(0, FOCUSABLE_IN_TOUCH_MODE); 9450 } 9451 setFlags(focusable, FOCUSABLE_MASK); 9452 } 9453 9454 /** 9455 * Set whether this view can receive focus while in touch mode. 9456 * 9457 * Setting this to true will also ensure that this view is focusable. 9458 * 9459 * @param focusableInTouchMode If true, this view can receive the focus while 9460 * in touch mode. 9461 * 9462 * @see #setFocusable(boolean) 9463 * @attr ref android.R.styleable#View_focusableInTouchMode 9464 */ 9465 public void setFocusableInTouchMode(boolean focusableInTouchMode) { 9466 // Focusable in touch mode should always be set before the focusable flag 9467 // otherwise, setting the focusable flag will trigger a focusableViewAvailable() 9468 // which, in touch mode, will not successfully request focus on this view 9469 // because the focusable in touch mode flag is not set 9470 setFlags(focusableInTouchMode ? FOCUSABLE_IN_TOUCH_MODE : 0, FOCUSABLE_IN_TOUCH_MODE); 9471 9472 // Clear FOCUSABLE_AUTO if set. 9473 if (focusableInTouchMode) { 9474 // Clears FOCUSABLE_AUTO if set. 9475 setFlags(FOCUSABLE, FOCUSABLE_MASK); 9476 } 9477 } 9478 9479 /** 9480 * Sets the hints that help an {@link android.service.autofill.AutofillService} determine how 9481 * to autofill the view with the user's data. 9482 * 9483 * <p>Typically, there is only one way to autofill a view, but there could be more than one. 9484 * For example, if the application accepts either an username or email address to identify 9485 * an user. 9486 * 9487 * <p>These hints are not validated by the Android System, but passed "as is" to the service. 9488 * Hence, they can have any value, but it's recommended to use the {@code AUTOFILL_HINT_} 9489 * constants such as: 9490 * {@link #AUTOFILL_HINT_USERNAME}, {@link #AUTOFILL_HINT_PASSWORD}, 9491 * {@link #AUTOFILL_HINT_EMAIL_ADDRESS}, 9492 * {@link #AUTOFILL_HINT_NAME}, 9493 * {@link #AUTOFILL_HINT_PHONE}, 9494 * {@link #AUTOFILL_HINT_POSTAL_ADDRESS}, {@link #AUTOFILL_HINT_POSTAL_CODE}, 9495 * {@link #AUTOFILL_HINT_CREDIT_CARD_NUMBER}, {@link #AUTOFILL_HINT_CREDIT_CARD_SECURITY_CODE}, 9496 * {@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE}, 9497 * {@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DAY}, 9498 * {@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH} or 9499 * {@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR}. 9500 * 9501 * @param autofillHints The autofill hints to set. If the array is emtpy, {@code null} is set. 9502 * @attr ref android.R.styleable#View_autofillHints 9503 */ 9504 public void setAutofillHints(@Nullable String... autofillHints) { 9505 if (autofillHints == null || autofillHints.length == 0) { 9506 mAutofillHints = null; 9507 } else { 9508 mAutofillHints = autofillHints; 9509 } 9510 } 9511 9512 /** 9513 * @hide 9514 */ 9515 @TestApi 9516 public void setAutofilled(boolean isAutofilled) { 9517 boolean wasChanged = isAutofilled != isAutofilled(); 9518 9519 if (wasChanged) { 9520 if (isAutofilled) { 9521 mPrivateFlags3 |= PFLAG3_IS_AUTOFILLED; 9522 } else { 9523 mPrivateFlags3 &= ~PFLAG3_IS_AUTOFILLED; 9524 } 9525 9526 invalidate(); 9527 } 9528 } 9529 9530 /** 9531 * Set whether this view should have sound effects enabled for events such as 9532 * clicking and touching. 9533 * 9534 * <p>You may wish to disable sound effects for a view if you already play sounds, 9535 * for instance, a dial key that plays dtmf tones. 9536 * 9537 * @param soundEffectsEnabled whether sound effects are enabled for this view. 9538 * @see #isSoundEffectsEnabled() 9539 * @see #playSoundEffect(int) 9540 * @attr ref android.R.styleable#View_soundEffectsEnabled 9541 */ 9542 public void setSoundEffectsEnabled(boolean soundEffectsEnabled) { 9543 setFlags(soundEffectsEnabled ? SOUND_EFFECTS_ENABLED: 0, SOUND_EFFECTS_ENABLED); 9544 } 9545 9546 /** 9547 * @return whether this view should have sound effects enabled for events such as 9548 * clicking and touching. 9549 * 9550 * @see #setSoundEffectsEnabled(boolean) 9551 * @see #playSoundEffect(int) 9552 * @attr ref android.R.styleable#View_soundEffectsEnabled 9553 */ 9554 @ViewDebug.ExportedProperty 9555 public boolean isSoundEffectsEnabled() { 9556 return SOUND_EFFECTS_ENABLED == (mViewFlags & SOUND_EFFECTS_ENABLED); 9557 } 9558 9559 /** 9560 * Set whether this view should have haptic feedback for events such as 9561 * long presses. 9562 * 9563 * <p>You may wish to disable haptic feedback if your view already controls 9564 * its own haptic feedback. 9565 * 9566 * @param hapticFeedbackEnabled whether haptic feedback enabled for this view. 9567 * @see #isHapticFeedbackEnabled() 9568 * @see #performHapticFeedback(int) 9569 * @attr ref android.R.styleable#View_hapticFeedbackEnabled 9570 */ 9571 public void setHapticFeedbackEnabled(boolean hapticFeedbackEnabled) { 9572 setFlags(hapticFeedbackEnabled ? HAPTIC_FEEDBACK_ENABLED: 0, HAPTIC_FEEDBACK_ENABLED); 9573 } 9574 9575 /** 9576 * @return whether this view should have haptic feedback enabled for events 9577 * long presses. 9578 * 9579 * @see #setHapticFeedbackEnabled(boolean) 9580 * @see #performHapticFeedback(int) 9581 * @attr ref android.R.styleable#View_hapticFeedbackEnabled 9582 */ 9583 @ViewDebug.ExportedProperty 9584 public boolean isHapticFeedbackEnabled() { 9585 return HAPTIC_FEEDBACK_ENABLED == (mViewFlags & HAPTIC_FEEDBACK_ENABLED); 9586 } 9587 9588 /** 9589 * Returns the layout direction for this view. 9590 * 9591 * @return One of {@link #LAYOUT_DIRECTION_LTR}, 9592 * {@link #LAYOUT_DIRECTION_RTL}, 9593 * {@link #LAYOUT_DIRECTION_INHERIT} or 9594 * {@link #LAYOUT_DIRECTION_LOCALE}. 9595 * 9596 * @attr ref android.R.styleable#View_layoutDirection 9597 * 9598 * @hide 9599 */ 9600 @ViewDebug.ExportedProperty(category = "layout", mapping = { 9601 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_LTR, to = "LTR"), 9602 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_RTL, to = "RTL"), 9603 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_INHERIT, to = "INHERIT"), 9604 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_LOCALE, to = "LOCALE") 9605 }) 9606 @LayoutDir 9607 public int getRawLayoutDirection() { 9608 return (mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_MASK) >> PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 9609 } 9610 9611 /** 9612 * Set the layout direction for this view. This will propagate a reset of layout direction 9613 * resolution to the view's children and resolve layout direction for this view. 9614 * 9615 * @param layoutDirection the layout direction to set. Should be one of: 9616 * 9617 * {@link #LAYOUT_DIRECTION_LTR}, 9618 * {@link #LAYOUT_DIRECTION_RTL}, 9619 * {@link #LAYOUT_DIRECTION_INHERIT}, 9620 * {@link #LAYOUT_DIRECTION_LOCALE}. 9621 * 9622 * Resolution will be done if the value is set to LAYOUT_DIRECTION_INHERIT. The resolution 9623 * proceeds up the parent chain of the view to get the value. If there is no parent, then it 9624 * will return the default {@link #LAYOUT_DIRECTION_LTR}. 9625 * 9626 * @attr ref android.R.styleable#View_layoutDirection 9627 */ 9628 @RemotableViewMethod 9629 public void setLayoutDirection(@LayoutDir int layoutDirection) { 9630 if (getRawLayoutDirection() != layoutDirection) { 9631 // Reset the current layout direction and the resolved one 9632 mPrivateFlags2 &= ~PFLAG2_LAYOUT_DIRECTION_MASK; 9633 resetRtlProperties(); 9634 // Set the new layout direction (filtered) 9635 mPrivateFlags2 |= 9636 ((layoutDirection << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT) & PFLAG2_LAYOUT_DIRECTION_MASK); 9637 // We need to resolve all RTL properties as they all depend on layout direction 9638 resolveRtlPropertiesIfNeeded(); 9639 requestLayout(); 9640 invalidate(true); 9641 } 9642 } 9643 9644 /** 9645 * Returns the resolved layout direction for this view. 9646 * 9647 * @return {@link #LAYOUT_DIRECTION_RTL} if the layout direction is RTL or returns 9648 * {@link #LAYOUT_DIRECTION_LTR} if the layout direction is not RTL. 9649 * 9650 * For compatibility, this will return {@link #LAYOUT_DIRECTION_LTR} if API version 9651 * is lower than {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR1}. 9652 * 9653 * @attr ref android.R.styleable#View_layoutDirection 9654 */ 9655 @ViewDebug.ExportedProperty(category = "layout", mapping = { 9656 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_LTR, to = "RESOLVED_DIRECTION_LTR"), 9657 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_RTL, to = "RESOLVED_DIRECTION_RTL") 9658 }) 9659 @ResolvedLayoutDir 9660 public int getLayoutDirection() { 9661 final int targetSdkVersion = getContext().getApplicationInfo().targetSdkVersion; 9662 if (targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR1) { 9663 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED; 9664 return LAYOUT_DIRECTION_RESOLVED_DEFAULT; 9665 } 9666 return ((mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL) == 9667 PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL) ? LAYOUT_DIRECTION_RTL : LAYOUT_DIRECTION_LTR; 9668 } 9669 9670 /** 9671 * Indicates whether or not this view's layout is right-to-left. This is resolved from 9672 * layout attribute and/or the inherited value from the parent 9673 * 9674 * @return true if the layout is right-to-left. 9675 * 9676 * @hide 9677 */ 9678 @ViewDebug.ExportedProperty(category = "layout") 9679 public boolean isLayoutRtl() { 9680 return (getLayoutDirection() == LAYOUT_DIRECTION_RTL); 9681 } 9682 9683 /** 9684 * Indicates whether the view is currently tracking transient state that the 9685 * app should not need to concern itself with saving and restoring, but that 9686 * the framework should take special note to preserve when possible. 9687 * 9688 * <p>A view with transient state cannot be trivially rebound from an external 9689 * data source, such as an adapter binding item views in a list. This may be 9690 * because the view is performing an animation, tracking user selection 9691 * of content, or similar.</p> 9692 * 9693 * @return true if the view has transient state 9694 */ 9695 @ViewDebug.ExportedProperty(category = "layout") 9696 public boolean hasTransientState() { 9697 return (mPrivateFlags2 & PFLAG2_HAS_TRANSIENT_STATE) == PFLAG2_HAS_TRANSIENT_STATE; 9698 } 9699 9700 /** 9701 * Set whether this view is currently tracking transient state that the 9702 * framework should attempt to preserve when possible. This flag is reference counted, 9703 * so every call to setHasTransientState(true) should be paired with a later call 9704 * to setHasTransientState(false). 9705 * 9706 * <p>A view with transient state cannot be trivially rebound from an external 9707 * data source, such as an adapter binding item views in a list. This may be 9708 * because the view is performing an animation, tracking user selection 9709 * of content, or similar.</p> 9710 * 9711 * @param hasTransientState true if this view has transient state 9712 */ 9713 public void setHasTransientState(boolean hasTransientState) { 9714 mTransientStateCount = hasTransientState ? mTransientStateCount + 1 : 9715 mTransientStateCount - 1; 9716 if (mTransientStateCount < 0) { 9717 mTransientStateCount = 0; 9718 Log.e(VIEW_LOG_TAG, "hasTransientState decremented below 0: " + 9719 "unmatched pair of setHasTransientState calls"); 9720 } else if ((hasTransientState && mTransientStateCount == 1) || 9721 (!hasTransientState && mTransientStateCount == 0)) { 9722 // update flag if we've just incremented up from 0 or decremented down to 0 9723 mPrivateFlags2 = (mPrivateFlags2 & ~PFLAG2_HAS_TRANSIENT_STATE) | 9724 (hasTransientState ? PFLAG2_HAS_TRANSIENT_STATE : 0); 9725 if (mParent != null) { 9726 try { 9727 mParent.childHasTransientStateChanged(this, hasTransientState); 9728 } catch (AbstractMethodError e) { 9729 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 9730 " does not fully implement ViewParent", e); 9731 } 9732 } 9733 } 9734 } 9735 9736 /** 9737 * Returns true if this view is currently attached to a window. 9738 */ 9739 public boolean isAttachedToWindow() { 9740 return mAttachInfo != null; 9741 } 9742 9743 /** 9744 * Returns true if this view has been through at least one layout since it 9745 * was last attached to or detached from a window. 9746 */ 9747 public boolean isLaidOut() { 9748 return (mPrivateFlags3 & PFLAG3_IS_LAID_OUT) == PFLAG3_IS_LAID_OUT; 9749 } 9750 9751 /** 9752 * If this view doesn't do any drawing on its own, set this flag to 9753 * allow further optimizations. By default, this flag is not set on 9754 * View, but could be set on some View subclasses such as ViewGroup. 9755 * 9756 * Typically, if you override {@link #onDraw(android.graphics.Canvas)} 9757 * you should clear this flag. 9758 * 9759 * @param willNotDraw whether or not this View draw on its own 9760 */ 9761 public void setWillNotDraw(boolean willNotDraw) { 9762 setFlags(willNotDraw ? WILL_NOT_DRAW : 0, DRAW_MASK); 9763 } 9764 9765 /** 9766 * Returns whether or not this View draws on its own. 9767 * 9768 * @return true if this view has nothing to draw, false otherwise 9769 */ 9770 @ViewDebug.ExportedProperty(category = "drawing") 9771 public boolean willNotDraw() { 9772 return (mViewFlags & DRAW_MASK) == WILL_NOT_DRAW; 9773 } 9774 9775 /** 9776 * When a View's drawing cache is enabled, drawing is redirected to an 9777 * offscreen bitmap. Some views, like an ImageView, must be able to 9778 * bypass this mechanism if they already draw a single bitmap, to avoid 9779 * unnecessary usage of the memory. 9780 * 9781 * @param willNotCacheDrawing true if this view does not cache its 9782 * drawing, false otherwise 9783 */ 9784 public void setWillNotCacheDrawing(boolean willNotCacheDrawing) { 9785 setFlags(willNotCacheDrawing ? WILL_NOT_CACHE_DRAWING : 0, WILL_NOT_CACHE_DRAWING); 9786 } 9787 9788 /** 9789 * Returns whether or not this View can cache its drawing or not. 9790 * 9791 * @return true if this view does not cache its drawing, false otherwise 9792 */ 9793 @ViewDebug.ExportedProperty(category = "drawing") 9794 public boolean willNotCacheDrawing() { 9795 return (mViewFlags & WILL_NOT_CACHE_DRAWING) == WILL_NOT_CACHE_DRAWING; 9796 } 9797 9798 /** 9799 * Indicates whether this view reacts to click events or not. 9800 * 9801 * @return true if the view is clickable, false otherwise 9802 * 9803 * @see #setClickable(boolean) 9804 * @attr ref android.R.styleable#View_clickable 9805 */ 9806 @ViewDebug.ExportedProperty 9807 public boolean isClickable() { 9808 return (mViewFlags & CLICKABLE) == CLICKABLE; 9809 } 9810 9811 /** 9812 * Enables or disables click events for this view. When a view 9813 * is clickable it will change its state to "pressed" on every click. 9814 * Subclasses should set the view clickable to visually react to 9815 * user's clicks. 9816 * 9817 * @param clickable true to make the view clickable, false otherwise 9818 * 9819 * @see #isClickable() 9820 * @attr ref android.R.styleable#View_clickable 9821 */ 9822 public void setClickable(boolean clickable) { 9823 setFlags(clickable ? CLICKABLE : 0, CLICKABLE); 9824 } 9825 9826 /** 9827 * Indicates whether this view reacts to long click events or not. 9828 * 9829 * @return true if the view is long clickable, false otherwise 9830 * 9831 * @see #setLongClickable(boolean) 9832 * @attr ref android.R.styleable#View_longClickable 9833 */ 9834 public boolean isLongClickable() { 9835 return (mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE; 9836 } 9837 9838 /** 9839 * Enables or disables long click events for this view. When a view is long 9840 * clickable it reacts to the user holding down the button for a longer 9841 * duration than a tap. This event can either launch the listener or a 9842 * context menu. 9843 * 9844 * @param longClickable true to make the view long clickable, false otherwise 9845 * @see #isLongClickable() 9846 * @attr ref android.R.styleable#View_longClickable 9847 */ 9848 public void setLongClickable(boolean longClickable) { 9849 setFlags(longClickable ? LONG_CLICKABLE : 0, LONG_CLICKABLE); 9850 } 9851 9852 /** 9853 * Indicates whether this view reacts to context clicks or not. 9854 * 9855 * @return true if the view is context clickable, false otherwise 9856 * @see #setContextClickable(boolean) 9857 * @attr ref android.R.styleable#View_contextClickable 9858 */ 9859 public boolean isContextClickable() { 9860 return (mViewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE; 9861 } 9862 9863 /** 9864 * Enables or disables context clicking for this view. This event can launch the listener. 9865 * 9866 * @param contextClickable true to make the view react to a context click, false otherwise 9867 * @see #isContextClickable() 9868 * @attr ref android.R.styleable#View_contextClickable 9869 */ 9870 public void setContextClickable(boolean contextClickable) { 9871 setFlags(contextClickable ? CONTEXT_CLICKABLE : 0, CONTEXT_CLICKABLE); 9872 } 9873 9874 /** 9875 * Sets the pressed state for this view and provides a touch coordinate for 9876 * animation hinting. 9877 * 9878 * @param pressed Pass true to set the View's internal state to "pressed", 9879 * or false to reverts the View's internal state from a 9880 * previously set "pressed" state. 9881 * @param x The x coordinate of the touch that caused the press 9882 * @param y The y coordinate of the touch that caused the press 9883 */ 9884 private void setPressed(boolean pressed, float x, float y) { 9885 if (pressed) { 9886 drawableHotspotChanged(x, y); 9887 } 9888 9889 setPressed(pressed); 9890 } 9891 9892 /** 9893 * Sets the pressed state for this view. 9894 * 9895 * @see #isClickable() 9896 * @see #setClickable(boolean) 9897 * 9898 * @param pressed Pass true to set the View's internal state to "pressed", or false to reverts 9899 * the View's internal state from a previously set "pressed" state. 9900 */ 9901 public void setPressed(boolean pressed) { 9902 final boolean needsRefresh = pressed != ((mPrivateFlags & PFLAG_PRESSED) == PFLAG_PRESSED); 9903 9904 if (pressed) { 9905 mPrivateFlags |= PFLAG_PRESSED; 9906 } else { 9907 mPrivateFlags &= ~PFLAG_PRESSED; 9908 } 9909 9910 if (needsRefresh) { 9911 refreshDrawableState(); 9912 } 9913 dispatchSetPressed(pressed); 9914 } 9915 9916 /** 9917 * Dispatch setPressed to all of this View's children. 9918 * 9919 * @see #setPressed(boolean) 9920 * 9921 * @param pressed The new pressed state 9922 */ 9923 protected void dispatchSetPressed(boolean pressed) { 9924 } 9925 9926 /** 9927 * Indicates whether the view is currently in pressed state. Unless 9928 * {@link #setPressed(boolean)} is explicitly called, only clickable views can enter 9929 * the pressed state. 9930 * 9931 * @see #setPressed(boolean) 9932 * @see #isClickable() 9933 * @see #setClickable(boolean) 9934 * 9935 * @return true if the view is currently pressed, false otherwise 9936 */ 9937 @ViewDebug.ExportedProperty 9938 public boolean isPressed() { 9939 return (mPrivateFlags & PFLAG_PRESSED) == PFLAG_PRESSED; 9940 } 9941 9942 /** 9943 * @hide 9944 * Indicates whether this view will participate in data collection through 9945 * {@link ViewStructure}. If true, it will not provide any data 9946 * for itself or its children. If false, the normal data collection will be allowed. 9947 * 9948 * @return Returns false if assist data collection is not blocked, else true. 9949 * 9950 * @see #setAssistBlocked(boolean) 9951 * @attr ref android.R.styleable#View_assistBlocked 9952 */ 9953 public boolean isAssistBlocked() { 9954 return (mPrivateFlags3 & PFLAG3_ASSIST_BLOCKED) != 0; 9955 } 9956 9957 /** 9958 * @hide 9959 * Controls whether assist data collection from this view and its children is enabled 9960 * (that is, whether {@link #onProvideStructure} and 9961 * {@link #onProvideVirtualStructure} will be called). The default value is false, 9962 * allowing normal assist collection. Setting this to false will disable assist collection. 9963 * 9964 * @param enabled Set to true to <em>disable</em> assist data collection, or false 9965 * (the default) to allow it. 9966 * 9967 * @see #isAssistBlocked() 9968 * @see #onProvideStructure 9969 * @see #onProvideVirtualStructure 9970 * @attr ref android.R.styleable#View_assistBlocked 9971 */ 9972 public void setAssistBlocked(boolean enabled) { 9973 if (enabled) { 9974 mPrivateFlags3 |= PFLAG3_ASSIST_BLOCKED; 9975 } else { 9976 mPrivateFlags3 &= ~PFLAG3_ASSIST_BLOCKED; 9977 } 9978 } 9979 9980 /** 9981 * Indicates whether this view will save its state (that is, 9982 * whether its {@link #onSaveInstanceState} method will be called). 9983 * 9984 * @return Returns true if the view state saving is enabled, else false. 9985 * 9986 * @see #setSaveEnabled(boolean) 9987 * @attr ref android.R.styleable#View_saveEnabled 9988 */ 9989 public boolean isSaveEnabled() { 9990 return (mViewFlags & SAVE_DISABLED_MASK) != SAVE_DISABLED; 9991 } 9992 9993 /** 9994 * Controls whether the saving of this view's state is 9995 * enabled (that is, whether its {@link #onSaveInstanceState} method 9996 * will be called). Note that even if freezing is enabled, the 9997 * view still must have an id assigned to it (via {@link #setId(int)}) 9998 * for its state to be saved. This flag can only disable the 9999 * saving of this view; any child views may still have their state saved. 10000 * 10001 * @param enabled Set to false to <em>disable</em> state saving, or true 10002 * (the default) to allow it. 10003 * 10004 * @see #isSaveEnabled() 10005 * @see #setId(int) 10006 * @see #onSaveInstanceState() 10007 * @attr ref android.R.styleable#View_saveEnabled 10008 */ 10009 public void setSaveEnabled(boolean enabled) { 10010 setFlags(enabled ? 0 : SAVE_DISABLED, SAVE_DISABLED_MASK); 10011 } 10012 10013 /** 10014 * Gets whether the framework should discard touches when the view's 10015 * window is obscured by another visible window. 10016 * Refer to the {@link View} security documentation for more details. 10017 * 10018 * @return True if touch filtering is enabled. 10019 * 10020 * @see #setFilterTouchesWhenObscured(boolean) 10021 * @attr ref android.R.styleable#View_filterTouchesWhenObscured 10022 */ 10023 @ViewDebug.ExportedProperty 10024 public boolean getFilterTouchesWhenObscured() { 10025 return (mViewFlags & FILTER_TOUCHES_WHEN_OBSCURED) != 0; 10026 } 10027 10028 /** 10029 * Sets whether the framework should discard touches when the view's 10030 * window is obscured by another visible window. 10031 * Refer to the {@link View} security documentation for more details. 10032 * 10033 * @param enabled True if touch filtering should be enabled. 10034 * 10035 * @see #getFilterTouchesWhenObscured 10036 * @attr ref android.R.styleable#View_filterTouchesWhenObscured 10037 */ 10038 public void setFilterTouchesWhenObscured(boolean enabled) { 10039 setFlags(enabled ? FILTER_TOUCHES_WHEN_OBSCURED : 0, 10040 FILTER_TOUCHES_WHEN_OBSCURED); 10041 } 10042 10043 /** 10044 * Indicates whether the entire hierarchy under this view will save its 10045 * state when a state saving traversal occurs from its parent. The default 10046 * is true; if false, these views will not be saved unless 10047 * {@link #saveHierarchyState(SparseArray)} is called directly on this view. 10048 * 10049 * @return Returns true if the view state saving from parent is enabled, else false. 10050 * 10051 * @see #setSaveFromParentEnabled(boolean) 10052 */ 10053 public boolean isSaveFromParentEnabled() { 10054 return (mViewFlags & PARENT_SAVE_DISABLED_MASK) != PARENT_SAVE_DISABLED; 10055 } 10056 10057 /** 10058 * Controls whether the entire hierarchy under this view will save its 10059 * state when a state saving traversal occurs from its parent. The default 10060 * is true; if false, these views will not be saved unless 10061 * {@link #saveHierarchyState(SparseArray)} is called directly on this view. 10062 * 10063 * @param enabled Set to false to <em>disable</em> state saving, or true 10064 * (the default) to allow it. 10065 * 10066 * @see #isSaveFromParentEnabled() 10067 * @see #setId(int) 10068 * @see #onSaveInstanceState() 10069 */ 10070 public void setSaveFromParentEnabled(boolean enabled) { 10071 setFlags(enabled ? 0 : PARENT_SAVE_DISABLED, PARENT_SAVE_DISABLED_MASK); 10072 } 10073 10074 10075 /** 10076 * Returns whether this View is currently able to take focus. 10077 * 10078 * @return True if this view can take focus, or false otherwise. 10079 */ 10080 @ViewDebug.ExportedProperty(category = "focus") 10081 public final boolean isFocusable() { 10082 return FOCUSABLE == (mViewFlags & FOCUSABLE); 10083 } 10084 10085 /** 10086 * Returns the focusable setting for this view. 10087 * 10088 * @return One of {@link #NOT_FOCUSABLE}, {@link #FOCUSABLE}, or {@link #FOCUSABLE_AUTO}. 10089 * @attr ref android.R.styleable#View_focusable 10090 */ 10091 @ViewDebug.ExportedProperty(mapping = { 10092 @ViewDebug.IntToString(from = NOT_FOCUSABLE, to = "NOT_FOCUSABLE"), 10093 @ViewDebug.IntToString(from = FOCUSABLE, to = "FOCUSABLE"), 10094 @ViewDebug.IntToString(from = FOCUSABLE_AUTO, to = "FOCUSABLE_AUTO") 10095 }, category = "focus") 10096 @Focusable 10097 public int getFocusable() { 10098 return (mViewFlags & FOCUSABLE_AUTO) > 0 ? FOCUSABLE_AUTO : mViewFlags & FOCUSABLE; 10099 } 10100 10101 /** 10102 * When a view is focusable, it may not want to take focus when in touch mode. 10103 * For example, a button would like focus when the user is navigating via a D-pad 10104 * so that the user can click on it, but once the user starts touching the screen, 10105 * the button shouldn't take focus 10106 * @return Whether the view is focusable in touch mode. 10107 * @attr ref android.R.styleable#View_focusableInTouchMode 10108 */ 10109 @ViewDebug.ExportedProperty(category = "focus") 10110 public final boolean isFocusableInTouchMode() { 10111 return FOCUSABLE_IN_TOUCH_MODE == (mViewFlags & FOCUSABLE_IN_TOUCH_MODE); 10112 } 10113 10114 /** 10115 * Find the nearest view in the specified direction that can take focus. 10116 * This does not actually give focus to that view. 10117 * 10118 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT 10119 * 10120 * @return The nearest focusable in the specified direction, or null if none 10121 * can be found. 10122 */ 10123 public View focusSearch(@FocusRealDirection int direction) { 10124 if (mParent != null) { 10125 return mParent.focusSearch(this, direction); 10126 } else { 10127 return null; 10128 } 10129 } 10130 10131 /** 10132 * Returns whether this View is a root of a keyboard navigation cluster. 10133 * 10134 * @return True if this view is a root of a cluster, or false otherwise. 10135 * @attr ref android.R.styleable#View_keyboardNavigationCluster 10136 */ 10137 @ViewDebug.ExportedProperty(category = "focus") 10138 public final boolean isKeyboardNavigationCluster() { 10139 return (mPrivateFlags3 & PFLAG3_CLUSTER) != 0; 10140 } 10141 10142 /** 10143 * Searches up the view hierarchy to find the top-most cluster. All deeper/nested clusters 10144 * will be ignored. 10145 * 10146 * @return the keyboard navigation cluster that this view is in (can be this view) 10147 * or {@code null} if not in one 10148 */ 10149 View findKeyboardNavigationCluster() { 10150 if (mParent instanceof View) { 10151 View cluster = ((View) mParent).findKeyboardNavigationCluster(); 10152 if (cluster != null) { 10153 return cluster; 10154 } else if (isKeyboardNavigationCluster()) { 10155 return this; 10156 } 10157 } 10158 return null; 10159 } 10160 10161 /** 10162 * Set whether this view is a root of a keyboard navigation cluster. 10163 * 10164 * @param isCluster If true, this view is a root of a cluster. 10165 * 10166 * @attr ref android.R.styleable#View_keyboardNavigationCluster 10167 */ 10168 public void setKeyboardNavigationCluster(boolean isCluster) { 10169 if (isCluster) { 10170 mPrivateFlags3 |= PFLAG3_CLUSTER; 10171 } else { 10172 mPrivateFlags3 &= ~PFLAG3_CLUSTER; 10173 } 10174 } 10175 10176 /** 10177 * Sets this View as the one which receives focus the next time cluster navigation jumps 10178 * to the cluster containing this View. This does NOT change focus even if the cluster 10179 * containing this view is current. 10180 * 10181 * @hide 10182 */ 10183 @TestApi 10184 public final void setFocusedInCluster() { 10185 setFocusedInCluster(findKeyboardNavigationCluster()); 10186 } 10187 10188 private void setFocusedInCluster(View cluster) { 10189 if (this instanceof ViewGroup) { 10190 ((ViewGroup) this).mFocusedInCluster = null; 10191 } 10192 if (cluster == this) { 10193 return; 10194 } 10195 ViewParent parent = mParent; 10196 View child = this; 10197 while (parent instanceof ViewGroup) { 10198 ((ViewGroup) parent).mFocusedInCluster = child; 10199 if (parent == cluster) { 10200 break; 10201 } 10202 child = (View) parent; 10203 parent = parent.getParent(); 10204 } 10205 } 10206 10207 private void updateFocusedInCluster(View oldFocus, @FocusDirection int direction) { 10208 if (oldFocus != null) { 10209 View oldCluster = oldFocus.findKeyboardNavigationCluster(); 10210 View cluster = findKeyboardNavigationCluster(); 10211 if (oldCluster != cluster) { 10212 // Going from one cluster to another, so save last-focused. 10213 // This covers cluster jumps because they are always FOCUS_DOWN 10214 oldFocus.setFocusedInCluster(oldCluster); 10215 if (!(oldFocus.mParent instanceof ViewGroup)) { 10216 return; 10217 } 10218 if (direction == FOCUS_FORWARD || direction == FOCUS_BACKWARD) { 10219 // This is a result of ordered navigation so consider navigation through 10220 // the previous cluster "complete" and clear its last-focused memory. 10221 ((ViewGroup) oldFocus.mParent).clearFocusedInCluster(oldFocus); 10222 } else if (oldFocus instanceof ViewGroup 10223 && ((ViewGroup) oldFocus).getDescendantFocusability() 10224 == ViewGroup.FOCUS_AFTER_DESCENDANTS 10225 && ViewRootImpl.isViewDescendantOf(this, oldFocus)) { 10226 // This means oldFocus is not focusable since it obviously has a focusable 10227 // child (this). Don't restore focus to it in the future. 10228 ((ViewGroup) oldFocus.mParent).clearFocusedInCluster(oldFocus); 10229 } 10230 } 10231 } 10232 } 10233 10234 /** 10235 * Returns whether this View should receive focus when the focus is restored for the view 10236 * hierarchy containing this view. 10237 * <p> 10238 * Focus gets restored for a view hierarchy when the root of the hierarchy gets added to a 10239 * window or serves as a target of cluster navigation. 10240 * 10241 * @see #restoreDefaultFocus() 10242 * 10243 * @return {@code true} if this view is the default-focus view, {@code false} otherwise 10244 * @attr ref android.R.styleable#View_focusedByDefault 10245 */ 10246 @ViewDebug.ExportedProperty(category = "focus") 10247 public final boolean isFocusedByDefault() { 10248 return (mPrivateFlags3 & PFLAG3_FOCUSED_BY_DEFAULT) != 0; 10249 } 10250 10251 /** 10252 * Sets whether this View should receive focus when the focus is restored for the view 10253 * hierarchy containing this view. 10254 * <p> 10255 * Focus gets restored for a view hierarchy when the root of the hierarchy gets added to a 10256 * window or serves as a target of cluster navigation. 10257 * 10258 * @param isFocusedByDefault {@code true} to set this view as the default-focus view, 10259 * {@code false} otherwise. 10260 * 10261 * @see #restoreDefaultFocus() 10262 * 10263 * @attr ref android.R.styleable#View_focusedByDefault 10264 */ 10265 public void setFocusedByDefault(boolean isFocusedByDefault) { 10266 if (isFocusedByDefault == ((mPrivateFlags3 & PFLAG3_FOCUSED_BY_DEFAULT) != 0)) { 10267 return; 10268 } 10269 10270 if (isFocusedByDefault) { 10271 mPrivateFlags3 |= PFLAG3_FOCUSED_BY_DEFAULT; 10272 } else { 10273 mPrivateFlags3 &= ~PFLAG3_FOCUSED_BY_DEFAULT; 10274 } 10275 10276 if (mParent instanceof ViewGroup) { 10277 if (isFocusedByDefault) { 10278 ((ViewGroup) mParent).setDefaultFocus(this); 10279 } else { 10280 ((ViewGroup) mParent).clearDefaultFocus(this); 10281 } 10282 } 10283 } 10284 10285 /** 10286 * Returns whether the view hierarchy with this view as a root contain a default-focus view. 10287 * 10288 * @return {@code true} if this view has default focus, {@code false} otherwise 10289 */ 10290 boolean hasDefaultFocus() { 10291 return isFocusedByDefault(); 10292 } 10293 10294 /** 10295 * Find the nearest keyboard navigation cluster in the specified direction. 10296 * This does not actually give focus to that cluster. 10297 * 10298 * @param currentCluster The starting point of the search. Null means the current cluster is not 10299 * found yet 10300 * @param direction Direction to look 10301 * 10302 * @return The nearest keyboard navigation cluster in the specified direction, or null if none 10303 * can be found 10304 */ 10305 public View keyboardNavigationClusterSearch(View currentCluster, 10306 @FocusDirection int direction) { 10307 if (isKeyboardNavigationCluster()) { 10308 currentCluster = this; 10309 } 10310 if (isRootNamespace()) { 10311 // Root namespace means we should consider ourselves the top of the 10312 // tree for group searching; otherwise we could be group searching 10313 // into other tabs. see LocalActivityManager and TabHost for more info. 10314 return FocusFinder.getInstance().findNextKeyboardNavigationCluster( 10315 this, currentCluster, direction); 10316 } else if (mParent != null) { 10317 return mParent.keyboardNavigationClusterSearch(currentCluster, direction); 10318 } 10319 return null; 10320 } 10321 10322 /** 10323 * This method is the last chance for the focused view and its ancestors to 10324 * respond to an arrow key. This is called when the focused view did not 10325 * consume the key internally, nor could the view system find a new view in 10326 * the requested direction to give focus to. 10327 * 10328 * @param focused The currently focused view. 10329 * @param direction The direction focus wants to move. One of FOCUS_UP, 10330 * FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT. 10331 * @return True if the this view consumed this unhandled move. 10332 */ 10333 public boolean dispatchUnhandledMove(View focused, @FocusRealDirection int direction) { 10334 return false; 10335 } 10336 10337 /** 10338 * Sets whether this View should use a default focus highlight when it gets focused but doesn't 10339 * have {@link android.R.attr#state_focused} defined in its background. 10340 * 10341 * @param defaultFocusHighlightEnabled {@code true} to set this view to use a default focus 10342 * highlight, {@code false} otherwise. 10343 * 10344 * @attr ref android.R.styleable#View_defaultFocusHighlightEnabled 10345 */ 10346 public void setDefaultFocusHighlightEnabled(boolean defaultFocusHighlightEnabled) { 10347 mDefaultFocusHighlightEnabled = defaultFocusHighlightEnabled; 10348 } 10349 10350 /** 10351 10352 /** 10353 * Returns whether this View should use a default focus highlight when it gets focused but 10354 * doesn't have {@link android.R.attr#state_focused} defined in its background. 10355 * 10356 * @return True if this View should use a default focus highlight. 10357 * @attr ref android.R.styleable#View_defaultFocusHighlightEnabled 10358 */ 10359 @ViewDebug.ExportedProperty(category = "focus") 10360 public final boolean getDefaultFocusHighlightEnabled() { 10361 return mDefaultFocusHighlightEnabled; 10362 } 10363 10364 /** 10365 * If a user manually specified the next view id for a particular direction, 10366 * use the root to look up the view. 10367 * @param root The root view of the hierarchy containing this view. 10368 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, FOCUS_RIGHT, FOCUS_FORWARD, 10369 * or FOCUS_BACKWARD. 10370 * @return The user specified next view, or null if there is none. 10371 */ 10372 View findUserSetNextFocus(View root, @FocusDirection int direction) { 10373 switch (direction) { 10374 case FOCUS_LEFT: 10375 if (mNextFocusLeftId == View.NO_ID) return null; 10376 return findViewInsideOutShouldExist(root, mNextFocusLeftId); 10377 case FOCUS_RIGHT: 10378 if (mNextFocusRightId == View.NO_ID) return null; 10379 return findViewInsideOutShouldExist(root, mNextFocusRightId); 10380 case FOCUS_UP: 10381 if (mNextFocusUpId == View.NO_ID) return null; 10382 return findViewInsideOutShouldExist(root, mNextFocusUpId); 10383 case FOCUS_DOWN: 10384 if (mNextFocusDownId == View.NO_ID) return null; 10385 return findViewInsideOutShouldExist(root, mNextFocusDownId); 10386 case FOCUS_FORWARD: 10387 if (mNextFocusForwardId == View.NO_ID) return null; 10388 return findViewInsideOutShouldExist(root, mNextFocusForwardId); 10389 case FOCUS_BACKWARD: { 10390 if (mID == View.NO_ID) return null; 10391 final int id = mID; 10392 return root.findViewByPredicateInsideOut(this, new Predicate<View>() { 10393 @Override 10394 public boolean test(View t) { 10395 return t.mNextFocusForwardId == id; 10396 } 10397 }); 10398 } 10399 } 10400 return null; 10401 } 10402 10403 /** 10404 * If a user manually specified the next keyboard-navigation cluster for a particular direction, 10405 * use the root to look up the view. 10406 * 10407 * @param root the root view of the hierarchy containing this view 10408 * @param direction {@link #FOCUS_FORWARD} or {@link #FOCUS_BACKWARD} 10409 * @return the user-specified next cluster, or {@code null} if there is none 10410 */ 10411 View findUserSetNextKeyboardNavigationCluster(View root, @FocusDirection int direction) { 10412 switch (direction) { 10413 case FOCUS_FORWARD: 10414 if (mNextClusterForwardId == View.NO_ID) return null; 10415 return findViewInsideOutShouldExist(root, mNextClusterForwardId); 10416 case FOCUS_BACKWARD: { 10417 if (mID == View.NO_ID) return null; 10418 final int id = mID; 10419 return root.findViewByPredicateInsideOut(this, 10420 (Predicate<View>) t -> t.mNextClusterForwardId == id); 10421 } 10422 } 10423 return null; 10424 } 10425 10426 private View findViewInsideOutShouldExist(View root, int id) { 10427 if (mMatchIdPredicate == null) { 10428 mMatchIdPredicate = new MatchIdPredicate(); 10429 } 10430 mMatchIdPredicate.mId = id; 10431 View result = root.findViewByPredicateInsideOut(this, mMatchIdPredicate); 10432 if (result == null) { 10433 Log.w(VIEW_LOG_TAG, "couldn't find view with id " + id); 10434 } 10435 return result; 10436 } 10437 10438 /** 10439 * Find and return all focusable views that are descendants of this view, 10440 * possibly including this view if it is focusable itself. 10441 * 10442 * @param direction The direction of the focus 10443 * @return A list of focusable views 10444 */ 10445 public ArrayList<View> getFocusables(@FocusDirection int direction) { 10446 ArrayList<View> result = new ArrayList<View>(24); 10447 addFocusables(result, direction); 10448 return result; 10449 } 10450 10451 /** 10452 * Add any focusable views that are descendants of this view (possibly 10453 * including this view if it is focusable itself) to views. If we are in touch mode, 10454 * only add views that are also focusable in touch mode. 10455 * 10456 * @param views Focusable views found so far 10457 * @param direction The direction of the focus 10458 */ 10459 public void addFocusables(ArrayList<View> views, @FocusDirection int direction) { 10460 addFocusables(views, direction, isInTouchMode() ? FOCUSABLES_TOUCH_MODE : FOCUSABLES_ALL); 10461 } 10462 10463 /** 10464 * Adds any focusable views that are descendants of this view (possibly 10465 * including this view if it is focusable itself) to views. This method 10466 * adds all focusable views regardless if we are in touch mode or 10467 * only views focusable in touch mode if we are in touch mode or 10468 * only views that can take accessibility focus if accessibility is enabled 10469 * depending on the focusable mode parameter. 10470 * 10471 * @param views Focusable views found so far or null if all we are interested is 10472 * the number of focusables. 10473 * @param direction The direction of the focus. 10474 * @param focusableMode The type of focusables to be added. 10475 * 10476 * @see #FOCUSABLES_ALL 10477 * @see #FOCUSABLES_TOUCH_MODE 10478 */ 10479 public void addFocusables(ArrayList<View> views, @FocusDirection int direction, 10480 @FocusableMode int focusableMode) { 10481 if (views == null) { 10482 return; 10483 } 10484 if (!isFocusable()) { 10485 return; 10486 } 10487 if ((focusableMode & FOCUSABLES_TOUCH_MODE) == FOCUSABLES_TOUCH_MODE 10488 && !isFocusableInTouchMode()) { 10489 return; 10490 } 10491 views.add(this); 10492 } 10493 10494 /** 10495 * Adds any keyboard navigation cluster roots that are descendants of this view (possibly 10496 * including this view if it is a cluster root itself) to views. 10497 * 10498 * @param views Keyboard navigation cluster roots found so far 10499 * @param direction Direction to look 10500 */ 10501 public void addKeyboardNavigationClusters( 10502 @NonNull Collection<View> views, 10503 int direction) { 10504 if (!isKeyboardNavigationCluster()) { 10505 return; 10506 } 10507 if (!hasFocusable()) { 10508 return; 10509 } 10510 views.add(this); 10511 } 10512 10513 /** 10514 * Finds the Views that contain given text. The containment is case insensitive. 10515 * The search is performed by either the text that the View renders or the content 10516 * description that describes the view for accessibility purposes and the view does 10517 * not render or both. Clients can specify how the search is to be performed via 10518 * passing the {@link #FIND_VIEWS_WITH_TEXT} and 10519 * {@link #FIND_VIEWS_WITH_CONTENT_DESCRIPTION} flags. 10520 * 10521 * @param outViews The output list of matching Views. 10522 * @param searched The text to match against. 10523 * 10524 * @see #FIND_VIEWS_WITH_TEXT 10525 * @see #FIND_VIEWS_WITH_CONTENT_DESCRIPTION 10526 * @see #setContentDescription(CharSequence) 10527 */ 10528 public void findViewsWithText(ArrayList<View> outViews, CharSequence searched, 10529 @FindViewFlags int flags) { 10530 if (getAccessibilityNodeProvider() != null) { 10531 if ((flags & FIND_VIEWS_WITH_ACCESSIBILITY_NODE_PROVIDERS) != 0) { 10532 outViews.add(this); 10533 } 10534 } else if ((flags & FIND_VIEWS_WITH_CONTENT_DESCRIPTION) != 0 10535 && (searched != null && searched.length() > 0) 10536 && (mContentDescription != null && mContentDescription.length() > 0)) { 10537 String searchedLowerCase = searched.toString().toLowerCase(); 10538 String contentDescriptionLowerCase = mContentDescription.toString().toLowerCase(); 10539 if (contentDescriptionLowerCase.contains(searchedLowerCase)) { 10540 outViews.add(this); 10541 } 10542 } 10543 } 10544 10545 /** 10546 * Find and return all touchable views that are descendants of this view, 10547 * possibly including this view if it is touchable itself. 10548 * 10549 * @return A list of touchable views 10550 */ 10551 public ArrayList<View> getTouchables() { 10552 ArrayList<View> result = new ArrayList<View>(); 10553 addTouchables(result); 10554 return result; 10555 } 10556 10557 /** 10558 * Add any touchable views that are descendants of this view (possibly 10559 * including this view if it is touchable itself) to views. 10560 * 10561 * @param views Touchable views found so far 10562 */ 10563 public void addTouchables(ArrayList<View> views) { 10564 final int viewFlags = mViewFlags; 10565 10566 if (((viewFlags & CLICKABLE) == CLICKABLE || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE 10567 || (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE) 10568 && (viewFlags & ENABLED_MASK) == ENABLED) { 10569 views.add(this); 10570 } 10571 } 10572 10573 /** 10574 * Returns whether this View is accessibility focused. 10575 * 10576 * @return True if this View is accessibility focused. 10577 */ 10578 public boolean isAccessibilityFocused() { 10579 return (mPrivateFlags2 & PFLAG2_ACCESSIBILITY_FOCUSED) != 0; 10580 } 10581 10582 /** 10583 * Call this to try to give accessibility focus to this view. 10584 * 10585 * A view will not actually take focus if {@link AccessibilityManager#isEnabled()} 10586 * returns false or the view is no visible or the view already has accessibility 10587 * focus. 10588 * 10589 * See also {@link #focusSearch(int)}, which is what you call to say that you 10590 * have focus, and you want your parent to look for the next one. 10591 * 10592 * @return Whether this view actually took accessibility focus. 10593 * 10594 * @hide 10595 */ 10596 public boolean requestAccessibilityFocus() { 10597 AccessibilityManager manager = AccessibilityManager.getInstance(mContext); 10598 if (!manager.isEnabled() || !manager.isTouchExplorationEnabled()) { 10599 return false; 10600 } 10601 if ((mViewFlags & VISIBILITY_MASK) != VISIBLE) { 10602 return false; 10603 } 10604 if ((mPrivateFlags2 & PFLAG2_ACCESSIBILITY_FOCUSED) == 0) { 10605 mPrivateFlags2 |= PFLAG2_ACCESSIBILITY_FOCUSED; 10606 ViewRootImpl viewRootImpl = getViewRootImpl(); 10607 if (viewRootImpl != null) { 10608 viewRootImpl.setAccessibilityFocus(this, null); 10609 } 10610 invalidate(); 10611 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED); 10612 return true; 10613 } 10614 return false; 10615 } 10616 10617 /** 10618 * Call this to try to clear accessibility focus of this view. 10619 * 10620 * See also {@link #focusSearch(int)}, which is what you call to say that you 10621 * have focus, and you want your parent to look for the next one. 10622 * 10623 * @hide 10624 */ 10625 public void clearAccessibilityFocus() { 10626 clearAccessibilityFocusNoCallbacks(0); 10627 10628 // Clear the global reference of accessibility focus if this view or 10629 // any of its descendants had accessibility focus. This will NOT send 10630 // an event or update internal state if focus is cleared from a 10631 // descendant view, which may leave views in inconsistent states. 10632 final ViewRootImpl viewRootImpl = getViewRootImpl(); 10633 if (viewRootImpl != null) { 10634 final View focusHost = viewRootImpl.getAccessibilityFocusedHost(); 10635 if (focusHost != null && ViewRootImpl.isViewDescendantOf(focusHost, this)) { 10636 viewRootImpl.setAccessibilityFocus(null, null); 10637 } 10638 } 10639 } 10640 10641 private void sendAccessibilityHoverEvent(int eventType) { 10642 // Since we are not delivering to a client accessibility events from not 10643 // important views (unless the clinet request that) we need to fire the 10644 // event from the deepest view exposed to the client. As a consequence if 10645 // the user crosses a not exposed view the client will see enter and exit 10646 // of the exposed predecessor followed by and enter and exit of that same 10647 // predecessor when entering and exiting the not exposed descendant. This 10648 // is fine since the client has a clear idea which view is hovered at the 10649 // price of a couple more events being sent. This is a simple and 10650 // working solution. 10651 View source = this; 10652 while (true) { 10653 if (source.includeForAccessibility()) { 10654 source.sendAccessibilityEvent(eventType); 10655 return; 10656 } 10657 ViewParent parent = source.getParent(); 10658 if (parent instanceof View) { 10659 source = (View) parent; 10660 } else { 10661 return; 10662 } 10663 } 10664 } 10665 10666 /** 10667 * Clears accessibility focus without calling any callback methods 10668 * normally invoked in {@link #clearAccessibilityFocus()}. This method 10669 * is used separately from that one for clearing accessibility focus when 10670 * giving this focus to another view. 10671 * 10672 * @param action The action, if any, that led to focus being cleared. Set to 10673 * AccessibilityNodeInfo#ACTION_ACCESSIBILITY_FOCUS to specify that focus is moving within 10674 * the window. 10675 */ 10676 void clearAccessibilityFocusNoCallbacks(int action) { 10677 if ((mPrivateFlags2 & PFLAG2_ACCESSIBILITY_FOCUSED) != 0) { 10678 mPrivateFlags2 &= ~PFLAG2_ACCESSIBILITY_FOCUSED; 10679 invalidate(); 10680 if (AccessibilityManager.getInstance(mContext).isEnabled()) { 10681 AccessibilityEvent event = AccessibilityEvent.obtain( 10682 AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED); 10683 event.setAction(action); 10684 if (mAccessibilityDelegate != null) { 10685 mAccessibilityDelegate.sendAccessibilityEventUnchecked(this, event); 10686 } else { 10687 sendAccessibilityEventUnchecked(event); 10688 } 10689 } 10690 } 10691 } 10692 10693 /** 10694 * Call this to try to give focus to a specific view or to one of its 10695 * descendants. 10696 * 10697 * A view will not actually take focus if it is not focusable ({@link #isFocusable} returns 10698 * false), or if it is focusable and it is not focusable in touch mode 10699 * ({@link #isFocusableInTouchMode}) while the device is in touch mode. 10700 * 10701 * See also {@link #focusSearch(int)}, which is what you call to say that you 10702 * have focus, and you want your parent to look for the next one. 10703 * 10704 * This is equivalent to calling {@link #requestFocus(int, Rect)} with arguments 10705 * {@link #FOCUS_DOWN} and <code>null</code>. 10706 * 10707 * @return Whether this view or one of its descendants actually took focus. 10708 */ 10709 public final boolean requestFocus() { 10710 return requestFocus(View.FOCUS_DOWN); 10711 } 10712 10713 /** 10714 * This will request focus for whichever View was last focused within this 10715 * cluster before a focus-jump out of it. 10716 * 10717 * @hide 10718 */ 10719 @TestApi 10720 public boolean restoreFocusInCluster(@FocusRealDirection int direction) { 10721 // Prioritize focusableByDefault over algorithmic focus selection. 10722 if (restoreDefaultFocus()) { 10723 return true; 10724 } 10725 return requestFocus(direction); 10726 } 10727 10728 /** 10729 * This will request focus for whichever View not in a cluster was last focused before a 10730 * focus-jump to a cluster. If no non-cluster View has previously had focus, this will focus 10731 * the "first" focusable view it finds. 10732 * 10733 * @hide 10734 */ 10735 @TestApi 10736 public boolean restoreFocusNotInCluster() { 10737 return requestFocus(View.FOCUS_DOWN); 10738 } 10739 10740 /** 10741 * Gives focus to the default-focus view in the view hierarchy that has this view as a root. 10742 * If the default-focus view cannot be found, falls back to calling {@link #requestFocus(int)}. 10743 * 10744 * @return Whether this view or one of its descendants actually took focus 10745 */ 10746 public boolean restoreDefaultFocus() { 10747 return requestFocus(View.FOCUS_DOWN); 10748 } 10749 10750 /** 10751 * Call this to try to give focus to a specific view or to one of its 10752 * descendants and give it a hint about what direction focus is heading. 10753 * 10754 * A view will not actually take focus if it is not focusable ({@link #isFocusable} returns 10755 * false), or if it is focusable and it is not focusable in touch mode 10756 * ({@link #isFocusableInTouchMode}) while the device is in touch mode. 10757 * 10758 * See also {@link #focusSearch(int)}, which is what you call to say that you 10759 * have focus, and you want your parent to look for the next one. 10760 * 10761 * This is equivalent to calling {@link #requestFocus(int, Rect)} with 10762 * <code>null</code> set for the previously focused rectangle. 10763 * 10764 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT 10765 * @return Whether this view or one of its descendants actually took focus. 10766 */ 10767 public final boolean requestFocus(int direction) { 10768 return requestFocus(direction, null); 10769 } 10770 10771 /** 10772 * Call this to try to give focus to a specific view or to one of its descendants 10773 * and give it hints about the direction and a specific rectangle that the focus 10774 * is coming from. The rectangle can help give larger views a finer grained hint 10775 * about where focus is coming from, and therefore, where to show selection, or 10776 * forward focus change internally. 10777 * 10778 * A view will not actually take focus if it is not focusable ({@link #isFocusable} returns 10779 * false), or if it is focusable and it is not focusable in touch mode 10780 * ({@link #isFocusableInTouchMode}) while the device is in touch mode. 10781 * 10782 * A View will not take focus if it is not visible. 10783 * 10784 * A View will not take focus if one of its parents has 10785 * {@link android.view.ViewGroup#getDescendantFocusability()} equal to 10786 * {@link ViewGroup#FOCUS_BLOCK_DESCENDANTS}. 10787 * 10788 * See also {@link #focusSearch(int)}, which is what you call to say that you 10789 * have focus, and you want your parent to look for the next one. 10790 * 10791 * You may wish to override this method if your custom {@link View} has an internal 10792 * {@link View} that it wishes to forward the request to. 10793 * 10794 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT 10795 * @param previouslyFocusedRect The rectangle (in this View's coordinate system) 10796 * to give a finer grained hint about where focus is coming from. May be null 10797 * if there is no hint. 10798 * @return Whether this view or one of its descendants actually took focus. 10799 */ 10800 public boolean requestFocus(int direction, Rect previouslyFocusedRect) { 10801 return requestFocusNoSearch(direction, previouslyFocusedRect); 10802 } 10803 10804 private boolean requestFocusNoSearch(int direction, Rect previouslyFocusedRect) { 10805 // need to be focusable 10806 if ((mViewFlags & FOCUSABLE) != FOCUSABLE 10807 || (mViewFlags & VISIBILITY_MASK) != VISIBLE) { 10808 return false; 10809 } 10810 10811 // need to be focusable in touch mode if in touch mode 10812 if (isInTouchMode() && 10813 (FOCUSABLE_IN_TOUCH_MODE != (mViewFlags & FOCUSABLE_IN_TOUCH_MODE))) { 10814 return false; 10815 } 10816 10817 // need to not have any parents blocking us 10818 if (hasAncestorThatBlocksDescendantFocus()) { 10819 return false; 10820 } 10821 10822 handleFocusGainInternal(direction, previouslyFocusedRect); 10823 return true; 10824 } 10825 10826 /** 10827 * Call this to try to give focus to a specific view or to one of its descendants. This is a 10828 * special variant of {@link #requestFocus() } that will allow views that are not focusable in 10829 * touch mode to request focus when they are touched. 10830 * 10831 * @return Whether this view or one of its descendants actually took focus. 10832 * 10833 * @see #isInTouchMode() 10834 * 10835 */ 10836 public final boolean requestFocusFromTouch() { 10837 // Leave touch mode if we need to 10838 if (isInTouchMode()) { 10839 ViewRootImpl viewRoot = getViewRootImpl(); 10840 if (viewRoot != null) { 10841 viewRoot.ensureTouchMode(false); 10842 } 10843 } 10844 return requestFocus(View.FOCUS_DOWN); 10845 } 10846 10847 /** 10848 * @return Whether any ancestor of this view blocks descendant focus. 10849 */ 10850 private boolean hasAncestorThatBlocksDescendantFocus() { 10851 final boolean focusableInTouchMode = isFocusableInTouchMode(); 10852 ViewParent ancestor = mParent; 10853 while (ancestor instanceof ViewGroup) { 10854 final ViewGroup vgAncestor = (ViewGroup) ancestor; 10855 if (vgAncestor.getDescendantFocusability() == ViewGroup.FOCUS_BLOCK_DESCENDANTS 10856 || (!focusableInTouchMode && vgAncestor.shouldBlockFocusForTouchscreen())) { 10857 return true; 10858 } else { 10859 ancestor = vgAncestor.getParent(); 10860 } 10861 } 10862 return false; 10863 } 10864 10865 /** 10866 * Gets the mode for determining whether this View is important for accessibility. 10867 * A view is important for accessibility if it fires accessibility events and if it 10868 * is reported to accessibility services that query the screen. 10869 * 10870 * @return The mode for determining whether a view is important for accessibility, one 10871 * of {@link #IMPORTANT_FOR_ACCESSIBILITY_AUTO}, {@link #IMPORTANT_FOR_ACCESSIBILITY_YES}, 10872 * {@link #IMPORTANT_FOR_ACCESSIBILITY_NO}, or 10873 * {@link #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS}. 10874 * 10875 * @attr ref android.R.styleable#View_importantForAccessibility 10876 * 10877 * @see #IMPORTANT_FOR_ACCESSIBILITY_YES 10878 * @see #IMPORTANT_FOR_ACCESSIBILITY_NO 10879 * @see #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS 10880 * @see #IMPORTANT_FOR_ACCESSIBILITY_AUTO 10881 */ 10882 @ViewDebug.ExportedProperty(category = "accessibility", mapping = { 10883 @ViewDebug.IntToString(from = IMPORTANT_FOR_ACCESSIBILITY_AUTO, to = "auto"), 10884 @ViewDebug.IntToString(from = IMPORTANT_FOR_ACCESSIBILITY_YES, to = "yes"), 10885 @ViewDebug.IntToString(from = IMPORTANT_FOR_ACCESSIBILITY_NO, to = "no"), 10886 @ViewDebug.IntToString(from = IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS, 10887 to = "noHideDescendants") 10888 }) 10889 public int getImportantForAccessibility() { 10890 return (mPrivateFlags2 & PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK) 10891 >> PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT; 10892 } 10893 10894 /** 10895 * Sets the live region mode for this view. This indicates to accessibility 10896 * services whether they should automatically notify the user about changes 10897 * to the view's content description or text, or to the content descriptions 10898 * or text of the view's children (where applicable). 10899 * <p> 10900 * For example, in a login screen with a TextView that displays an "incorrect 10901 * password" notification, that view should be marked as a live region with 10902 * mode {@link #ACCESSIBILITY_LIVE_REGION_POLITE}. 10903 * <p> 10904 * To disable change notifications for this view, use 10905 * {@link #ACCESSIBILITY_LIVE_REGION_NONE}. This is the default live region 10906 * mode for most views. 10907 * <p> 10908 * To indicate that the user should be notified of changes, use 10909 * {@link #ACCESSIBILITY_LIVE_REGION_POLITE}. 10910 * <p> 10911 * If the view's changes should interrupt ongoing speech and notify the user 10912 * immediately, use {@link #ACCESSIBILITY_LIVE_REGION_ASSERTIVE}. 10913 * 10914 * @param mode The live region mode for this view, one of: 10915 * <ul> 10916 * <li>{@link #ACCESSIBILITY_LIVE_REGION_NONE} 10917 * <li>{@link #ACCESSIBILITY_LIVE_REGION_POLITE} 10918 * <li>{@link #ACCESSIBILITY_LIVE_REGION_ASSERTIVE} 10919 * </ul> 10920 * @attr ref android.R.styleable#View_accessibilityLiveRegion 10921 */ 10922 public void setAccessibilityLiveRegion(int mode) { 10923 if (mode != getAccessibilityLiveRegion()) { 10924 mPrivateFlags2 &= ~PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK; 10925 mPrivateFlags2 |= (mode << PFLAG2_ACCESSIBILITY_LIVE_REGION_SHIFT) 10926 & PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK; 10927 notifyViewAccessibilityStateChangedIfNeeded( 10928 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 10929 } 10930 } 10931 10932 /** 10933 * Gets the live region mode for this View. 10934 * 10935 * @return The live region mode for the view. 10936 * 10937 * @attr ref android.R.styleable#View_accessibilityLiveRegion 10938 * 10939 * @see #setAccessibilityLiveRegion(int) 10940 */ 10941 public int getAccessibilityLiveRegion() { 10942 return (mPrivateFlags2 & PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK) 10943 >> PFLAG2_ACCESSIBILITY_LIVE_REGION_SHIFT; 10944 } 10945 10946 /** 10947 * Sets how to determine whether this view is important for accessibility 10948 * which is if it fires accessibility events and if it is reported to 10949 * accessibility services that query the screen. 10950 * 10951 * @param mode How to determine whether this view is important for accessibility. 10952 * 10953 * @attr ref android.R.styleable#View_importantForAccessibility 10954 * 10955 * @see #IMPORTANT_FOR_ACCESSIBILITY_YES 10956 * @see #IMPORTANT_FOR_ACCESSIBILITY_NO 10957 * @see #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS 10958 * @see #IMPORTANT_FOR_ACCESSIBILITY_AUTO 10959 */ 10960 public void setImportantForAccessibility(int mode) { 10961 final int oldMode = getImportantForAccessibility(); 10962 if (mode != oldMode) { 10963 final boolean hideDescendants = 10964 mode == IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS; 10965 10966 // If this node or its descendants are no longer important, try to 10967 // clear accessibility focus. 10968 if (mode == IMPORTANT_FOR_ACCESSIBILITY_NO || hideDescendants) { 10969 final View focusHost = findAccessibilityFocusHost(hideDescendants); 10970 if (focusHost != null) { 10971 focusHost.clearAccessibilityFocus(); 10972 } 10973 } 10974 10975 // If we're moving between AUTO and another state, we might not need 10976 // to send a subtree changed notification. We'll store the computed 10977 // importance, since we'll need to check it later to make sure. 10978 final boolean maySkipNotify = oldMode == IMPORTANT_FOR_ACCESSIBILITY_AUTO 10979 || mode == IMPORTANT_FOR_ACCESSIBILITY_AUTO; 10980 final boolean oldIncludeForAccessibility = maySkipNotify && includeForAccessibility(); 10981 mPrivateFlags2 &= ~PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK; 10982 mPrivateFlags2 |= (mode << PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT) 10983 & PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK; 10984 if (!maySkipNotify || oldIncludeForAccessibility != includeForAccessibility()) { 10985 notifySubtreeAccessibilityStateChangedIfNeeded(); 10986 } else { 10987 notifyViewAccessibilityStateChangedIfNeeded( 10988 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 10989 } 10990 } 10991 } 10992 10993 /** 10994 * Returns the view within this view's hierarchy that is hosting 10995 * accessibility focus. 10996 * 10997 * @param searchDescendants whether to search for focus in descendant views 10998 * @return the view hosting accessibility focus, or {@code null} 10999 */ 11000 private View findAccessibilityFocusHost(boolean searchDescendants) { 11001 if (isAccessibilityFocusedViewOrHost()) { 11002 return this; 11003 } 11004 11005 if (searchDescendants) { 11006 final ViewRootImpl viewRoot = getViewRootImpl(); 11007 if (viewRoot != null) { 11008 final View focusHost = viewRoot.getAccessibilityFocusedHost(); 11009 if (focusHost != null && ViewRootImpl.isViewDescendantOf(focusHost, this)) { 11010 return focusHost; 11011 } 11012 } 11013 } 11014 11015 return null; 11016 } 11017 11018 /** 11019 * Computes whether this view should be exposed for accessibility. In 11020 * general, views that are interactive or provide information are exposed 11021 * while views that serve only as containers are hidden. 11022 * <p> 11023 * If an ancestor of this view has importance 11024 * {@link #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS}, this method 11025 * returns <code>false</code>. 11026 * <p> 11027 * Otherwise, the value is computed according to the view's 11028 * {@link #getImportantForAccessibility()} value: 11029 * <ol> 11030 * <li>{@link #IMPORTANT_FOR_ACCESSIBILITY_NO} or 11031 * {@link #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS}, return <code>false 11032 * </code> 11033 * <li>{@link #IMPORTANT_FOR_ACCESSIBILITY_YES}, return <code>true</code> 11034 * <li>{@link #IMPORTANT_FOR_ACCESSIBILITY_AUTO}, return <code>true</code> if 11035 * view satisfies any of the following: 11036 * <ul> 11037 * <li>Is actionable, e.g. {@link #isClickable()}, 11038 * {@link #isLongClickable()}, or {@link #isFocusable()} 11039 * <li>Has an {@link AccessibilityDelegate} 11040 * <li>Has an interaction listener, e.g. {@link OnTouchListener}, 11041 * {@link OnKeyListener}, etc. 11042 * <li>Is an accessibility live region, e.g. 11043 * {@link #getAccessibilityLiveRegion()} is not 11044 * {@link #ACCESSIBILITY_LIVE_REGION_NONE}. 11045 * </ul> 11046 * </ol> 11047 * 11048 * @return Whether the view is exposed for accessibility. 11049 * @see #setImportantForAccessibility(int) 11050 * @see #getImportantForAccessibility() 11051 */ 11052 public boolean isImportantForAccessibility() { 11053 final int mode = (mPrivateFlags2 & PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK) 11054 >> PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT; 11055 if (mode == IMPORTANT_FOR_ACCESSIBILITY_NO 11056 || mode == IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS) { 11057 return false; 11058 } 11059 11060 // Check parent mode to ensure we're not hidden. 11061 ViewParent parent = mParent; 11062 while (parent instanceof View) { 11063 if (((View) parent).getImportantForAccessibility() 11064 == IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS) { 11065 return false; 11066 } 11067 parent = parent.getParent(); 11068 } 11069 11070 return mode == IMPORTANT_FOR_ACCESSIBILITY_YES || isActionableForAccessibility() 11071 || hasListenersForAccessibility() || getAccessibilityNodeProvider() != null 11072 || getAccessibilityLiveRegion() != ACCESSIBILITY_LIVE_REGION_NONE; 11073 } 11074 11075 /** 11076 * Gets the parent for accessibility purposes. Note that the parent for 11077 * accessibility is not necessary the immediate parent. It is the first 11078 * predecessor that is important for accessibility. 11079 * 11080 * @return The parent for accessibility purposes. 11081 */ 11082 public ViewParent getParentForAccessibility() { 11083 if (mParent instanceof View) { 11084 View parentView = (View) mParent; 11085 if (parentView.includeForAccessibility()) { 11086 return mParent; 11087 } else { 11088 return mParent.getParentForAccessibility(); 11089 } 11090 } 11091 return null; 11092 } 11093 11094 /** 11095 * Adds the children of this View relevant for accessibility to the given list 11096 * as output. Since some Views are not important for accessibility the added 11097 * child views are not necessarily direct children of this view, rather they are 11098 * the first level of descendants important for accessibility. 11099 * 11100 * @param outChildren The output list that will receive children for accessibility. 11101 */ 11102 public void addChildrenForAccessibility(ArrayList<View> outChildren) { 11103 11104 } 11105 11106 /** 11107 * Whether to regard this view for accessibility. A view is regarded for 11108 * accessibility if it is important for accessibility or the querying 11109 * accessibility service has explicitly requested that view not 11110 * important for accessibility are regarded. 11111 * 11112 * @return Whether to regard the view for accessibility. 11113 * 11114 * @hide 11115 */ 11116 public boolean includeForAccessibility() { 11117 if (mAttachInfo != null) { 11118 return (mAttachInfo.mAccessibilityFetchFlags 11119 & AccessibilityNodeInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS) != 0 11120 || isImportantForAccessibility(); 11121 } 11122 return false; 11123 } 11124 11125 /** 11126 * Returns whether the View is considered actionable from 11127 * accessibility perspective. Such view are important for 11128 * accessibility. 11129 * 11130 * @return True if the view is actionable for accessibility. 11131 * 11132 * @hide 11133 */ 11134 public boolean isActionableForAccessibility() { 11135 return (isClickable() || isLongClickable() || isFocusable()); 11136 } 11137 11138 /** 11139 * Returns whether the View has registered callbacks which makes it 11140 * important for accessibility. 11141 * 11142 * @return True if the view is actionable for accessibility. 11143 */ 11144 private boolean hasListenersForAccessibility() { 11145 ListenerInfo info = getListenerInfo(); 11146 return mTouchDelegate != null || info.mOnKeyListener != null 11147 || info.mOnTouchListener != null || info.mOnGenericMotionListener != null 11148 || info.mOnHoverListener != null || info.mOnDragListener != null; 11149 } 11150 11151 /** 11152 * Notifies that the accessibility state of this view changed. The change 11153 * is local to this view and does not represent structural changes such 11154 * as children and parent. For example, the view became focusable. The 11155 * notification is at at most once every 11156 * {@link ViewConfiguration#getSendRecurringAccessibilityEventsInterval()} 11157 * to avoid unnecessary load to the system. Also once a view has a pending 11158 * notification this method is a NOP until the notification has been sent. 11159 * 11160 * @hide 11161 */ 11162 public void notifyViewAccessibilityStateChangedIfNeeded(int changeType) { 11163 if (!AccessibilityManager.getInstance(mContext).isEnabled() || mAttachInfo == null) { 11164 return; 11165 } 11166 // If this is a live region, we should send a subtree change event 11167 // from this view immediately. Otherwise, we can let it propagate up. 11168 if (getAccessibilityLiveRegion() != ACCESSIBILITY_LIVE_REGION_NONE) { 11169 final AccessibilityEvent event = AccessibilityEvent.obtain(); 11170 event.setEventType(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED); 11171 event.setContentChangeTypes(changeType); 11172 sendAccessibilityEventUnchecked(event); 11173 } else if (mParent != null) { 11174 try { 11175 mParent.notifySubtreeAccessibilityStateChanged(this, this, changeType); 11176 } catch (AbstractMethodError e) { 11177 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 11178 " does not fully implement ViewParent", e); 11179 } 11180 } 11181 } 11182 11183 /** 11184 * Notifies that the accessibility state of this view changed. The change 11185 * is *not* local to this view and does represent structural changes such 11186 * as children and parent. For example, the view size changed. The 11187 * notification is at at most once every 11188 * {@link ViewConfiguration#getSendRecurringAccessibilityEventsInterval()} 11189 * to avoid unnecessary load to the system. Also once a view has a pending 11190 * notification this method is a NOP until the notification has been sent. 11191 * 11192 * @hide 11193 */ 11194 public void notifySubtreeAccessibilityStateChangedIfNeeded() { 11195 if (!AccessibilityManager.getInstance(mContext).isEnabled() || mAttachInfo == null) { 11196 return; 11197 } 11198 if ((mPrivateFlags2 & PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED) == 0) { 11199 mPrivateFlags2 |= PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED; 11200 if (mParent != null) { 11201 try { 11202 mParent.notifySubtreeAccessibilityStateChanged( 11203 this, this, AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE); 11204 } catch (AbstractMethodError e) { 11205 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 11206 " does not fully implement ViewParent", e); 11207 } 11208 } 11209 } 11210 } 11211 11212 /** 11213 * Change the visibility of the View without triggering any other changes. This is 11214 * important for transitions, where visibility changes should not adjust focus or 11215 * trigger a new layout. This is only used when the visibility has already been changed 11216 * and we need a transient value during an animation. When the animation completes, 11217 * the original visibility value is always restored. 11218 * 11219 * @param visibility One of {@link #VISIBLE}, {@link #INVISIBLE}, or {@link #GONE}. 11220 * @hide 11221 */ 11222 public void setTransitionVisibility(@Visibility int visibility) { 11223 mViewFlags = (mViewFlags & ~View.VISIBILITY_MASK) | visibility; 11224 } 11225 11226 /** 11227 * Reset the flag indicating the accessibility state of the subtree rooted 11228 * at this view changed. 11229 */ 11230 void resetSubtreeAccessibilityStateChanged() { 11231 mPrivateFlags2 &= ~PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED; 11232 } 11233 11234 /** 11235 * Report an accessibility action to this view's parents for delegated processing. 11236 * 11237 * <p>Implementations of {@link #performAccessibilityAction(int, Bundle)} may internally 11238 * call this method to delegate an accessibility action to a supporting parent. If the parent 11239 * returns true from its 11240 * {@link ViewParent#onNestedPrePerformAccessibilityAction(View, int, android.os.Bundle)} 11241 * method this method will return true to signify that the action was consumed.</p> 11242 * 11243 * <p>This method is useful for implementing nested scrolling child views. If 11244 * {@link #isNestedScrollingEnabled()} returns true and the action is a scrolling action 11245 * a custom view implementation may invoke this method to allow a parent to consume the 11246 * scroll first. If this method returns true the custom view should skip its own scrolling 11247 * behavior.</p> 11248 * 11249 * @param action Accessibility action to delegate 11250 * @param arguments Optional action arguments 11251 * @return true if the action was consumed by a parent 11252 */ 11253 public boolean dispatchNestedPrePerformAccessibilityAction(int action, Bundle arguments) { 11254 for (ViewParent p = getParent(); p != null; p = p.getParent()) { 11255 if (p.onNestedPrePerformAccessibilityAction(this, action, arguments)) { 11256 return true; 11257 } 11258 } 11259 return false; 11260 } 11261 11262 /** 11263 * Performs the specified accessibility action on the view. For 11264 * possible accessibility actions look at {@link AccessibilityNodeInfo}. 11265 * <p> 11266 * If an {@link AccessibilityDelegate} has been specified via calling 11267 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 11268 * {@link AccessibilityDelegate#performAccessibilityAction(View, int, Bundle)} 11269 * is responsible for handling this call. 11270 * </p> 11271 * 11272 * <p>The default implementation will delegate 11273 * {@link AccessibilityNodeInfo#ACTION_SCROLL_BACKWARD} and 11274 * {@link AccessibilityNodeInfo#ACTION_SCROLL_FORWARD} to nested scrolling parents if 11275 * {@link #isNestedScrollingEnabled() nested scrolling is enabled} on this view.</p> 11276 * 11277 * @param action The action to perform. 11278 * @param arguments Optional action arguments. 11279 * @return Whether the action was performed. 11280 */ 11281 public boolean performAccessibilityAction(int action, Bundle arguments) { 11282 if (mAccessibilityDelegate != null) { 11283 return mAccessibilityDelegate.performAccessibilityAction(this, action, arguments); 11284 } else { 11285 return performAccessibilityActionInternal(action, arguments); 11286 } 11287 } 11288 11289 /** 11290 * @see #performAccessibilityAction(int, Bundle) 11291 * 11292 * Note: Called from the default {@link AccessibilityDelegate}. 11293 * 11294 * @hide 11295 */ 11296 public boolean performAccessibilityActionInternal(int action, Bundle arguments) { 11297 if (isNestedScrollingEnabled() 11298 && (action == AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD 11299 || action == AccessibilityNodeInfo.ACTION_SCROLL_FORWARD 11300 || action == R.id.accessibilityActionScrollUp 11301 || action == R.id.accessibilityActionScrollLeft 11302 || action == R.id.accessibilityActionScrollDown 11303 || action == R.id.accessibilityActionScrollRight)) { 11304 if (dispatchNestedPrePerformAccessibilityAction(action, arguments)) { 11305 return true; 11306 } 11307 } 11308 11309 switch (action) { 11310 case AccessibilityNodeInfo.ACTION_CLICK: { 11311 if (isClickable()) { 11312 performClick(); 11313 return true; 11314 } 11315 } break; 11316 case AccessibilityNodeInfo.ACTION_LONG_CLICK: { 11317 if (isLongClickable()) { 11318 performLongClick(); 11319 return true; 11320 } 11321 } break; 11322 case AccessibilityNodeInfo.ACTION_FOCUS: { 11323 if (!hasFocus()) { 11324 // Get out of touch mode since accessibility 11325 // wants to move focus around. 11326 getViewRootImpl().ensureTouchMode(false); 11327 return requestFocus(); 11328 } 11329 } break; 11330 case AccessibilityNodeInfo.ACTION_CLEAR_FOCUS: { 11331 if (hasFocus()) { 11332 clearFocus(); 11333 return !isFocused(); 11334 } 11335 } break; 11336 case AccessibilityNodeInfo.ACTION_SELECT: { 11337 if (!isSelected()) { 11338 setSelected(true); 11339 return isSelected(); 11340 } 11341 } break; 11342 case AccessibilityNodeInfo.ACTION_CLEAR_SELECTION: { 11343 if (isSelected()) { 11344 setSelected(false); 11345 return !isSelected(); 11346 } 11347 } break; 11348 case AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS: { 11349 if (!isAccessibilityFocused()) { 11350 return requestAccessibilityFocus(); 11351 } 11352 } break; 11353 case AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS: { 11354 if (isAccessibilityFocused()) { 11355 clearAccessibilityFocus(); 11356 return true; 11357 } 11358 } break; 11359 case AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY: { 11360 if (arguments != null) { 11361 final int granularity = arguments.getInt( 11362 AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT); 11363 final boolean extendSelection = arguments.getBoolean( 11364 AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN); 11365 return traverseAtGranularity(granularity, true, extendSelection); 11366 } 11367 } break; 11368 case AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY: { 11369 if (arguments != null) { 11370 final int granularity = arguments.getInt( 11371 AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT); 11372 final boolean extendSelection = arguments.getBoolean( 11373 AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN); 11374 return traverseAtGranularity(granularity, false, extendSelection); 11375 } 11376 } break; 11377 case AccessibilityNodeInfo.ACTION_SET_SELECTION: { 11378 CharSequence text = getIterableTextForAccessibility(); 11379 if (text == null) { 11380 return false; 11381 } 11382 final int start = (arguments != null) ? arguments.getInt( 11383 AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT, -1) : -1; 11384 final int end = (arguments != null) ? arguments.getInt( 11385 AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT, -1) : -1; 11386 // Only cursor position can be specified (selection length == 0) 11387 if ((getAccessibilitySelectionStart() != start 11388 || getAccessibilitySelectionEnd() != end) 11389 && (start == end)) { 11390 setAccessibilitySelection(start, end); 11391 notifyViewAccessibilityStateChangedIfNeeded( 11392 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 11393 return true; 11394 } 11395 } break; 11396 case R.id.accessibilityActionShowOnScreen: { 11397 if (mAttachInfo != null) { 11398 final Rect r = mAttachInfo.mTmpInvalRect; 11399 getDrawingRect(r); 11400 return requestRectangleOnScreen(r, true); 11401 } 11402 } break; 11403 case R.id.accessibilityActionContextClick: { 11404 if (isContextClickable()) { 11405 performContextClick(); 11406 return true; 11407 } 11408 } break; 11409 } 11410 return false; 11411 } 11412 11413 private boolean traverseAtGranularity(int granularity, boolean forward, 11414 boolean extendSelection) { 11415 CharSequence text = getIterableTextForAccessibility(); 11416 if (text == null || text.length() == 0) { 11417 return false; 11418 } 11419 TextSegmentIterator iterator = getIteratorForGranularity(granularity); 11420 if (iterator == null) { 11421 return false; 11422 } 11423 int current = getAccessibilitySelectionEnd(); 11424 if (current == ACCESSIBILITY_CURSOR_POSITION_UNDEFINED) { 11425 current = forward ? 0 : text.length(); 11426 } 11427 final int[] range = forward ? iterator.following(current) : iterator.preceding(current); 11428 if (range == null) { 11429 return false; 11430 } 11431 final int segmentStart = range[0]; 11432 final int segmentEnd = range[1]; 11433 int selectionStart; 11434 int selectionEnd; 11435 if (extendSelection && isAccessibilitySelectionExtendable()) { 11436 selectionStart = getAccessibilitySelectionStart(); 11437 if (selectionStart == ACCESSIBILITY_CURSOR_POSITION_UNDEFINED) { 11438 selectionStart = forward ? segmentStart : segmentEnd; 11439 } 11440 selectionEnd = forward ? segmentEnd : segmentStart; 11441 } else { 11442 selectionStart = selectionEnd= forward ? segmentEnd : segmentStart; 11443 } 11444 setAccessibilitySelection(selectionStart, selectionEnd); 11445 final int action = forward ? AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY 11446 : AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY; 11447 sendViewTextTraversedAtGranularityEvent(action, granularity, segmentStart, segmentEnd); 11448 return true; 11449 } 11450 11451 /** 11452 * Gets the text reported for accessibility purposes. 11453 * 11454 * @return The accessibility text. 11455 * 11456 * @hide 11457 */ 11458 public CharSequence getIterableTextForAccessibility() { 11459 return getContentDescription(); 11460 } 11461 11462 /** 11463 * Gets whether accessibility selection can be extended. 11464 * 11465 * @return If selection is extensible. 11466 * 11467 * @hide 11468 */ 11469 public boolean isAccessibilitySelectionExtendable() { 11470 return false; 11471 } 11472 11473 /** 11474 * @hide 11475 */ 11476 public int getAccessibilitySelectionStart() { 11477 return mAccessibilityCursorPosition; 11478 } 11479 11480 /** 11481 * @hide 11482 */ 11483 public int getAccessibilitySelectionEnd() { 11484 return getAccessibilitySelectionStart(); 11485 } 11486 11487 /** 11488 * @hide 11489 */ 11490 public void setAccessibilitySelection(int start, int end) { 11491 if (start == end && end == mAccessibilityCursorPosition) { 11492 return; 11493 } 11494 if (start >= 0 && start == end && end <= getIterableTextForAccessibility().length()) { 11495 mAccessibilityCursorPosition = start; 11496 } else { 11497 mAccessibilityCursorPosition = ACCESSIBILITY_CURSOR_POSITION_UNDEFINED; 11498 } 11499 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED); 11500 } 11501 11502 private void sendViewTextTraversedAtGranularityEvent(int action, int granularity, 11503 int fromIndex, int toIndex) { 11504 if (mParent == null) { 11505 return; 11506 } 11507 AccessibilityEvent event = AccessibilityEvent.obtain( 11508 AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY); 11509 onInitializeAccessibilityEvent(event); 11510 onPopulateAccessibilityEvent(event); 11511 event.setFromIndex(fromIndex); 11512 event.setToIndex(toIndex); 11513 event.setAction(action); 11514 event.setMovementGranularity(granularity); 11515 mParent.requestSendAccessibilityEvent(this, event); 11516 } 11517 11518 /** 11519 * @hide 11520 */ 11521 public TextSegmentIterator getIteratorForGranularity(int granularity) { 11522 switch (granularity) { 11523 case AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER: { 11524 CharSequence text = getIterableTextForAccessibility(); 11525 if (text != null && text.length() > 0) { 11526 CharacterTextSegmentIterator iterator = 11527 CharacterTextSegmentIterator.getInstance( 11528 mContext.getResources().getConfiguration().locale); 11529 iterator.initialize(text.toString()); 11530 return iterator; 11531 } 11532 } break; 11533 case AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD: { 11534 CharSequence text = getIterableTextForAccessibility(); 11535 if (text != null && text.length() > 0) { 11536 WordTextSegmentIterator iterator = 11537 WordTextSegmentIterator.getInstance( 11538 mContext.getResources().getConfiguration().locale); 11539 iterator.initialize(text.toString()); 11540 return iterator; 11541 } 11542 } break; 11543 case AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH: { 11544 CharSequence text = getIterableTextForAccessibility(); 11545 if (text != null && text.length() > 0) { 11546 ParagraphTextSegmentIterator iterator = 11547 ParagraphTextSegmentIterator.getInstance(); 11548 iterator.initialize(text.toString()); 11549 return iterator; 11550 } 11551 } break; 11552 } 11553 return null; 11554 } 11555 11556 /** 11557 * Tells whether the {@link View} is in the state between {@link #onStartTemporaryDetach()} 11558 * and {@link #onFinishTemporaryDetach()}. 11559 * 11560 * <p>This method always returns {@code true} when called directly or indirectly from 11561 * {@link #onStartTemporaryDetach()}. The return value when called directly or indirectly from 11562 * {@link #onFinishTemporaryDetach()}, however, depends on the OS version. 11563 * <ul> 11564 * <li>{@code true} on {@link android.os.Build.VERSION_CODES#N API 24}</li> 11565 * <li>{@code false} on {@link android.os.Build.VERSION_CODES#N_MR1 API 25}} and later</li> 11566 * </ul> 11567 * </p> 11568 * 11569 * @return {@code true} when the View is in the state between {@link #onStartTemporaryDetach()} 11570 * and {@link #onFinishTemporaryDetach()}. 11571 */ 11572 public final boolean isTemporarilyDetached() { 11573 return (mPrivateFlags3 & PFLAG3_TEMPORARY_DETACH) != 0; 11574 } 11575 11576 /** 11577 * Dispatch {@link #onStartTemporaryDetach()} to this View and its direct children if this is 11578 * a container View. 11579 */ 11580 @CallSuper 11581 public void dispatchStartTemporaryDetach() { 11582 mPrivateFlags3 |= PFLAG3_TEMPORARY_DETACH; 11583 notifyEnterOrExitForAutoFillIfNeeded(false); 11584 onStartTemporaryDetach(); 11585 } 11586 11587 /** 11588 * This is called when a container is going to temporarily detach a child, with 11589 * {@link ViewGroup#detachViewFromParent(View) ViewGroup.detachViewFromParent}. 11590 * It will either be followed by {@link #onFinishTemporaryDetach()} or 11591 * {@link #onDetachedFromWindow()} when the container is done. 11592 */ 11593 public void onStartTemporaryDetach() { 11594 removeUnsetPressCallback(); 11595 mPrivateFlags |= PFLAG_CANCEL_NEXT_UP_EVENT; 11596 } 11597 11598 /** 11599 * Dispatch {@link #onFinishTemporaryDetach()} to this View and its direct children if this is 11600 * a container View. 11601 */ 11602 @CallSuper 11603 public void dispatchFinishTemporaryDetach() { 11604 mPrivateFlags3 &= ~PFLAG3_TEMPORARY_DETACH; 11605 onFinishTemporaryDetach(); 11606 if (hasWindowFocus() && hasFocus()) { 11607 InputMethodManager.getInstance().focusIn(this); 11608 } 11609 notifyEnterOrExitForAutoFillIfNeeded(true); 11610 } 11611 11612 /** 11613 * Called after {@link #onStartTemporaryDetach} when the container is done 11614 * changing the view. 11615 */ 11616 public void onFinishTemporaryDetach() { 11617 } 11618 11619 /** 11620 * Return the global {@link KeyEvent.DispatcherState KeyEvent.DispatcherState} 11621 * for this view's window. Returns null if the view is not currently attached 11622 * to the window. Normally you will not need to use this directly, but 11623 * just use the standard high-level event callbacks like 11624 * {@link #onKeyDown(int, KeyEvent)}. 11625 */ 11626 public KeyEvent.DispatcherState getKeyDispatcherState() { 11627 return mAttachInfo != null ? mAttachInfo.mKeyDispatchState : null; 11628 } 11629 11630 /** 11631 * Dispatch a key event before it is processed by any input method 11632 * associated with the view hierarchy. This can be used to intercept 11633 * key events in special situations before the IME consumes them; a 11634 * typical example would be handling the BACK key to update the application's 11635 * UI instead of allowing the IME to see it and close itself. 11636 * 11637 * @param event The key event to be dispatched. 11638 * @return True if the event was handled, false otherwise. 11639 */ 11640 public boolean dispatchKeyEventPreIme(KeyEvent event) { 11641 return onKeyPreIme(event.getKeyCode(), event); 11642 } 11643 11644 /** 11645 * Dispatch a key event to the next view on the focus path. This path runs 11646 * from the top of the view tree down to the currently focused view. If this 11647 * view has focus, it will dispatch to itself. Otherwise it will dispatch 11648 * the next node down the focus path. This method also fires any key 11649 * listeners. 11650 * 11651 * @param event The key event to be dispatched. 11652 * @return True if the event was handled, false otherwise. 11653 */ 11654 public boolean dispatchKeyEvent(KeyEvent event) { 11655 if (mInputEventConsistencyVerifier != null) { 11656 mInputEventConsistencyVerifier.onKeyEvent(event, 0); 11657 } 11658 11659 // Give any attached key listener a first crack at the event. 11660 //noinspection SimplifiableIfStatement 11661 ListenerInfo li = mListenerInfo; 11662 if (li != null && li.mOnKeyListener != null && (mViewFlags & ENABLED_MASK) == ENABLED 11663 && li.mOnKeyListener.onKey(this, event.getKeyCode(), event)) { 11664 return true; 11665 } 11666 11667 if (event.dispatch(this, mAttachInfo != null 11668 ? mAttachInfo.mKeyDispatchState : null, this)) { 11669 return true; 11670 } 11671 11672 if (mInputEventConsistencyVerifier != null) { 11673 mInputEventConsistencyVerifier.onUnhandledEvent(event, 0); 11674 } 11675 return false; 11676 } 11677 11678 /** 11679 * Dispatches a key shortcut event. 11680 * 11681 * @param event The key event to be dispatched. 11682 * @return True if the event was handled by the view, false otherwise. 11683 */ 11684 public boolean dispatchKeyShortcutEvent(KeyEvent event) { 11685 return onKeyShortcut(event.getKeyCode(), event); 11686 } 11687 11688 /** 11689 * Pass the touch screen motion event down to the target view, or this 11690 * view if it is the target. 11691 * 11692 * @param event The motion event to be dispatched. 11693 * @return True if the event was handled by the view, false otherwise. 11694 */ 11695 public boolean dispatchTouchEvent(MotionEvent event) { 11696 // If the event should be handled by accessibility focus first. 11697 if (event.isTargetAccessibilityFocus()) { 11698 // We don't have focus or no virtual descendant has it, do not handle the event. 11699 if (!isAccessibilityFocusedViewOrHost()) { 11700 return false; 11701 } 11702 // We have focus and got the event, then use normal event dispatch. 11703 event.setTargetAccessibilityFocus(false); 11704 } 11705 11706 boolean result = false; 11707 11708 if (mInputEventConsistencyVerifier != null) { 11709 mInputEventConsistencyVerifier.onTouchEvent(event, 0); 11710 } 11711 11712 final int actionMasked = event.getActionMasked(); 11713 if (actionMasked == MotionEvent.ACTION_DOWN) { 11714 // Defensive cleanup for new gesture 11715 stopNestedScroll(); 11716 } 11717 11718 if (onFilterTouchEventForSecurity(event)) { 11719 if ((mViewFlags & ENABLED_MASK) == ENABLED && handleScrollBarDragging(event)) { 11720 result = true; 11721 } 11722 //noinspection SimplifiableIfStatement 11723 ListenerInfo li = mListenerInfo; 11724 if (li != null && li.mOnTouchListener != null 11725 && (mViewFlags & ENABLED_MASK) == ENABLED 11726 && li.mOnTouchListener.onTouch(this, event)) { 11727 result = true; 11728 } 11729 11730 if (!result && onTouchEvent(event)) { 11731 result = true; 11732 } 11733 } 11734 11735 if (!result && mInputEventConsistencyVerifier != null) { 11736 mInputEventConsistencyVerifier.onUnhandledEvent(event, 0); 11737 } 11738 11739 // Clean up after nested scrolls if this is the end of a gesture; 11740 // also cancel it if we tried an ACTION_DOWN but we didn't want the rest 11741 // of the gesture. 11742 if (actionMasked == MotionEvent.ACTION_UP || 11743 actionMasked == MotionEvent.ACTION_CANCEL || 11744 (actionMasked == MotionEvent.ACTION_DOWN && !result)) { 11745 stopNestedScroll(); 11746 } 11747 11748 return result; 11749 } 11750 11751 boolean isAccessibilityFocusedViewOrHost() { 11752 return isAccessibilityFocused() || (getViewRootImpl() != null && getViewRootImpl() 11753 .getAccessibilityFocusedHost() == this); 11754 } 11755 11756 /** 11757 * Filter the touch event to apply security policies. 11758 * 11759 * @param event The motion event to be filtered. 11760 * @return True if the event should be dispatched, false if the event should be dropped. 11761 * 11762 * @see #getFilterTouchesWhenObscured 11763 */ 11764 public boolean onFilterTouchEventForSecurity(MotionEvent event) { 11765 //noinspection RedundantIfStatement 11766 if ((mViewFlags & FILTER_TOUCHES_WHEN_OBSCURED) != 0 11767 && (event.getFlags() & MotionEvent.FLAG_WINDOW_IS_OBSCURED) != 0) { 11768 // Window is obscured, drop this touch. 11769 return false; 11770 } 11771 return true; 11772 } 11773 11774 /** 11775 * Pass a trackball motion event down to the focused view. 11776 * 11777 * @param event The motion event to be dispatched. 11778 * @return True if the event was handled by the view, false otherwise. 11779 */ 11780 public boolean dispatchTrackballEvent(MotionEvent event) { 11781 if (mInputEventConsistencyVerifier != null) { 11782 mInputEventConsistencyVerifier.onTrackballEvent(event, 0); 11783 } 11784 11785 return onTrackballEvent(event); 11786 } 11787 11788 /** 11789 * Pass a captured pointer event down to the focused view. 11790 * 11791 * @param event The motion event to be dispatched. 11792 * @return True if the event was handled by the view, false otherwise. 11793 */ 11794 public boolean dispatchCapturedPointerEvent(MotionEvent event) { 11795 if (!hasPointerCapture()) { 11796 return false; 11797 } 11798 //noinspection SimplifiableIfStatement 11799 ListenerInfo li = mListenerInfo; 11800 if (li != null && li.mOnCapturedPointerListener != null 11801 && li.mOnCapturedPointerListener.onCapturedPointer(this, event)) { 11802 return true; 11803 } 11804 return onCapturedPointerEvent(event); 11805 } 11806 11807 /** 11808 * Dispatch a generic motion event. 11809 * <p> 11810 * Generic motion events with source class {@link InputDevice#SOURCE_CLASS_POINTER} 11811 * are delivered to the view under the pointer. All other generic motion events are 11812 * delivered to the focused view. Hover events are handled specially and are delivered 11813 * to {@link #onHoverEvent(MotionEvent)}. 11814 * </p> 11815 * 11816 * @param event The motion event to be dispatched. 11817 * @return True if the event was handled by the view, false otherwise. 11818 */ 11819 public boolean dispatchGenericMotionEvent(MotionEvent event) { 11820 if (mInputEventConsistencyVerifier != null) { 11821 mInputEventConsistencyVerifier.onGenericMotionEvent(event, 0); 11822 } 11823 11824 final int source = event.getSource(); 11825 if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) { 11826 final int action = event.getAction(); 11827 if (action == MotionEvent.ACTION_HOVER_ENTER 11828 || action == MotionEvent.ACTION_HOVER_MOVE 11829 || action == MotionEvent.ACTION_HOVER_EXIT) { 11830 if (dispatchHoverEvent(event)) { 11831 return true; 11832 } 11833 } else if (dispatchGenericPointerEvent(event)) { 11834 return true; 11835 } 11836 } else if (dispatchGenericFocusedEvent(event)) { 11837 return true; 11838 } 11839 11840 if (dispatchGenericMotionEventInternal(event)) { 11841 return true; 11842 } 11843 11844 if (mInputEventConsistencyVerifier != null) { 11845 mInputEventConsistencyVerifier.onUnhandledEvent(event, 0); 11846 } 11847 return false; 11848 } 11849 11850 private boolean dispatchGenericMotionEventInternal(MotionEvent event) { 11851 //noinspection SimplifiableIfStatement 11852 ListenerInfo li = mListenerInfo; 11853 if (li != null && li.mOnGenericMotionListener != null 11854 && (mViewFlags & ENABLED_MASK) == ENABLED 11855 && li.mOnGenericMotionListener.onGenericMotion(this, event)) { 11856 return true; 11857 } 11858 11859 if (onGenericMotionEvent(event)) { 11860 return true; 11861 } 11862 11863 final int actionButton = event.getActionButton(); 11864 switch (event.getActionMasked()) { 11865 case MotionEvent.ACTION_BUTTON_PRESS: 11866 if (isContextClickable() && !mInContextButtonPress && !mHasPerformedLongPress 11867 && (actionButton == MotionEvent.BUTTON_STYLUS_PRIMARY 11868 || actionButton == MotionEvent.BUTTON_SECONDARY)) { 11869 if (performContextClick(event.getX(), event.getY())) { 11870 mInContextButtonPress = true; 11871 setPressed(true, event.getX(), event.getY()); 11872 removeTapCallback(); 11873 removeLongPressCallback(); 11874 return true; 11875 } 11876 } 11877 break; 11878 11879 case MotionEvent.ACTION_BUTTON_RELEASE: 11880 if (mInContextButtonPress && (actionButton == MotionEvent.BUTTON_STYLUS_PRIMARY 11881 || actionButton == MotionEvent.BUTTON_SECONDARY)) { 11882 mInContextButtonPress = false; 11883 mIgnoreNextUpEvent = true; 11884 } 11885 break; 11886 } 11887 11888 if (mInputEventConsistencyVerifier != null) { 11889 mInputEventConsistencyVerifier.onUnhandledEvent(event, 0); 11890 } 11891 return false; 11892 } 11893 11894 /** 11895 * Dispatch a hover event. 11896 * <p> 11897 * Do not call this method directly. 11898 * Call {@link #dispatchGenericMotionEvent(MotionEvent)} instead. 11899 * </p> 11900 * 11901 * @param event The motion event to be dispatched. 11902 * @return True if the event was handled by the view, false otherwise. 11903 */ 11904 protected boolean dispatchHoverEvent(MotionEvent event) { 11905 ListenerInfo li = mListenerInfo; 11906 //noinspection SimplifiableIfStatement 11907 if (li != null && li.mOnHoverListener != null 11908 && (mViewFlags & ENABLED_MASK) == ENABLED 11909 && li.mOnHoverListener.onHover(this, event)) { 11910 return true; 11911 } 11912 11913 return onHoverEvent(event); 11914 } 11915 11916 /** 11917 * Returns true if the view has a child to which it has recently sent 11918 * {@link MotionEvent#ACTION_HOVER_ENTER}. If this view is hovered and 11919 * it does not have a hovered child, then it must be the innermost hovered view. 11920 * @hide 11921 */ 11922 protected boolean hasHoveredChild() { 11923 return false; 11924 } 11925 11926 /** 11927 * Dispatch a generic motion event to the view under the first pointer. 11928 * <p> 11929 * Do not call this method directly. 11930 * Call {@link #dispatchGenericMotionEvent(MotionEvent)} instead. 11931 * </p> 11932 * 11933 * @param event The motion event to be dispatched. 11934 * @return True if the event was handled by the view, false otherwise. 11935 */ 11936 protected boolean dispatchGenericPointerEvent(MotionEvent event) { 11937 return false; 11938 } 11939 11940 /** 11941 * Dispatch a generic motion event to the currently focused view. 11942 * <p> 11943 * Do not call this method directly. 11944 * Call {@link #dispatchGenericMotionEvent(MotionEvent)} instead. 11945 * </p> 11946 * 11947 * @param event The motion event to be dispatched. 11948 * @return True if the event was handled by the view, false otherwise. 11949 */ 11950 protected boolean dispatchGenericFocusedEvent(MotionEvent event) { 11951 return false; 11952 } 11953 11954 /** 11955 * Dispatch a pointer event. 11956 * <p> 11957 * Dispatches touch related pointer events to {@link #onTouchEvent(MotionEvent)} and all 11958 * other events to {@link #onGenericMotionEvent(MotionEvent)}. This separation of concerns 11959 * reinforces the invariant that {@link #onTouchEvent(MotionEvent)} is really about touches 11960 * and should not be expected to handle other pointing device features. 11961 * </p> 11962 * 11963 * @param event The motion event to be dispatched. 11964 * @return True if the event was handled by the view, false otherwise. 11965 * @hide 11966 */ 11967 public final boolean dispatchPointerEvent(MotionEvent event) { 11968 if (event.isTouchEvent()) { 11969 return dispatchTouchEvent(event); 11970 } else { 11971 return dispatchGenericMotionEvent(event); 11972 } 11973 } 11974 11975 /** 11976 * Called when the window containing this view gains or loses window focus. 11977 * ViewGroups should override to route to their children. 11978 * 11979 * @param hasFocus True if the window containing this view now has focus, 11980 * false otherwise. 11981 */ 11982 public void dispatchWindowFocusChanged(boolean hasFocus) { 11983 onWindowFocusChanged(hasFocus); 11984 } 11985 11986 /** 11987 * Called when the window containing this view gains or loses focus. Note 11988 * that this is separate from view focus: to receive key events, both 11989 * your view and its window must have focus. If a window is displayed 11990 * on top of yours that takes input focus, then your own window will lose 11991 * focus but the view focus will remain unchanged. 11992 * 11993 * @param hasWindowFocus True if the window containing this view now has 11994 * focus, false otherwise. 11995 */ 11996 public void onWindowFocusChanged(boolean hasWindowFocus) { 11997 InputMethodManager imm = InputMethodManager.peekInstance(); 11998 if (!hasWindowFocus) { 11999 if (isPressed()) { 12000 setPressed(false); 12001 } 12002 mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN; 12003 if (imm != null && (mPrivateFlags & PFLAG_FOCUSED) != 0) { 12004 imm.focusOut(this); 12005 } 12006 removeLongPressCallback(); 12007 removeTapCallback(); 12008 onFocusLost(); 12009 } else if (imm != null && (mPrivateFlags & PFLAG_FOCUSED) != 0) { 12010 imm.focusIn(this); 12011 } 12012 12013 notifyEnterOrExitForAutoFillIfNeeded(hasWindowFocus); 12014 12015 refreshDrawableState(); 12016 } 12017 12018 /** 12019 * Returns true if this view is in a window that currently has window focus. 12020 * Note that this is not the same as the view itself having focus. 12021 * 12022 * @return True if this view is in a window that currently has window focus. 12023 */ 12024 public boolean hasWindowFocus() { 12025 return mAttachInfo != null && mAttachInfo.mHasWindowFocus; 12026 } 12027 12028 /** 12029 * Dispatch a view visibility change down the view hierarchy. 12030 * ViewGroups should override to route to their children. 12031 * @param changedView The view whose visibility changed. Could be 'this' or 12032 * an ancestor view. 12033 * @param visibility The new visibility of changedView: {@link #VISIBLE}, 12034 * {@link #INVISIBLE} or {@link #GONE}. 12035 */ 12036 protected void dispatchVisibilityChanged(@NonNull View changedView, 12037 @Visibility int visibility) { 12038 onVisibilityChanged(changedView, visibility); 12039 } 12040 12041 /** 12042 * Called when the visibility of the view or an ancestor of the view has 12043 * changed. 12044 * 12045 * @param changedView The view whose visibility changed. May be 12046 * {@code this} or an ancestor view. 12047 * @param visibility The new visibility, one of {@link #VISIBLE}, 12048 * {@link #INVISIBLE} or {@link #GONE}. 12049 */ 12050 protected void onVisibilityChanged(@NonNull View changedView, @Visibility int visibility) { 12051 } 12052 12053 /** 12054 * Dispatch a hint about whether this view is displayed. For instance, when 12055 * a View moves out of the screen, it might receives a display hint indicating 12056 * the view is not displayed. Applications should not <em>rely</em> on this hint 12057 * as there is no guarantee that they will receive one. 12058 * 12059 * @param hint A hint about whether or not this view is displayed: 12060 * {@link #VISIBLE} or {@link #INVISIBLE}. 12061 */ 12062 public void dispatchDisplayHint(@Visibility int hint) { 12063 onDisplayHint(hint); 12064 } 12065 12066 /** 12067 * Gives this view a hint about whether is displayed or not. For instance, when 12068 * a View moves out of the screen, it might receives a display hint indicating 12069 * the view is not displayed. Applications should not <em>rely</em> on this hint 12070 * as there is no guarantee that they will receive one. 12071 * 12072 * @param hint A hint about whether or not this view is displayed: 12073 * {@link #VISIBLE} or {@link #INVISIBLE}. 12074 */ 12075 protected void onDisplayHint(@Visibility int hint) { 12076 } 12077 12078 /** 12079 * Dispatch a window visibility change down the view hierarchy. 12080 * ViewGroups should override to route to their children. 12081 * 12082 * @param visibility The new visibility of the window. 12083 * 12084 * @see #onWindowVisibilityChanged(int) 12085 */ 12086 public void dispatchWindowVisibilityChanged(@Visibility int visibility) { 12087 onWindowVisibilityChanged(visibility); 12088 } 12089 12090 /** 12091 * Called when the window containing has change its visibility 12092 * (between {@link #GONE}, {@link #INVISIBLE}, and {@link #VISIBLE}). Note 12093 * that this tells you whether or not your window is being made visible 12094 * to the window manager; this does <em>not</em> tell you whether or not 12095 * your window is obscured by other windows on the screen, even if it 12096 * is itself visible. 12097 * 12098 * @param visibility The new visibility of the window. 12099 */ 12100 protected void onWindowVisibilityChanged(@Visibility int visibility) { 12101 if (visibility == VISIBLE) { 12102 initialAwakenScrollBars(); 12103 } 12104 } 12105 12106 /** 12107 * Internal dispatching method for {@link #onVisibilityAggregated}. Overridden by 12108 * ViewGroup. Intended to only be called when {@link #isAttachedToWindow()}, 12109 * {@link #getWindowVisibility()} is {@link #VISIBLE} and this view's parent {@link #isShown()}. 12110 * 12111 * @param isVisible true if this view's visibility to the user is uninterrupted by its 12112 * ancestors or by window visibility 12113 * @return true if this view is visible to the user, not counting clipping or overlapping 12114 */ 12115 boolean dispatchVisibilityAggregated(boolean isVisible) { 12116 final boolean thisVisible = getVisibility() == VISIBLE; 12117 // If we're not visible but something is telling us we are, ignore it. 12118 if (thisVisible || !isVisible) { 12119 onVisibilityAggregated(isVisible); 12120 } 12121 return thisVisible && isVisible; 12122 } 12123 12124 /** 12125 * Called when the user-visibility of this View is potentially affected by a change 12126 * to this view itself, an ancestor view or the window this view is attached to. 12127 * 12128 * @param isVisible true if this view and all of its ancestors are {@link #VISIBLE} 12129 * and this view's window is also visible 12130 */ 12131 @CallSuper 12132 public void onVisibilityAggregated(boolean isVisible) { 12133 if (isVisible && mAttachInfo != null) { 12134 initialAwakenScrollBars(); 12135 } 12136 12137 final Drawable dr = mBackground; 12138 if (dr != null && isVisible != dr.isVisible()) { 12139 dr.setVisible(isVisible, false); 12140 } 12141 final Drawable hl = mDefaultFocusHighlight; 12142 if (hl != null && isVisible != hl.isVisible()) { 12143 hl.setVisible(isVisible, false); 12144 } 12145 final Drawable fg = mForegroundInfo != null ? mForegroundInfo.mDrawable : null; 12146 if (fg != null && isVisible != fg.isVisible()) { 12147 fg.setVisible(isVisible, false); 12148 } 12149 12150 if (isAutofillable()) { 12151 AutofillManager afm = getAutofillManager(); 12152 12153 if (afm != null && getAutofillViewId() > LAST_APP_AUTOFILL_ID) { 12154 if (mVisibilityChangeForAutofillHandler != null) { 12155 mVisibilityChangeForAutofillHandler.removeMessages(0); 12156 } 12157 12158 // If the view is in the background but still part of the hierarchy this is called 12159 // with isVisible=false. Hence visibility==false requires further checks 12160 if (isVisible) { 12161 afm.notifyViewVisibilityChanged(this, true); 12162 } else { 12163 if (mVisibilityChangeForAutofillHandler == null) { 12164 mVisibilityChangeForAutofillHandler = 12165 new VisibilityChangeForAutofillHandler(afm, this); 12166 } 12167 // Let current operation (e.g. removal of the view from the hierarchy) 12168 // finish before checking state 12169 mVisibilityChangeForAutofillHandler.obtainMessage(0, this).sendToTarget(); 12170 } 12171 } 12172 } 12173 } 12174 12175 /** 12176 * Returns the current visibility of the window this view is attached to 12177 * (either {@link #GONE}, {@link #INVISIBLE}, or {@link #VISIBLE}). 12178 * 12179 * @return Returns the current visibility of the view's window. 12180 */ 12181 @Visibility 12182 public int getWindowVisibility() { 12183 return mAttachInfo != null ? mAttachInfo.mWindowVisibility : GONE; 12184 } 12185 12186 /** 12187 * Retrieve the overall visible display size in which the window this view is 12188 * attached to has been positioned in. This takes into account screen 12189 * decorations above the window, for both cases where the window itself 12190 * is being position inside of them or the window is being placed under 12191 * then and covered insets are used for the window to position its content 12192 * inside. In effect, this tells you the available area where content can 12193 * be placed and remain visible to users. 12194 * 12195 * <p>This function requires an IPC back to the window manager to retrieve 12196 * the requested information, so should not be used in performance critical 12197 * code like drawing. 12198 * 12199 * @param outRect Filled in with the visible display frame. If the view 12200 * is not attached to a window, this is simply the raw display size. 12201 */ 12202 public void getWindowVisibleDisplayFrame(Rect outRect) { 12203 if (mAttachInfo != null) { 12204 try { 12205 mAttachInfo.mSession.getDisplayFrame(mAttachInfo.mWindow, outRect); 12206 } catch (RemoteException e) { 12207 return; 12208 } 12209 // XXX This is really broken, and probably all needs to be done 12210 // in the window manager, and we need to know more about whether 12211 // we want the area behind or in front of the IME. 12212 final Rect insets = mAttachInfo.mVisibleInsets; 12213 outRect.left += insets.left; 12214 outRect.top += insets.top; 12215 outRect.right -= insets.right; 12216 outRect.bottom -= insets.bottom; 12217 return; 12218 } 12219 // The view is not attached to a display so we don't have a context. 12220 // Make a best guess about the display size. 12221 Display d = DisplayManagerGlobal.getInstance().getRealDisplay(Display.DEFAULT_DISPLAY); 12222 d.getRectSize(outRect); 12223 } 12224 12225 /** 12226 * Like {@link #getWindowVisibleDisplayFrame}, but returns the "full" display frame this window 12227 * is currently in without any insets. 12228 * 12229 * @hide 12230 */ 12231 public void getWindowDisplayFrame(Rect outRect) { 12232 if (mAttachInfo != null) { 12233 try { 12234 mAttachInfo.mSession.getDisplayFrame(mAttachInfo.mWindow, outRect); 12235 } catch (RemoteException e) { 12236 return; 12237 } 12238 return; 12239 } 12240 // The view is not attached to a display so we don't have a context. 12241 // Make a best guess about the display size. 12242 Display d = DisplayManagerGlobal.getInstance().getRealDisplay(Display.DEFAULT_DISPLAY); 12243 d.getRectSize(outRect); 12244 } 12245 12246 /** 12247 * Dispatch a notification about a resource configuration change down 12248 * the view hierarchy. 12249 * ViewGroups should override to route to their children. 12250 * 12251 * @param newConfig The new resource configuration. 12252 * 12253 * @see #onConfigurationChanged(android.content.res.Configuration) 12254 */ 12255 public void dispatchConfigurationChanged(Configuration newConfig) { 12256 onConfigurationChanged(newConfig); 12257 } 12258 12259 /** 12260 * Called when the current configuration of the resources being used 12261 * by the application have changed. You can use this to decide when 12262 * to reload resources that can changed based on orientation and other 12263 * configuration characteristics. You only need to use this if you are 12264 * not relying on the normal {@link android.app.Activity} mechanism of 12265 * recreating the activity instance upon a configuration change. 12266 * 12267 * @param newConfig The new resource configuration. 12268 */ 12269 protected void onConfigurationChanged(Configuration newConfig) { 12270 } 12271 12272 /** 12273 * Private function to aggregate all per-view attributes in to the view 12274 * root. 12275 */ 12276 void dispatchCollectViewAttributes(AttachInfo attachInfo, int visibility) { 12277 performCollectViewAttributes(attachInfo, visibility); 12278 } 12279 12280 void performCollectViewAttributes(AttachInfo attachInfo, int visibility) { 12281 if ((visibility & VISIBILITY_MASK) == VISIBLE) { 12282 if ((mViewFlags & KEEP_SCREEN_ON) == KEEP_SCREEN_ON) { 12283 attachInfo.mKeepScreenOn = true; 12284 } 12285 attachInfo.mSystemUiVisibility |= mSystemUiVisibility; 12286 ListenerInfo li = mListenerInfo; 12287 if (li != null && li.mOnSystemUiVisibilityChangeListener != null) { 12288 attachInfo.mHasSystemUiListeners = true; 12289 } 12290 } 12291 } 12292 12293 void needGlobalAttributesUpdate(boolean force) { 12294 final AttachInfo ai = mAttachInfo; 12295 if (ai != null && !ai.mRecomputeGlobalAttributes) { 12296 if (force || ai.mKeepScreenOn || (ai.mSystemUiVisibility != 0) 12297 || ai.mHasSystemUiListeners) { 12298 ai.mRecomputeGlobalAttributes = true; 12299 } 12300 } 12301 } 12302 12303 /** 12304 * Returns whether the device is currently in touch mode. Touch mode is entered 12305 * once the user begins interacting with the device by touch, and affects various 12306 * things like whether focus is always visible to the user. 12307 * 12308 * @return Whether the device is in touch mode. 12309 */ 12310 @ViewDebug.ExportedProperty 12311 public boolean isInTouchMode() { 12312 if (mAttachInfo != null) { 12313 return mAttachInfo.mInTouchMode; 12314 } else { 12315 return ViewRootImpl.isInTouchMode(); 12316 } 12317 } 12318 12319 /** 12320 * Returns the context the view is running in, through which it can 12321 * access the current theme, resources, etc. 12322 * 12323 * @return The view's Context. 12324 */ 12325 @ViewDebug.CapturedViewProperty 12326 public final Context getContext() { 12327 return mContext; 12328 } 12329 12330 /** 12331 * Handle a key event before it is processed by any input method 12332 * associated with the view hierarchy. This can be used to intercept 12333 * key events in special situations before the IME consumes them; a 12334 * typical example would be handling the BACK key to update the application's 12335 * UI instead of allowing the IME to see it and close itself. 12336 * 12337 * @param keyCode The value in event.getKeyCode(). 12338 * @param event Description of the key event. 12339 * @return If you handled the event, return true. If you want to allow the 12340 * event to be handled by the next receiver, return false. 12341 */ 12342 public boolean onKeyPreIme(int keyCode, KeyEvent event) { 12343 return false; 12344 } 12345 12346 /** 12347 * Default implementation of {@link KeyEvent.Callback#onKeyDown(int, KeyEvent) 12348 * KeyEvent.Callback.onKeyDown()}: perform press of the view 12349 * when {@link KeyEvent#KEYCODE_DPAD_CENTER} or {@link KeyEvent#KEYCODE_ENTER} 12350 * is released, if the view is enabled and clickable. 12351 * <p> 12352 * Key presses in software keyboards will generally NOT trigger this 12353 * listener, although some may elect to do so in some situations. Do not 12354 * rely on this to catch software key presses. 12355 * 12356 * @param keyCode a key code that represents the button pressed, from 12357 * {@link android.view.KeyEvent} 12358 * @param event the KeyEvent object that defines the button action 12359 */ 12360 public boolean onKeyDown(int keyCode, KeyEvent event) { 12361 if (KeyEvent.isConfirmKey(keyCode)) { 12362 if ((mViewFlags & ENABLED_MASK) == DISABLED) { 12363 return true; 12364 } 12365 12366 if (event.getRepeatCount() == 0) { 12367 // Long clickable items don't necessarily have to be clickable. 12368 final boolean clickable = (mViewFlags & CLICKABLE) == CLICKABLE 12369 || (mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE; 12370 if (clickable || (mViewFlags & TOOLTIP) == TOOLTIP) { 12371 // For the purposes of menu anchoring and drawable hotspots, 12372 // key events are considered to be at the center of the view. 12373 final float x = getWidth() / 2f; 12374 final float y = getHeight() / 2f; 12375 if (clickable) { 12376 setPressed(true, x, y); 12377 } 12378 checkForLongClick(0, x, y); 12379 return true; 12380 } 12381 } 12382 } 12383 12384 return false; 12385 } 12386 12387 /** 12388 * Default implementation of {@link KeyEvent.Callback#onKeyLongPress(int, KeyEvent) 12389 * KeyEvent.Callback.onKeyLongPress()}: always returns false (doesn't handle 12390 * the event). 12391 * <p>Key presses in software keyboards will generally NOT trigger this listener, 12392 * although some may elect to do so in some situations. Do not rely on this to 12393 * catch software key presses. 12394 */ 12395 public boolean onKeyLongPress(int keyCode, KeyEvent event) { 12396 return false; 12397 } 12398 12399 /** 12400 * Default implementation of {@link KeyEvent.Callback#onKeyUp(int, KeyEvent) 12401 * KeyEvent.Callback.onKeyUp()}: perform clicking of the view 12402 * when {@link KeyEvent#KEYCODE_DPAD_CENTER}, {@link KeyEvent#KEYCODE_ENTER} 12403 * or {@link KeyEvent#KEYCODE_SPACE} is released. 12404 * <p>Key presses in software keyboards will generally NOT trigger this listener, 12405 * although some may elect to do so in some situations. Do not rely on this to 12406 * catch software key presses. 12407 * 12408 * @param keyCode A key code that represents the button pressed, from 12409 * {@link android.view.KeyEvent}. 12410 * @param event The KeyEvent object that defines the button action. 12411 */ 12412 public boolean onKeyUp(int keyCode, KeyEvent event) { 12413 if (KeyEvent.isConfirmKey(keyCode)) { 12414 if ((mViewFlags & ENABLED_MASK) == DISABLED) { 12415 return true; 12416 } 12417 if ((mViewFlags & CLICKABLE) == CLICKABLE && isPressed()) { 12418 setPressed(false); 12419 12420 if (!mHasPerformedLongPress) { 12421 // This is a tap, so remove the longpress check 12422 removeLongPressCallback(); 12423 if (!event.isCanceled()) { 12424 return performClick(); 12425 } 12426 } 12427 } 12428 } 12429 return false; 12430 } 12431 12432 /** 12433 * Default implementation of {@link KeyEvent.Callback#onKeyMultiple(int, int, KeyEvent) 12434 * KeyEvent.Callback.onKeyMultiple()}: always returns false (doesn't handle 12435 * the event). 12436 * <p>Key presses in software keyboards will generally NOT trigger this listener, 12437 * although some may elect to do so in some situations. Do not rely on this to 12438 * catch software key presses. 12439 * 12440 * @param keyCode A key code that represents the button pressed, from 12441 * {@link android.view.KeyEvent}. 12442 * @param repeatCount The number of times the action was made. 12443 * @param event The KeyEvent object that defines the button action. 12444 */ 12445 public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event) { 12446 return false; 12447 } 12448 12449 /** 12450 * Called on the focused view when a key shortcut event is not handled. 12451 * Override this method to implement local key shortcuts for the View. 12452 * Key shortcuts can also be implemented by setting the 12453 * {@link MenuItem#setShortcut(char, char) shortcut} property of menu items. 12454 * 12455 * @param keyCode The value in event.getKeyCode(). 12456 * @param event Description of the key event. 12457 * @return If you handled the event, return true. If you want to allow the 12458 * event to be handled by the next receiver, return false. 12459 */ 12460 public boolean onKeyShortcut(int keyCode, KeyEvent event) { 12461 return false; 12462 } 12463 12464 /** 12465 * Check whether the called view is a text editor, in which case it 12466 * would make sense to automatically display a soft input window for 12467 * it. Subclasses should override this if they implement 12468 * {@link #onCreateInputConnection(EditorInfo)} to return true if 12469 * a call on that method would return a non-null InputConnection, and 12470 * they are really a first-class editor that the user would normally 12471 * start typing on when the go into a window containing your view. 12472 * 12473 * <p>The default implementation always returns false. This does 12474 * <em>not</em> mean that its {@link #onCreateInputConnection(EditorInfo)} 12475 * will not be called or the user can not otherwise perform edits on your 12476 * view; it is just a hint to the system that this is not the primary 12477 * purpose of this view. 12478 * 12479 * @return Returns true if this view is a text editor, else false. 12480 */ 12481 public boolean onCheckIsTextEditor() { 12482 return false; 12483 } 12484 12485 /** 12486 * Create a new InputConnection for an InputMethod to interact 12487 * with the view. The default implementation returns null, since it doesn't 12488 * support input methods. You can override this to implement such support. 12489 * This is only needed for views that take focus and text input. 12490 * 12491 * <p>When implementing this, you probably also want to implement 12492 * {@link #onCheckIsTextEditor()} to indicate you will return a 12493 * non-null InputConnection.</p> 12494 * 12495 * <p>Also, take good care to fill in the {@link android.view.inputmethod.EditorInfo} 12496 * object correctly and in its entirety, so that the connected IME can rely 12497 * on its values. For example, {@link android.view.inputmethod.EditorInfo#initialSelStart} 12498 * and {@link android.view.inputmethod.EditorInfo#initialSelEnd} members 12499 * must be filled in with the correct cursor position for IMEs to work correctly 12500 * with your application.</p> 12501 * 12502 * @param outAttrs Fill in with attribute information about the connection. 12503 */ 12504 public InputConnection onCreateInputConnection(EditorInfo outAttrs) { 12505 return null; 12506 } 12507 12508 /** 12509 * Called by the {@link android.view.inputmethod.InputMethodManager} 12510 * when a view who is not the current 12511 * input connection target is trying to make a call on the manager. The 12512 * default implementation returns false; you can override this to return 12513 * true for certain views if you are performing InputConnection proxying 12514 * to them. 12515 * @param view The View that is making the InputMethodManager call. 12516 * @return Return true to allow the call, false to reject. 12517 */ 12518 public boolean checkInputConnectionProxy(View view) { 12519 return false; 12520 } 12521 12522 /** 12523 * Show the context menu for this view. It is not safe to hold on to the 12524 * menu after returning from this method. 12525 * 12526 * You should normally not overload this method. Overload 12527 * {@link #onCreateContextMenu(ContextMenu)} or define an 12528 * {@link OnCreateContextMenuListener} to add items to the context menu. 12529 * 12530 * @param menu The context menu to populate 12531 */ 12532 public void createContextMenu(ContextMenu menu) { 12533 ContextMenuInfo menuInfo = getContextMenuInfo(); 12534 12535 // Sets the current menu info so all items added to menu will have 12536 // my extra info set. 12537 ((MenuBuilder)menu).setCurrentMenuInfo(menuInfo); 12538 12539 onCreateContextMenu(menu); 12540 ListenerInfo li = mListenerInfo; 12541 if (li != null && li.mOnCreateContextMenuListener != null) { 12542 li.mOnCreateContextMenuListener.onCreateContextMenu(menu, this, menuInfo); 12543 } 12544 12545 // Clear the extra information so subsequent items that aren't mine don't 12546 // have my extra info. 12547 ((MenuBuilder)menu).setCurrentMenuInfo(null); 12548 12549 if (mParent != null) { 12550 mParent.createContextMenu(menu); 12551 } 12552 } 12553 12554 /** 12555 * Views should implement this if they have extra information to associate 12556 * with the context menu. The return result is supplied as a parameter to 12557 * the {@link OnCreateContextMenuListener#onCreateContextMenu(ContextMenu, View, ContextMenuInfo)} 12558 * callback. 12559 * 12560 * @return Extra information about the item for which the context menu 12561 * should be shown. This information will vary across different 12562 * subclasses of View. 12563 */ 12564 protected ContextMenuInfo getContextMenuInfo() { 12565 return null; 12566 } 12567 12568 /** 12569 * Views should implement this if the view itself is going to add items to 12570 * the context menu. 12571 * 12572 * @param menu the context menu to populate 12573 */ 12574 protected void onCreateContextMenu(ContextMenu menu) { 12575 } 12576 12577 /** 12578 * Implement this method to handle trackball motion events. The 12579 * <em>relative</em> movement of the trackball since the last event 12580 * can be retrieve with {@link MotionEvent#getX MotionEvent.getX()} and 12581 * {@link MotionEvent#getY MotionEvent.getY()}. These are normalized so 12582 * that a movement of 1 corresponds to the user pressing one DPAD key (so 12583 * they will often be fractional values, representing the more fine-grained 12584 * movement information available from a trackball). 12585 * 12586 * @param event The motion event. 12587 * @return True if the event was handled, false otherwise. 12588 */ 12589 public boolean onTrackballEvent(MotionEvent event) { 12590 return false; 12591 } 12592 12593 /** 12594 * Implement this method to handle generic motion events. 12595 * <p> 12596 * Generic motion events describe joystick movements, mouse hovers, track pad 12597 * touches, scroll wheel movements and other input events. The 12598 * {@link MotionEvent#getSource() source} of the motion event specifies 12599 * the class of input that was received. Implementations of this method 12600 * must examine the bits in the source before processing the event. 12601 * The following code example shows how this is done. 12602 * </p><p> 12603 * Generic motion events with source class {@link InputDevice#SOURCE_CLASS_POINTER} 12604 * are delivered to the view under the pointer. All other generic motion events are 12605 * delivered to the focused view. 12606 * </p> 12607 * <pre> public boolean onGenericMotionEvent(MotionEvent event) { 12608 * if (event.isFromSource(InputDevice.SOURCE_CLASS_JOYSTICK)) { 12609 * if (event.getAction() == MotionEvent.ACTION_MOVE) { 12610 * // process the joystick movement... 12611 * return true; 12612 * } 12613 * } 12614 * if (event.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) { 12615 * switch (event.getAction()) { 12616 * case MotionEvent.ACTION_HOVER_MOVE: 12617 * // process the mouse hover movement... 12618 * return true; 12619 * case MotionEvent.ACTION_SCROLL: 12620 * // process the scroll wheel movement... 12621 * return true; 12622 * } 12623 * } 12624 * return super.onGenericMotionEvent(event); 12625 * }</pre> 12626 * 12627 * @param event The generic motion event being processed. 12628 * @return True if the event was handled, false otherwise. 12629 */ 12630 public boolean onGenericMotionEvent(MotionEvent event) { 12631 return false; 12632 } 12633 12634 /** 12635 * Implement this method to handle hover events. 12636 * <p> 12637 * This method is called whenever a pointer is hovering into, over, or out of the 12638 * bounds of a view and the view is not currently being touched. 12639 * Hover events are represented as pointer events with action 12640 * {@link MotionEvent#ACTION_HOVER_ENTER}, {@link MotionEvent#ACTION_HOVER_MOVE}, 12641 * or {@link MotionEvent#ACTION_HOVER_EXIT}. 12642 * </p> 12643 * <ul> 12644 * <li>The view receives a hover event with action {@link MotionEvent#ACTION_HOVER_ENTER} 12645 * when the pointer enters the bounds of the view.</li> 12646 * <li>The view receives a hover event with action {@link MotionEvent#ACTION_HOVER_MOVE} 12647 * when the pointer has already entered the bounds of the view and has moved.</li> 12648 * <li>The view receives a hover event with action {@link MotionEvent#ACTION_HOVER_EXIT} 12649 * when the pointer has exited the bounds of the view or when the pointer is 12650 * about to go down due to a button click, tap, or similar user action that 12651 * causes the view to be touched.</li> 12652 * </ul> 12653 * <p> 12654 * The view should implement this method to return true to indicate that it is 12655 * handling the hover event, such as by changing its drawable state. 12656 * </p><p> 12657 * The default implementation calls {@link #setHovered} to update the hovered state 12658 * of the view when a hover enter or hover exit event is received, if the view 12659 * is enabled and is clickable. The default implementation also sends hover 12660 * accessibility events. 12661 * </p> 12662 * 12663 * @param event The motion event that describes the hover. 12664 * @return True if the view handled the hover event. 12665 * 12666 * @see #isHovered 12667 * @see #setHovered 12668 * @see #onHoverChanged 12669 */ 12670 public boolean onHoverEvent(MotionEvent event) { 12671 // The root view may receive hover (or touch) events that are outside the bounds of 12672 // the window. This code ensures that we only send accessibility events for 12673 // hovers that are actually within the bounds of the root view. 12674 final int action = event.getActionMasked(); 12675 if (!mSendingHoverAccessibilityEvents) { 12676 if ((action == MotionEvent.ACTION_HOVER_ENTER 12677 || action == MotionEvent.ACTION_HOVER_MOVE) 12678 && !hasHoveredChild() 12679 && pointInView(event.getX(), event.getY())) { 12680 sendAccessibilityHoverEvent(AccessibilityEvent.TYPE_VIEW_HOVER_ENTER); 12681 mSendingHoverAccessibilityEvents = true; 12682 } 12683 } else { 12684 if (action == MotionEvent.ACTION_HOVER_EXIT 12685 || (action == MotionEvent.ACTION_MOVE 12686 && !pointInView(event.getX(), event.getY()))) { 12687 mSendingHoverAccessibilityEvents = false; 12688 sendAccessibilityHoverEvent(AccessibilityEvent.TYPE_VIEW_HOVER_EXIT); 12689 } 12690 } 12691 12692 if ((action == MotionEvent.ACTION_HOVER_ENTER || action == MotionEvent.ACTION_HOVER_MOVE) 12693 && event.isFromSource(InputDevice.SOURCE_MOUSE) 12694 && isOnScrollbar(event.getX(), event.getY())) { 12695 awakenScrollBars(); 12696 } 12697 12698 // If we consider ourself hoverable, or if we we're already hovered, 12699 // handle changing state in response to ENTER and EXIT events. 12700 if (isHoverable() || isHovered()) { 12701 switch (action) { 12702 case MotionEvent.ACTION_HOVER_ENTER: 12703 setHovered(true); 12704 break; 12705 case MotionEvent.ACTION_HOVER_EXIT: 12706 setHovered(false); 12707 break; 12708 } 12709 12710 // Dispatch the event to onGenericMotionEvent before returning true. 12711 // This is to provide compatibility with existing applications that 12712 // handled HOVER_MOVE events in onGenericMotionEvent and that would 12713 // break because of the new default handling for hoverable views 12714 // in onHoverEvent. 12715 // Note that onGenericMotionEvent will be called by default when 12716 // onHoverEvent returns false (refer to dispatchGenericMotionEvent). 12717 dispatchGenericMotionEventInternal(event); 12718 // The event was already handled by calling setHovered(), so always 12719 // return true. 12720 return true; 12721 } 12722 12723 return false; 12724 } 12725 12726 /** 12727 * Returns true if the view should handle {@link #onHoverEvent} 12728 * by calling {@link #setHovered} to change its hovered state. 12729 * 12730 * @return True if the view is hoverable. 12731 */ 12732 private boolean isHoverable() { 12733 final int viewFlags = mViewFlags; 12734 if ((viewFlags & ENABLED_MASK) == DISABLED) { 12735 return false; 12736 } 12737 12738 return (viewFlags & CLICKABLE) == CLICKABLE 12739 || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE 12740 || (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE; 12741 } 12742 12743 /** 12744 * Returns true if the view is currently hovered. 12745 * 12746 * @return True if the view is currently hovered. 12747 * 12748 * @see #setHovered 12749 * @see #onHoverChanged 12750 */ 12751 @ViewDebug.ExportedProperty 12752 public boolean isHovered() { 12753 return (mPrivateFlags & PFLAG_HOVERED) != 0; 12754 } 12755 12756 /** 12757 * Sets whether the view is currently hovered. 12758 * <p> 12759 * Calling this method also changes the drawable state of the view. This 12760 * enables the view to react to hover by using different drawable resources 12761 * to change its appearance. 12762 * </p><p> 12763 * The {@link #onHoverChanged} method is called when the hovered state changes. 12764 * </p> 12765 * 12766 * @param hovered True if the view is hovered. 12767 * 12768 * @see #isHovered 12769 * @see #onHoverChanged 12770 */ 12771 public void setHovered(boolean hovered) { 12772 if (hovered) { 12773 if ((mPrivateFlags & PFLAG_HOVERED) == 0) { 12774 mPrivateFlags |= PFLAG_HOVERED; 12775 refreshDrawableState(); 12776 onHoverChanged(true); 12777 } 12778 } else { 12779 if ((mPrivateFlags & PFLAG_HOVERED) != 0) { 12780 mPrivateFlags &= ~PFLAG_HOVERED; 12781 refreshDrawableState(); 12782 onHoverChanged(false); 12783 } 12784 } 12785 } 12786 12787 /** 12788 * Implement this method to handle hover state changes. 12789 * <p> 12790 * This method is called whenever the hover state changes as a result of a 12791 * call to {@link #setHovered}. 12792 * </p> 12793 * 12794 * @param hovered The current hover state, as returned by {@link #isHovered}. 12795 * 12796 * @see #isHovered 12797 * @see #setHovered 12798 */ 12799 public void onHoverChanged(boolean hovered) { 12800 } 12801 12802 /** 12803 * Handles scroll bar dragging by mouse input. 12804 * 12805 * @hide 12806 * @param event The motion event. 12807 * 12808 * @return true if the event was handled as a scroll bar dragging, false otherwise. 12809 */ 12810 protected boolean handleScrollBarDragging(MotionEvent event) { 12811 if (mScrollCache == null) { 12812 return false; 12813 } 12814 final float x = event.getX(); 12815 final float y = event.getY(); 12816 final int action = event.getAction(); 12817 if ((mScrollCache.mScrollBarDraggingState == ScrollabilityCache.NOT_DRAGGING 12818 && action != MotionEvent.ACTION_DOWN) 12819 || !event.isFromSource(InputDevice.SOURCE_MOUSE) 12820 || !event.isButtonPressed(MotionEvent.BUTTON_PRIMARY)) { 12821 mScrollCache.mScrollBarDraggingState = ScrollabilityCache.NOT_DRAGGING; 12822 return false; 12823 } 12824 12825 switch (action) { 12826 case MotionEvent.ACTION_MOVE: 12827 if (mScrollCache.mScrollBarDraggingState == ScrollabilityCache.NOT_DRAGGING) { 12828 return false; 12829 } 12830 if (mScrollCache.mScrollBarDraggingState 12831 == ScrollabilityCache.DRAGGING_VERTICAL_SCROLL_BAR) { 12832 final Rect bounds = mScrollCache.mScrollBarBounds; 12833 getVerticalScrollBarBounds(bounds, null); 12834 final int range = computeVerticalScrollRange(); 12835 final int offset = computeVerticalScrollOffset(); 12836 final int extent = computeVerticalScrollExtent(); 12837 12838 final int thumbLength = ScrollBarUtils.getThumbLength( 12839 bounds.height(), bounds.width(), extent, range); 12840 final int thumbOffset = ScrollBarUtils.getThumbOffset( 12841 bounds.height(), thumbLength, extent, range, offset); 12842 12843 final float diff = y - mScrollCache.mScrollBarDraggingPos; 12844 final float maxThumbOffset = bounds.height() - thumbLength; 12845 final float newThumbOffset = 12846 Math.min(Math.max(thumbOffset + diff, 0.0f), maxThumbOffset); 12847 final int height = getHeight(); 12848 if (Math.round(newThumbOffset) != thumbOffset && maxThumbOffset > 0 12849 && height > 0 && extent > 0) { 12850 final int newY = Math.round((range - extent) 12851 / ((float)extent / height) * (newThumbOffset / maxThumbOffset)); 12852 if (newY != getScrollY()) { 12853 mScrollCache.mScrollBarDraggingPos = y; 12854 setScrollY(newY); 12855 } 12856 } 12857 return true; 12858 } 12859 if (mScrollCache.mScrollBarDraggingState 12860 == ScrollabilityCache.DRAGGING_HORIZONTAL_SCROLL_BAR) { 12861 final Rect bounds = mScrollCache.mScrollBarBounds; 12862 getHorizontalScrollBarBounds(bounds, null); 12863 final int range = computeHorizontalScrollRange(); 12864 final int offset = computeHorizontalScrollOffset(); 12865 final int extent = computeHorizontalScrollExtent(); 12866 12867 final int thumbLength = ScrollBarUtils.getThumbLength( 12868 bounds.width(), bounds.height(), extent, range); 12869 final int thumbOffset = ScrollBarUtils.getThumbOffset( 12870 bounds.width(), thumbLength, extent, range, offset); 12871 12872 final float diff = x - mScrollCache.mScrollBarDraggingPos; 12873 final float maxThumbOffset = bounds.width() - thumbLength; 12874 final float newThumbOffset = 12875 Math.min(Math.max(thumbOffset + diff, 0.0f), maxThumbOffset); 12876 final int width = getWidth(); 12877 if (Math.round(newThumbOffset) != thumbOffset && maxThumbOffset > 0 12878 && width > 0 && extent > 0) { 12879 final int newX = Math.round((range - extent) 12880 / ((float)extent / width) * (newThumbOffset / maxThumbOffset)); 12881 if (newX != getScrollX()) { 12882 mScrollCache.mScrollBarDraggingPos = x; 12883 setScrollX(newX); 12884 } 12885 } 12886 return true; 12887 } 12888 case MotionEvent.ACTION_DOWN: 12889 if (mScrollCache.state == ScrollabilityCache.OFF) { 12890 return false; 12891 } 12892 if (isOnVerticalScrollbarThumb(x, y)) { 12893 mScrollCache.mScrollBarDraggingState = 12894 ScrollabilityCache.DRAGGING_VERTICAL_SCROLL_BAR; 12895 mScrollCache.mScrollBarDraggingPos = y; 12896 return true; 12897 } 12898 if (isOnHorizontalScrollbarThumb(x, y)) { 12899 mScrollCache.mScrollBarDraggingState = 12900 ScrollabilityCache.DRAGGING_HORIZONTAL_SCROLL_BAR; 12901 mScrollCache.mScrollBarDraggingPos = x; 12902 return true; 12903 } 12904 } 12905 mScrollCache.mScrollBarDraggingState = ScrollabilityCache.NOT_DRAGGING; 12906 return false; 12907 } 12908 12909 /** 12910 * Implement this method to handle touch screen motion events. 12911 * <p> 12912 * If this method is used to detect click actions, it is recommended that 12913 * the actions be performed by implementing and calling 12914 * {@link #performClick()}. This will ensure consistent system behavior, 12915 * including: 12916 * <ul> 12917 * <li>obeying click sound preferences 12918 * <li>dispatching OnClickListener calls 12919 * <li>handling {@link AccessibilityNodeInfo#ACTION_CLICK ACTION_CLICK} when 12920 * accessibility features are enabled 12921 * </ul> 12922 * 12923 * @param event The motion event. 12924 * @return True if the event was handled, false otherwise. 12925 */ 12926 public boolean onTouchEvent(MotionEvent event) { 12927 final float x = event.getX(); 12928 final float y = event.getY(); 12929 final int viewFlags = mViewFlags; 12930 final int action = event.getAction(); 12931 12932 final boolean clickable = ((viewFlags & CLICKABLE) == CLICKABLE 12933 || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE) 12934 || (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE; 12935 12936 if ((viewFlags & ENABLED_MASK) == DISABLED) { 12937 if (action == MotionEvent.ACTION_UP && (mPrivateFlags & PFLAG_PRESSED) != 0) { 12938 setPressed(false); 12939 } 12940 mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN; 12941 // A disabled view that is clickable still consumes the touch 12942 // events, it just doesn't respond to them. 12943 return clickable; 12944 } 12945 if (mTouchDelegate != null) { 12946 if (mTouchDelegate.onTouchEvent(event)) { 12947 return true; 12948 } 12949 } 12950 12951 if (clickable || (viewFlags & TOOLTIP) == TOOLTIP) { 12952 switch (action) { 12953 case MotionEvent.ACTION_UP: 12954 mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN; 12955 if ((viewFlags & TOOLTIP) == TOOLTIP) { 12956 handleTooltipUp(); 12957 } 12958 if (!clickable) { 12959 removeTapCallback(); 12960 removeLongPressCallback(); 12961 mInContextButtonPress = false; 12962 mHasPerformedLongPress = false; 12963 mIgnoreNextUpEvent = false; 12964 break; 12965 } 12966 boolean prepressed = (mPrivateFlags & PFLAG_PREPRESSED) != 0; 12967 if ((mPrivateFlags & PFLAG_PRESSED) != 0 || prepressed) { 12968 // take focus if we don't have it already and we should in 12969 // touch mode. 12970 boolean focusTaken = false; 12971 if (isFocusable() && isFocusableInTouchMode() && !isFocused()) { 12972 focusTaken = requestFocus(); 12973 } 12974 12975 if (prepressed) { 12976 // The button is being released before we actually 12977 // showed it as pressed. Make it show the pressed 12978 // state now (before scheduling the click) to ensure 12979 // the user sees it. 12980 setPressed(true, x, y); 12981 } 12982 12983 if (!mHasPerformedLongPress && !mIgnoreNextUpEvent) { 12984 // This is a tap, so remove the longpress check 12985 removeLongPressCallback(); 12986 12987 // Only perform take click actions if we were in the pressed state 12988 if (!focusTaken) { 12989 // Use a Runnable and post this rather than calling 12990 // performClick directly. This lets other visual state 12991 // of the view update before click actions start. 12992 if (mPerformClick == null) { 12993 mPerformClick = new PerformClick(); 12994 } 12995 if (!post(mPerformClick)) { 12996 performClick(); 12997 } 12998 } 12999 } 13000 13001 if (mUnsetPressedState == null) { 13002 mUnsetPressedState = new UnsetPressedState(); 13003 } 13004 13005 if (prepressed) { 13006 postDelayed(mUnsetPressedState, 13007 ViewConfiguration.getPressedStateDuration()); 13008 } else if (!post(mUnsetPressedState)) { 13009 // If the post failed, unpress right now 13010 mUnsetPressedState.run(); 13011 } 13012 13013 removeTapCallback(); 13014 } 13015 mIgnoreNextUpEvent = false; 13016 break; 13017 13018 case MotionEvent.ACTION_DOWN: 13019 if (event.getSource() == InputDevice.SOURCE_TOUCHSCREEN) { 13020 mPrivateFlags3 |= PFLAG3_FINGER_DOWN; 13021 } 13022 mHasPerformedLongPress = false; 13023 13024 if (!clickable) { 13025 checkForLongClick(0, x, y); 13026 break; 13027 } 13028 13029 if (performButtonActionOnTouchDown(event)) { 13030 break; 13031 } 13032 13033 // Walk up the hierarchy to determine if we're inside a scrolling container. 13034 boolean isInScrollingContainer = isInScrollingContainer(); 13035 13036 // For views inside a scrolling container, delay the pressed feedback for 13037 // a short period in case this is a scroll. 13038 if (isInScrollingContainer) { 13039 mPrivateFlags |= PFLAG_PREPRESSED; 13040 if (mPendingCheckForTap == null) { 13041 mPendingCheckForTap = new CheckForTap(); 13042 } 13043 mPendingCheckForTap.x = event.getX(); 13044 mPendingCheckForTap.y = event.getY(); 13045 postDelayed(mPendingCheckForTap, ViewConfiguration.getTapTimeout()); 13046 } else { 13047 // Not inside a scrolling container, so show the feedback right away 13048 setPressed(true, x, y); 13049 checkForLongClick(0, x, y); 13050 } 13051 break; 13052 13053 case MotionEvent.ACTION_CANCEL: 13054 if (clickable) { 13055 setPressed(false); 13056 } 13057 removeTapCallback(); 13058 removeLongPressCallback(); 13059 mInContextButtonPress = false; 13060 mHasPerformedLongPress = false; 13061 mIgnoreNextUpEvent = false; 13062 mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN; 13063 break; 13064 13065 case MotionEvent.ACTION_MOVE: 13066 if (clickable) { 13067 drawableHotspotChanged(x, y); 13068 } 13069 13070 // Be lenient about moving outside of buttons 13071 if (!pointInView(x, y, mTouchSlop)) { 13072 // Outside button 13073 // Remove any future long press/tap checks 13074 removeTapCallback(); 13075 removeLongPressCallback(); 13076 if ((mPrivateFlags & PFLAG_PRESSED) != 0) { 13077 setPressed(false); 13078 } 13079 mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN; 13080 } 13081 break; 13082 } 13083 13084 return true; 13085 } 13086 13087 return false; 13088 } 13089 13090 /** 13091 * @hide 13092 */ 13093 public boolean isInScrollingContainer() { 13094 ViewParent p = getParent(); 13095 while (p != null && p instanceof ViewGroup) { 13096 if (((ViewGroup) p).shouldDelayChildPressedState()) { 13097 return true; 13098 } 13099 p = p.getParent(); 13100 } 13101 return false; 13102 } 13103 13104 /** 13105 * Remove the longpress detection timer. 13106 */ 13107 private void removeLongPressCallback() { 13108 if (mPendingCheckForLongPress != null) { 13109 removeCallbacks(mPendingCheckForLongPress); 13110 } 13111 } 13112 13113 /** 13114 * Remove the pending click action 13115 */ 13116 private void removePerformClickCallback() { 13117 if (mPerformClick != null) { 13118 removeCallbacks(mPerformClick); 13119 } 13120 } 13121 13122 /** 13123 * Remove the prepress detection timer. 13124 */ 13125 private void removeUnsetPressCallback() { 13126 if ((mPrivateFlags & PFLAG_PRESSED) != 0 && mUnsetPressedState != null) { 13127 setPressed(false); 13128 removeCallbacks(mUnsetPressedState); 13129 } 13130 } 13131 13132 /** 13133 * Remove the tap detection timer. 13134 */ 13135 private void removeTapCallback() { 13136 if (mPendingCheckForTap != null) { 13137 mPrivateFlags &= ~PFLAG_PREPRESSED; 13138 removeCallbacks(mPendingCheckForTap); 13139 } 13140 } 13141 13142 /** 13143 * Cancels a pending long press. Your subclass can use this if you 13144 * want the context menu to come up if the user presses and holds 13145 * at the same place, but you don't want it to come up if they press 13146 * and then move around enough to cause scrolling. 13147 */ 13148 public void cancelLongPress() { 13149 removeLongPressCallback(); 13150 13151 /* 13152 * The prepressed state handled by the tap callback is a display 13153 * construct, but the tap callback will post a long press callback 13154 * less its own timeout. Remove it here. 13155 */ 13156 removeTapCallback(); 13157 } 13158 13159 /** 13160 * Remove the pending callback for sending a 13161 * {@link AccessibilityEvent#TYPE_VIEW_SCROLLED} accessibility event. 13162 */ 13163 private void removeSendViewScrolledAccessibilityEventCallback() { 13164 if (mSendViewScrolledAccessibilityEvent != null) { 13165 removeCallbacks(mSendViewScrolledAccessibilityEvent); 13166 mSendViewScrolledAccessibilityEvent.mIsPending = false; 13167 } 13168 } 13169 13170 /** 13171 * Sets the TouchDelegate for this View. 13172 */ 13173 public void setTouchDelegate(TouchDelegate delegate) { 13174 mTouchDelegate = delegate; 13175 } 13176 13177 /** 13178 * Gets the TouchDelegate for this View. 13179 */ 13180 public TouchDelegate getTouchDelegate() { 13181 return mTouchDelegate; 13182 } 13183 13184 /** 13185 * Request unbuffered dispatch of the given stream of MotionEvents to this View. 13186 * 13187 * Until this View receives a corresponding {@link MotionEvent#ACTION_UP}, ask that the input 13188 * system not batch {@link MotionEvent}s but instead deliver them as soon as they're 13189 * available. This method should only be called for touch events. 13190 * 13191 * <p class="note">This api is not intended for most applications. Buffered dispatch 13192 * provides many of benefits, and just requesting unbuffered dispatch on most MotionEvent 13193 * streams will not improve your input latency. Side effects include: increased latency, 13194 * jittery scrolls and inability to take advantage of system resampling. Talk to your input 13195 * professional to see if {@link #requestUnbufferedDispatch(MotionEvent)} is right for 13196 * you.</p> 13197 */ 13198 public final void requestUnbufferedDispatch(MotionEvent event) { 13199 final int action = event.getAction(); 13200 if (mAttachInfo == null 13201 || action != MotionEvent.ACTION_DOWN && action != MotionEvent.ACTION_MOVE 13202 || !event.isTouchEvent()) { 13203 return; 13204 } 13205 mAttachInfo.mUnbufferedDispatchRequested = true; 13206 } 13207 13208 /** 13209 * Set flags controlling behavior of this view. 13210 * 13211 * @param flags Constant indicating the value which should be set 13212 * @param mask Constant indicating the bit range that should be changed 13213 */ 13214 void setFlags(int flags, int mask) { 13215 final boolean accessibilityEnabled = 13216 AccessibilityManager.getInstance(mContext).isEnabled(); 13217 final boolean oldIncludeForAccessibility = accessibilityEnabled && includeForAccessibility(); 13218 13219 int old = mViewFlags; 13220 mViewFlags = (mViewFlags & ~mask) | (flags & mask); 13221 13222 int changed = mViewFlags ^ old; 13223 if (changed == 0) { 13224 return; 13225 } 13226 int privateFlags = mPrivateFlags; 13227 13228 // If focusable is auto, update the FOCUSABLE bit. 13229 int focusableChangedByAuto = 0; 13230 if (((mViewFlags & FOCUSABLE_AUTO) != 0) 13231 && (changed & (FOCUSABLE_MASK | CLICKABLE)) != 0) { 13232 // Heuristic only takes into account whether view is clickable. 13233 final int newFocus; 13234 if ((mViewFlags & CLICKABLE) != 0) { 13235 newFocus = FOCUSABLE; 13236 } else { 13237 newFocus = NOT_FOCUSABLE; 13238 } 13239 mViewFlags = (mViewFlags & ~FOCUSABLE) | newFocus; 13240 focusableChangedByAuto = (old & FOCUSABLE) ^ (newFocus & FOCUSABLE); 13241 changed = (changed & ~FOCUSABLE) | focusableChangedByAuto; 13242 } 13243 13244 /* Check if the FOCUSABLE bit has changed */ 13245 if (((changed & FOCUSABLE) != 0) && ((privateFlags & PFLAG_HAS_BOUNDS) != 0)) { 13246 if (((old & FOCUSABLE) == FOCUSABLE) 13247 && ((privateFlags & PFLAG_FOCUSED) != 0)) { 13248 /* Give up focus if we are no longer focusable */ 13249 clearFocus(); 13250 } else if (((old & FOCUSABLE) == NOT_FOCUSABLE) 13251 && ((privateFlags & PFLAG_FOCUSED) == 0)) { 13252 /* 13253 * Tell the view system that we are now available to take focus 13254 * if no one else already has it. 13255 */ 13256 if (mParent != null) { 13257 ViewRootImpl viewRootImpl = getViewRootImpl(); 13258 if (!sAutoFocusableOffUIThreadWontNotifyParents 13259 || focusableChangedByAuto == 0 13260 || viewRootImpl == null 13261 || viewRootImpl.mThread == Thread.currentThread()) { 13262 mParent.focusableViewAvailable(this); 13263 } 13264 } 13265 } 13266 } 13267 13268 final int newVisibility = flags & VISIBILITY_MASK; 13269 if (newVisibility == VISIBLE) { 13270 if ((changed & VISIBILITY_MASK) != 0) { 13271 /* 13272 * If this view is becoming visible, invalidate it in case it changed while 13273 * it was not visible. Marking it drawn ensures that the invalidation will 13274 * go through. 13275 */ 13276 mPrivateFlags |= PFLAG_DRAWN; 13277 invalidate(true); 13278 13279 needGlobalAttributesUpdate(true); 13280 13281 // a view becoming visible is worth notifying the parent 13282 // about in case nothing has focus. even if this specific view 13283 // isn't focusable, it may contain something that is, so let 13284 // the root view try to give this focus if nothing else does. 13285 if ((mParent != null)) { 13286 mParent.focusableViewAvailable(this); 13287 } 13288 } 13289 } 13290 13291 /* Check if the GONE bit has changed */ 13292 if ((changed & GONE) != 0) { 13293 needGlobalAttributesUpdate(false); 13294 requestLayout(); 13295 13296 if (((mViewFlags & VISIBILITY_MASK) == GONE)) { 13297 if (hasFocus()) clearFocus(); 13298 clearAccessibilityFocus(); 13299 destroyDrawingCache(); 13300 if (mParent instanceof View) { 13301 // GONE views noop invalidation, so invalidate the parent 13302 ((View) mParent).invalidate(true); 13303 } 13304 // Mark the view drawn to ensure that it gets invalidated properly the next 13305 // time it is visible and gets invalidated 13306 mPrivateFlags |= PFLAG_DRAWN; 13307 } 13308 if (mAttachInfo != null) { 13309 mAttachInfo.mViewVisibilityChanged = true; 13310 } 13311 } 13312 13313 /* Check if the VISIBLE bit has changed */ 13314 if ((changed & INVISIBLE) != 0) { 13315 needGlobalAttributesUpdate(false); 13316 /* 13317 * If this view is becoming invisible, set the DRAWN flag so that 13318 * the next invalidate() will not be skipped. 13319 */ 13320 mPrivateFlags |= PFLAG_DRAWN; 13321 13322 if (((mViewFlags & VISIBILITY_MASK) == INVISIBLE)) { 13323 // root view becoming invisible shouldn't clear focus and accessibility focus 13324 if (getRootView() != this) { 13325 if (hasFocus()) clearFocus(); 13326 clearAccessibilityFocus(); 13327 } 13328 } 13329 if (mAttachInfo != null) { 13330 mAttachInfo.mViewVisibilityChanged = true; 13331 } 13332 } 13333 13334 if ((changed & VISIBILITY_MASK) != 0) { 13335 // If the view is invisible, cleanup its display list to free up resources 13336 if (newVisibility != VISIBLE && mAttachInfo != null) { 13337 cleanupDraw(); 13338 } 13339 13340 if (mParent instanceof ViewGroup) { 13341 ((ViewGroup) mParent).onChildVisibilityChanged(this, 13342 (changed & VISIBILITY_MASK), newVisibility); 13343 ((View) mParent).invalidate(true); 13344 } else if (mParent != null) { 13345 mParent.invalidateChild(this, null); 13346 } 13347 13348 if (mAttachInfo != null) { 13349 dispatchVisibilityChanged(this, newVisibility); 13350 13351 // Aggregated visibility changes are dispatched to attached views 13352 // in visible windows where the parent is currently shown/drawn 13353 // or the parent is not a ViewGroup (and therefore assumed to be a ViewRoot), 13354 // discounting clipping or overlapping. This makes it a good place 13355 // to change animation states. 13356 if (mParent != null && getWindowVisibility() == VISIBLE && 13357 ((!(mParent instanceof ViewGroup)) || ((ViewGroup) mParent).isShown())) { 13358 dispatchVisibilityAggregated(newVisibility == VISIBLE); 13359 } 13360 notifySubtreeAccessibilityStateChangedIfNeeded(); 13361 } 13362 } 13363 13364 if ((changed & WILL_NOT_CACHE_DRAWING) != 0) { 13365 destroyDrawingCache(); 13366 } 13367 13368 if ((changed & DRAWING_CACHE_ENABLED) != 0) { 13369 destroyDrawingCache(); 13370 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; 13371 invalidateParentCaches(); 13372 } 13373 13374 if ((changed & DRAWING_CACHE_QUALITY_MASK) != 0) { 13375 destroyDrawingCache(); 13376 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; 13377 } 13378 13379 if ((changed & DRAW_MASK) != 0) { 13380 if ((mViewFlags & WILL_NOT_DRAW) != 0) { 13381 if (mBackground != null 13382 || mDefaultFocusHighlight != null 13383 || (mForegroundInfo != null && mForegroundInfo.mDrawable != null)) { 13384 mPrivateFlags &= ~PFLAG_SKIP_DRAW; 13385 } else { 13386 mPrivateFlags |= PFLAG_SKIP_DRAW; 13387 } 13388 } else { 13389 mPrivateFlags &= ~PFLAG_SKIP_DRAW; 13390 } 13391 requestLayout(); 13392 invalidate(true); 13393 } 13394 13395 if ((changed & KEEP_SCREEN_ON) != 0) { 13396 if (mParent != null && mAttachInfo != null && !mAttachInfo.mRecomputeGlobalAttributes) { 13397 mParent.recomputeViewAttributes(this); 13398 } 13399 } 13400 13401 if (accessibilityEnabled) { 13402 if ((changed & FOCUSABLE) != 0 || (changed & VISIBILITY_MASK) != 0 13403 || (changed & CLICKABLE) != 0 || (changed & LONG_CLICKABLE) != 0 13404 || (changed & CONTEXT_CLICKABLE) != 0) { 13405 if (oldIncludeForAccessibility != includeForAccessibility()) { 13406 notifySubtreeAccessibilityStateChangedIfNeeded(); 13407 } else { 13408 notifyViewAccessibilityStateChangedIfNeeded( 13409 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 13410 } 13411 } else if ((changed & ENABLED_MASK) != 0) { 13412 notifyViewAccessibilityStateChangedIfNeeded( 13413 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 13414 } 13415 } 13416 } 13417 13418 /** 13419 * Change the view's z order in the tree, so it's on top of other sibling 13420 * views. This ordering change may affect layout, if the parent container 13421 * uses an order-dependent layout scheme (e.g., LinearLayout). Prior 13422 * to {@link android.os.Build.VERSION_CODES#KITKAT} this 13423 * method should be followed by calls to {@link #requestLayout()} and 13424 * {@link View#invalidate()} on the view's parent to force the parent to redraw 13425 * with the new child ordering. 13426 * 13427 * @see ViewGroup#bringChildToFront(View) 13428 */ 13429 public void bringToFront() { 13430 if (mParent != null) { 13431 mParent.bringChildToFront(this); 13432 } 13433 } 13434 13435 /** 13436 * This is called in response to an internal scroll in this view (i.e., the 13437 * view scrolled its own contents). This is typically as a result of 13438 * {@link #scrollBy(int, int)} or {@link #scrollTo(int, int)} having been 13439 * called. 13440 * 13441 * @param l Current horizontal scroll origin. 13442 * @param t Current vertical scroll origin. 13443 * @param oldl Previous horizontal scroll origin. 13444 * @param oldt Previous vertical scroll origin. 13445 */ 13446 protected void onScrollChanged(int l, int t, int oldl, int oldt) { 13447 notifySubtreeAccessibilityStateChangedIfNeeded(); 13448 13449 if (AccessibilityManager.getInstance(mContext).isEnabled()) { 13450 postSendViewScrolledAccessibilityEventCallback(); 13451 } 13452 13453 mBackgroundSizeChanged = true; 13454 mDefaultFocusHighlightSizeChanged = true; 13455 if (mForegroundInfo != null) { 13456 mForegroundInfo.mBoundsChanged = true; 13457 } 13458 13459 final AttachInfo ai = mAttachInfo; 13460 if (ai != null) { 13461 ai.mViewScrollChanged = true; 13462 } 13463 13464 if (mListenerInfo != null && mListenerInfo.mOnScrollChangeListener != null) { 13465 mListenerInfo.mOnScrollChangeListener.onScrollChange(this, l, t, oldl, oldt); 13466 } 13467 } 13468 13469 /** 13470 * Interface definition for a callback to be invoked when the scroll 13471 * X or Y positions of a view change. 13472 * <p> 13473 * <b>Note:</b> Some views handle scrolling independently from View and may 13474 * have their own separate listeners for scroll-type events. For example, 13475 * {@link android.widget.ListView ListView} allows clients to register an 13476 * {@link android.widget.ListView#setOnScrollListener(android.widget.AbsListView.OnScrollListener) AbsListView.OnScrollListener} 13477 * to listen for changes in list scroll position. 13478 * 13479 * @see #setOnScrollChangeListener(View.OnScrollChangeListener) 13480 */ 13481 public interface OnScrollChangeListener { 13482 /** 13483 * Called when the scroll position of a view changes. 13484 * 13485 * @param v The view whose scroll position has changed. 13486 * @param scrollX Current horizontal scroll origin. 13487 * @param scrollY Current vertical scroll origin. 13488 * @param oldScrollX Previous horizontal scroll origin. 13489 * @param oldScrollY Previous vertical scroll origin. 13490 */ 13491 void onScrollChange(View v, int scrollX, int scrollY, int oldScrollX, int oldScrollY); 13492 } 13493 13494 /** 13495 * Interface definition for a callback to be invoked when the layout bounds of a view 13496 * changes due to layout processing. 13497 */ 13498 public interface OnLayoutChangeListener { 13499 /** 13500 * Called when the layout bounds of a view changes due to layout processing. 13501 * 13502 * @param v The view whose bounds have changed. 13503 * @param left The new value of the view's left property. 13504 * @param top The new value of the view's top property. 13505 * @param right The new value of the view's right property. 13506 * @param bottom The new value of the view's bottom property. 13507 * @param oldLeft The previous value of the view's left property. 13508 * @param oldTop The previous value of the view's top property. 13509 * @param oldRight The previous value of the view's right property. 13510 * @param oldBottom The previous value of the view's bottom property. 13511 */ 13512 void onLayoutChange(View v, int left, int top, int right, int bottom, 13513 int oldLeft, int oldTop, int oldRight, int oldBottom); 13514 } 13515 13516 /** 13517 * This is called during layout when the size of this view has changed. If 13518 * you were just added to the view hierarchy, you're called with the old 13519 * values of 0. 13520 * 13521 * @param w Current width of this view. 13522 * @param h Current height of this view. 13523 * @param oldw Old width of this view. 13524 * @param oldh Old height of this view. 13525 */ 13526 protected void onSizeChanged(int w, int h, int oldw, int oldh) { 13527 } 13528 13529 /** 13530 * Called by draw to draw the child views. This may be overridden 13531 * by derived classes to gain control just before its children are drawn 13532 * (but after its own view has been drawn). 13533 * @param canvas the canvas on which to draw the view 13534 */ 13535 protected void dispatchDraw(Canvas canvas) { 13536 13537 } 13538 13539 /** 13540 * Gets the parent of this view. Note that the parent is a 13541 * ViewParent and not necessarily a View. 13542 * 13543 * @return Parent of this view. 13544 */ 13545 public final ViewParent getParent() { 13546 return mParent; 13547 } 13548 13549 /** 13550 * Set the horizontal scrolled position of your view. This will cause a call to 13551 * {@link #onScrollChanged(int, int, int, int)} and the view will be 13552 * invalidated. 13553 * @param value the x position to scroll to 13554 */ 13555 public void setScrollX(int value) { 13556 scrollTo(value, mScrollY); 13557 } 13558 13559 /** 13560 * Set the vertical scrolled position of your view. This will cause a call to 13561 * {@link #onScrollChanged(int, int, int, int)} and the view will be 13562 * invalidated. 13563 * @param value the y position to scroll to 13564 */ 13565 public void setScrollY(int value) { 13566 scrollTo(mScrollX, value); 13567 } 13568 13569 /** 13570 * Return the scrolled left position of this view. This is the left edge of 13571 * the displayed part of your view. You do not need to draw any pixels 13572 * farther left, since those are outside of the frame of your view on 13573 * screen. 13574 * 13575 * @return The left edge of the displayed part of your view, in pixels. 13576 */ 13577 public final int getScrollX() { 13578 return mScrollX; 13579 } 13580 13581 /** 13582 * Return the scrolled top position of this view. This is the top edge of 13583 * the displayed part of your view. You do not need to draw any pixels above 13584 * it, since those are outside of the frame of your view on screen. 13585 * 13586 * @return The top edge of the displayed part of your view, in pixels. 13587 */ 13588 public final int getScrollY() { 13589 return mScrollY; 13590 } 13591 13592 /** 13593 * Return the width of the your view. 13594 * 13595 * @return The width of your view, in pixels. 13596 */ 13597 @ViewDebug.ExportedProperty(category = "layout") 13598 public final int getWidth() { 13599 return mRight - mLeft; 13600 } 13601 13602 /** 13603 * Return the height of your view. 13604 * 13605 * @return The height of your view, in pixels. 13606 */ 13607 @ViewDebug.ExportedProperty(category = "layout") 13608 public final int getHeight() { 13609 return mBottom - mTop; 13610 } 13611 13612 /** 13613 * Return the visible drawing bounds of your view. Fills in the output 13614 * rectangle with the values from getScrollX(), getScrollY(), 13615 * getWidth(), and getHeight(). These bounds do not account for any 13616 * transformation properties currently set on the view, such as 13617 * {@link #setScaleX(float)} or {@link #setRotation(float)}. 13618 * 13619 * @param outRect The (scrolled) drawing bounds of the view. 13620 */ 13621 public void getDrawingRect(Rect outRect) { 13622 outRect.left = mScrollX; 13623 outRect.top = mScrollY; 13624 outRect.right = mScrollX + (mRight - mLeft); 13625 outRect.bottom = mScrollY + (mBottom - mTop); 13626 } 13627 13628 /** 13629 * Like {@link #getMeasuredWidthAndState()}, but only returns the 13630 * raw width component (that is the result is masked by 13631 * {@link #MEASURED_SIZE_MASK}). 13632 * 13633 * @return The raw measured width of this view. 13634 */ 13635 public final int getMeasuredWidth() { 13636 return mMeasuredWidth & MEASURED_SIZE_MASK; 13637 } 13638 13639 /** 13640 * Return the full width measurement information for this view as computed 13641 * by the most recent call to {@link #measure(int, int)}. This result is a bit mask 13642 * as defined by {@link #MEASURED_SIZE_MASK} and {@link #MEASURED_STATE_TOO_SMALL}. 13643 * This should be used during measurement and layout calculations only. Use 13644 * {@link #getWidth()} to see how wide a view is after layout. 13645 * 13646 * @return The measured width of this view as a bit mask. 13647 */ 13648 @ViewDebug.ExportedProperty(category = "measurement", flagMapping = { 13649 @ViewDebug.FlagToString(mask = MEASURED_STATE_MASK, equals = MEASURED_STATE_TOO_SMALL, 13650 name = "MEASURED_STATE_TOO_SMALL"), 13651 }) 13652 public final int getMeasuredWidthAndState() { 13653 return mMeasuredWidth; 13654 } 13655 13656 /** 13657 * Like {@link #getMeasuredHeightAndState()}, but only returns the 13658 * raw height component (that is the result is masked by 13659 * {@link #MEASURED_SIZE_MASK}). 13660 * 13661 * @return The raw measured height of this view. 13662 */ 13663 public final int getMeasuredHeight() { 13664 return mMeasuredHeight & MEASURED_SIZE_MASK; 13665 } 13666 13667 /** 13668 * Return the full height measurement information for this view as computed 13669 * by the most recent call to {@link #measure(int, int)}. This result is a bit mask 13670 * as defined by {@link #MEASURED_SIZE_MASK} and {@link #MEASURED_STATE_TOO_SMALL}. 13671 * This should be used during measurement and layout calculations only. Use 13672 * {@link #getHeight()} to see how wide a view is after layout. 13673 * 13674 * @return The measured height of this view as a bit mask. 13675 */ 13676 @ViewDebug.ExportedProperty(category = "measurement", flagMapping = { 13677 @ViewDebug.FlagToString(mask = MEASURED_STATE_MASK, equals = MEASURED_STATE_TOO_SMALL, 13678 name = "MEASURED_STATE_TOO_SMALL"), 13679 }) 13680 public final int getMeasuredHeightAndState() { 13681 return mMeasuredHeight; 13682 } 13683 13684 /** 13685 * Return only the state bits of {@link #getMeasuredWidthAndState()} 13686 * and {@link #getMeasuredHeightAndState()}, combined into one integer. 13687 * The width component is in the regular bits {@link #MEASURED_STATE_MASK} 13688 * and the height component is at the shifted bits 13689 * {@link #MEASURED_HEIGHT_STATE_SHIFT}>>{@link #MEASURED_STATE_MASK}. 13690 */ 13691 public final int getMeasuredState() { 13692 return (mMeasuredWidth&MEASURED_STATE_MASK) 13693 | ((mMeasuredHeight>>MEASURED_HEIGHT_STATE_SHIFT) 13694 & (MEASURED_STATE_MASK>>MEASURED_HEIGHT_STATE_SHIFT)); 13695 } 13696 13697 /** 13698 * The transform matrix of this view, which is calculated based on the current 13699 * rotation, scale, and pivot properties. 13700 * 13701 * @see #getRotation() 13702 * @see #getScaleX() 13703 * @see #getScaleY() 13704 * @see #getPivotX() 13705 * @see #getPivotY() 13706 * @return The current transform matrix for the view 13707 */ 13708 public Matrix getMatrix() { 13709 ensureTransformationInfo(); 13710 final Matrix matrix = mTransformationInfo.mMatrix; 13711 mRenderNode.getMatrix(matrix); 13712 return matrix; 13713 } 13714 13715 /** 13716 * Returns true if the transform matrix is the identity matrix. 13717 * Recomputes the matrix if necessary. 13718 * 13719 * @return True if the transform matrix is the identity matrix, false otherwise. 13720 */ 13721 final boolean hasIdentityMatrix() { 13722 return mRenderNode.hasIdentityMatrix(); 13723 } 13724 13725 void ensureTransformationInfo() { 13726 if (mTransformationInfo == null) { 13727 mTransformationInfo = new TransformationInfo(); 13728 } 13729 } 13730 13731 /** 13732 * Utility method to retrieve the inverse of the current mMatrix property. 13733 * We cache the matrix to avoid recalculating it when transform properties 13734 * have not changed. 13735 * 13736 * @return The inverse of the current matrix of this view. 13737 * @hide 13738 */ 13739 public final Matrix getInverseMatrix() { 13740 ensureTransformationInfo(); 13741 if (mTransformationInfo.mInverseMatrix == null) { 13742 mTransformationInfo.mInverseMatrix = new Matrix(); 13743 } 13744 final Matrix matrix = mTransformationInfo.mInverseMatrix; 13745 mRenderNode.getInverseMatrix(matrix); 13746 return matrix; 13747 } 13748 13749 /** 13750 * Gets the distance along the Z axis from the camera to this view. 13751 * 13752 * @see #setCameraDistance(float) 13753 * 13754 * @return The distance along the Z axis. 13755 */ 13756 public float getCameraDistance() { 13757 final float dpi = mResources.getDisplayMetrics().densityDpi; 13758 return -(mRenderNode.getCameraDistance() * dpi); 13759 } 13760 13761 /** 13762 * <p>Sets the distance along the Z axis (orthogonal to the X/Y plane on which 13763 * views are drawn) from the camera to this view. The camera's distance 13764 * affects 3D transformations, for instance rotations around the X and Y 13765 * axis. If the rotationX or rotationY properties are changed and this view is 13766 * large (more than half the size of the screen), it is recommended to always 13767 * use a camera distance that's greater than the height (X axis rotation) or 13768 * the width (Y axis rotation) of this view.</p> 13769 * 13770 * <p>The distance of the camera from the view plane can have an affect on the 13771 * perspective distortion of the view when it is rotated around the x or y axis. 13772 * For example, a large distance will result in a large viewing angle, and there 13773 * will not be much perspective distortion of the view as it rotates. A short 13774 * distance may cause much more perspective distortion upon rotation, and can 13775 * also result in some drawing artifacts if the rotated view ends up partially 13776 * behind the camera (which is why the recommendation is to use a distance at 13777 * least as far as the size of the view, if the view is to be rotated.)</p> 13778 * 13779 * <p>The distance is expressed in "depth pixels." The default distance depends 13780 * on the screen density. For instance, on a medium density display, the 13781 * default distance is 1280. On a high density display, the default distance 13782 * is 1920.</p> 13783 * 13784 * <p>If you want to specify a distance that leads to visually consistent 13785 * results across various densities, use the following formula:</p> 13786 * <pre> 13787 * float scale = context.getResources().getDisplayMetrics().density; 13788 * view.setCameraDistance(distance * scale); 13789 * </pre> 13790 * 13791 * <p>The density scale factor of a high density display is 1.5, 13792 * and 1920 = 1280 * 1.5.</p> 13793 * 13794 * @param distance The distance in "depth pixels", if negative the opposite 13795 * value is used 13796 * 13797 * @see #setRotationX(float) 13798 * @see #setRotationY(float) 13799 */ 13800 public void setCameraDistance(float distance) { 13801 final float dpi = mResources.getDisplayMetrics().densityDpi; 13802 13803 invalidateViewProperty(true, false); 13804 mRenderNode.setCameraDistance(-Math.abs(distance) / dpi); 13805 invalidateViewProperty(false, false); 13806 13807 invalidateParentIfNeededAndWasQuickRejected(); 13808 } 13809 13810 /** 13811 * The degrees that the view is rotated around the pivot point. 13812 * 13813 * @see #setRotation(float) 13814 * @see #getPivotX() 13815 * @see #getPivotY() 13816 * 13817 * @return The degrees of rotation. 13818 */ 13819 @ViewDebug.ExportedProperty(category = "drawing") 13820 public float getRotation() { 13821 return mRenderNode.getRotation(); 13822 } 13823 13824 /** 13825 * Sets the degrees that the view is rotated around the pivot point. Increasing values 13826 * result in clockwise rotation. 13827 * 13828 * @param rotation The degrees of rotation. 13829 * 13830 * @see #getRotation() 13831 * @see #getPivotX() 13832 * @see #getPivotY() 13833 * @see #setRotationX(float) 13834 * @see #setRotationY(float) 13835 * 13836 * @attr ref android.R.styleable#View_rotation 13837 */ 13838 public void setRotation(float rotation) { 13839 if (rotation != getRotation()) { 13840 // Double-invalidation is necessary to capture view's old and new areas 13841 invalidateViewProperty(true, false); 13842 mRenderNode.setRotation(rotation); 13843 invalidateViewProperty(false, true); 13844 13845 invalidateParentIfNeededAndWasQuickRejected(); 13846 notifySubtreeAccessibilityStateChangedIfNeeded(); 13847 } 13848 } 13849 13850 /** 13851 * The degrees that the view is rotated around the vertical axis through the pivot point. 13852 * 13853 * @see #getPivotX() 13854 * @see #getPivotY() 13855 * @see #setRotationY(float) 13856 * 13857 * @return The degrees of Y rotation. 13858 */ 13859 @ViewDebug.ExportedProperty(category = "drawing") 13860 public float getRotationY() { 13861 return mRenderNode.getRotationY(); 13862 } 13863 13864 /** 13865 * Sets the degrees that the view is rotated around the vertical axis through the pivot point. 13866 * Increasing values result in counter-clockwise rotation from the viewpoint of looking 13867 * down the y axis. 13868 * 13869 * When rotating large views, it is recommended to adjust the camera distance 13870 * accordingly. Refer to {@link #setCameraDistance(float)} for more information. 13871 * 13872 * @param rotationY The degrees of Y rotation. 13873 * 13874 * @see #getRotationY() 13875 * @see #getPivotX() 13876 * @see #getPivotY() 13877 * @see #setRotation(float) 13878 * @see #setRotationX(float) 13879 * @see #setCameraDistance(float) 13880 * 13881 * @attr ref android.R.styleable#View_rotationY 13882 */ 13883 public void setRotationY(float rotationY) { 13884 if (rotationY != getRotationY()) { 13885 invalidateViewProperty(true, false); 13886 mRenderNode.setRotationY(rotationY); 13887 invalidateViewProperty(false, true); 13888 13889 invalidateParentIfNeededAndWasQuickRejected(); 13890 notifySubtreeAccessibilityStateChangedIfNeeded(); 13891 } 13892 } 13893 13894 /** 13895 * The degrees that the view is rotated around the horizontal axis through the pivot point. 13896 * 13897 * @see #getPivotX() 13898 * @see #getPivotY() 13899 * @see #setRotationX(float) 13900 * 13901 * @return The degrees of X rotation. 13902 */ 13903 @ViewDebug.ExportedProperty(category = "drawing") 13904 public float getRotationX() { 13905 return mRenderNode.getRotationX(); 13906 } 13907 13908 /** 13909 * Sets the degrees that the view is rotated around the horizontal axis through the pivot point. 13910 * Increasing values result in clockwise rotation from the viewpoint of looking down the 13911 * x axis. 13912 * 13913 * When rotating large views, it is recommended to adjust the camera distance 13914 * accordingly. Refer to {@link #setCameraDistance(float)} for more information. 13915 * 13916 * @param rotationX The degrees of X rotation. 13917 * 13918 * @see #getRotationX() 13919 * @see #getPivotX() 13920 * @see #getPivotY() 13921 * @see #setRotation(float) 13922 * @see #setRotationY(float) 13923 * @see #setCameraDistance(float) 13924 * 13925 * @attr ref android.R.styleable#View_rotationX 13926 */ 13927 public void setRotationX(float rotationX) { 13928 if (rotationX != getRotationX()) { 13929 invalidateViewProperty(true, false); 13930 mRenderNode.setRotationX(rotationX); 13931 invalidateViewProperty(false, true); 13932 13933 invalidateParentIfNeededAndWasQuickRejected(); 13934 notifySubtreeAccessibilityStateChangedIfNeeded(); 13935 } 13936 } 13937 13938 /** 13939 * The amount that the view is scaled in x around the pivot point, as a proportion of 13940 * the view's unscaled width. A value of 1, the default, means that no scaling is applied. 13941 * 13942 * <p>By default, this is 1.0f. 13943 * 13944 * @see #getPivotX() 13945 * @see #getPivotY() 13946 * @return The scaling factor. 13947 */ 13948 @ViewDebug.ExportedProperty(category = "drawing") 13949 public float getScaleX() { 13950 return mRenderNode.getScaleX(); 13951 } 13952 13953 /** 13954 * Sets the amount that the view is scaled in x around the pivot point, as a proportion of 13955 * the view's unscaled width. A value of 1 means that no scaling is applied. 13956 * 13957 * @param scaleX The scaling factor. 13958 * @see #getPivotX() 13959 * @see #getPivotY() 13960 * 13961 * @attr ref android.R.styleable#View_scaleX 13962 */ 13963 public void setScaleX(float scaleX) { 13964 if (scaleX != getScaleX()) { 13965 invalidateViewProperty(true, false); 13966 mRenderNode.setScaleX(scaleX); 13967 invalidateViewProperty(false, true); 13968 13969 invalidateParentIfNeededAndWasQuickRejected(); 13970 notifySubtreeAccessibilityStateChangedIfNeeded(); 13971 } 13972 } 13973 13974 /** 13975 * The amount that the view is scaled in y around the pivot point, as a proportion of 13976 * the view's unscaled height. A value of 1, the default, means that no scaling is applied. 13977 * 13978 * <p>By default, this is 1.0f. 13979 * 13980 * @see #getPivotX() 13981 * @see #getPivotY() 13982 * @return The scaling factor. 13983 */ 13984 @ViewDebug.ExportedProperty(category = "drawing") 13985 public float getScaleY() { 13986 return mRenderNode.getScaleY(); 13987 } 13988 13989 /** 13990 * Sets the amount that the view is scaled in Y around the pivot point, as a proportion of 13991 * the view's unscaled width. A value of 1 means that no scaling is applied. 13992 * 13993 * @param scaleY The scaling factor. 13994 * @see #getPivotX() 13995 * @see #getPivotY() 13996 * 13997 * @attr ref android.R.styleable#View_scaleY 13998 */ 13999 public void setScaleY(float scaleY) { 14000 if (scaleY != getScaleY()) { 14001 invalidateViewProperty(true, false); 14002 mRenderNode.setScaleY(scaleY); 14003 invalidateViewProperty(false, true); 14004 14005 invalidateParentIfNeededAndWasQuickRejected(); 14006 notifySubtreeAccessibilityStateChangedIfNeeded(); 14007 } 14008 } 14009 14010 /** 14011 * The x location of the point around which the view is {@link #setRotation(float) rotated} 14012 * and {@link #setScaleX(float) scaled}. 14013 * 14014 * @see #getRotation() 14015 * @see #getScaleX() 14016 * @see #getScaleY() 14017 * @see #getPivotY() 14018 * @return The x location of the pivot point. 14019 * 14020 * @attr ref android.R.styleable#View_transformPivotX 14021 */ 14022 @ViewDebug.ExportedProperty(category = "drawing") 14023 public float getPivotX() { 14024 return mRenderNode.getPivotX(); 14025 } 14026 14027 /** 14028 * Sets the x location of the point around which the view is 14029 * {@link #setRotation(float) rotated} and {@link #setScaleX(float) scaled}. 14030 * By default, the pivot point is centered on the object. 14031 * Setting this property disables this behavior and causes the view to use only the 14032 * explicitly set pivotX and pivotY values. 14033 * 14034 * @param pivotX The x location of the pivot point. 14035 * @see #getRotation() 14036 * @see #getScaleX() 14037 * @see #getScaleY() 14038 * @see #getPivotY() 14039 * 14040 * @attr ref android.R.styleable#View_transformPivotX 14041 */ 14042 public void setPivotX(float pivotX) { 14043 if (!mRenderNode.isPivotExplicitlySet() || pivotX != getPivotX()) { 14044 invalidateViewProperty(true, false); 14045 mRenderNode.setPivotX(pivotX); 14046 invalidateViewProperty(false, true); 14047 14048 invalidateParentIfNeededAndWasQuickRejected(); 14049 } 14050 } 14051 14052 /** 14053 * The y location of the point around which the view is {@link #setRotation(float) rotated} 14054 * and {@link #setScaleY(float) scaled}. 14055 * 14056 * @see #getRotation() 14057 * @see #getScaleX() 14058 * @see #getScaleY() 14059 * @see #getPivotY() 14060 * @return The y location of the pivot point. 14061 * 14062 * @attr ref android.R.styleable#View_transformPivotY 14063 */ 14064 @ViewDebug.ExportedProperty(category = "drawing") 14065 public float getPivotY() { 14066 return mRenderNode.getPivotY(); 14067 } 14068 14069 /** 14070 * Sets the y location of the point around which the view is {@link #setRotation(float) rotated} 14071 * and {@link #setScaleY(float) scaled}. By default, the pivot point is centered on the object. 14072 * Setting this property disables this behavior and causes the view to use only the 14073 * explicitly set pivotX and pivotY values. 14074 * 14075 * @param pivotY The y location of the pivot point. 14076 * @see #getRotation() 14077 * @see #getScaleX() 14078 * @see #getScaleY() 14079 * @see #getPivotY() 14080 * 14081 * @attr ref android.R.styleable#View_transformPivotY 14082 */ 14083 public void setPivotY(float pivotY) { 14084 if (!mRenderNode.isPivotExplicitlySet() || pivotY != getPivotY()) { 14085 invalidateViewProperty(true, false); 14086 mRenderNode.setPivotY(pivotY); 14087 invalidateViewProperty(false, true); 14088 14089 invalidateParentIfNeededAndWasQuickRejected(); 14090 } 14091 } 14092 14093 /** 14094 * The opacity of the view. This is a value from 0 to 1, where 0 means the view is 14095 * completely transparent and 1 means the view is completely opaque. 14096 * 14097 * <p>By default this is 1.0f. 14098 * @return The opacity of the view. 14099 */ 14100 @ViewDebug.ExportedProperty(category = "drawing") 14101 public float getAlpha() { 14102 return mTransformationInfo != null ? mTransformationInfo.mAlpha : 1; 14103 } 14104 14105 /** 14106 * Sets the behavior for overlapping rendering for this view (see {@link 14107 * #hasOverlappingRendering()} for more details on this behavior). Calling this method 14108 * is an alternative to overriding {@link #hasOverlappingRendering()} in a subclass, 14109 * providing the value which is then used internally. That is, when {@link 14110 * #forceHasOverlappingRendering(boolean)} is called, the value of {@link 14111 * #hasOverlappingRendering()} is ignored and the value passed into this method is used 14112 * instead. 14113 * 14114 * @param hasOverlappingRendering The value for overlapping rendering to be used internally 14115 * instead of that returned by {@link #hasOverlappingRendering()}. 14116 * 14117 * @attr ref android.R.styleable#View_forceHasOverlappingRendering 14118 */ 14119 public void forceHasOverlappingRendering(boolean hasOverlappingRendering) { 14120 mPrivateFlags3 |= PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED; 14121 if (hasOverlappingRendering) { 14122 mPrivateFlags3 |= PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE; 14123 } else { 14124 mPrivateFlags3 &= ~PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE; 14125 } 14126 } 14127 14128 /** 14129 * Returns the value for overlapping rendering that is used internally. This is either 14130 * the value passed into {@link #forceHasOverlappingRendering(boolean)}, if called, or 14131 * the return value of {@link #hasOverlappingRendering()}, otherwise. 14132 * 14133 * @return The value for overlapping rendering being used internally. 14134 */ 14135 public final boolean getHasOverlappingRendering() { 14136 return (mPrivateFlags3 & PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED) != 0 ? 14137 (mPrivateFlags3 & PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE) != 0 : 14138 hasOverlappingRendering(); 14139 } 14140 14141 /** 14142 * Returns whether this View has content which overlaps. 14143 * 14144 * <p>This function, intended to be overridden by specific View types, is an optimization when 14145 * alpha is set on a view. If rendering overlaps in a view with alpha < 1, that view is drawn to 14146 * an offscreen buffer and then composited into place, which can be expensive. If the view has 14147 * no overlapping rendering, the view can draw each primitive with the appropriate alpha value 14148 * directly. An example of overlapping rendering is a TextView with a background image, such as 14149 * a Button. An example of non-overlapping rendering is a TextView with no background, or an 14150 * ImageView with only the foreground image. The default implementation returns true; subclasses 14151 * should override if they have cases which can be optimized.</p> 14152 * 14153 * <p>The current implementation of the saveLayer and saveLayerAlpha methods in {@link Canvas} 14154 * necessitates that a View return true if it uses the methods internally without passing the 14155 * {@link Canvas#CLIP_TO_LAYER_SAVE_FLAG}.</p> 14156 * 14157 * <p><strong>Note:</strong> The return value of this method is ignored if {@link 14158 * #forceHasOverlappingRendering(boolean)} has been called on this view.</p> 14159 * 14160 * @return true if the content in this view might overlap, false otherwise. 14161 */ 14162 @ViewDebug.ExportedProperty(category = "drawing") 14163 public boolean hasOverlappingRendering() { 14164 return true; 14165 } 14166 14167 /** 14168 * Sets the opacity of the view to a value from 0 to 1, where 0 means the view is 14169 * completely transparent and 1 means the view is completely opaque. 14170 * 14171 * <p class="note"><strong>Note:</strong> setting alpha to a translucent value (0 < alpha < 1) 14172 * can have significant performance implications, especially for large views. It is best to use 14173 * the alpha property sparingly and transiently, as in the case of fading animations.</p> 14174 * 14175 * <p>For a view with a frequently changing alpha, such as during a fading animation, it is 14176 * strongly recommended for performance reasons to either override 14177 * {@link #hasOverlappingRendering()} to return <code>false</code> if appropriate, or setting a 14178 * {@link #setLayerType(int, android.graphics.Paint) layer type} on the view for the duration 14179 * of the animation. On versions {@link android.os.Build.VERSION_CODES#M} and below, 14180 * the default path for rendering an unlayered View with alpha could add multiple milliseconds 14181 * of rendering cost, even for simple or small views. Starting with 14182 * {@link android.os.Build.VERSION_CODES#M}, {@link #LAYER_TYPE_HARDWARE} is automatically 14183 * applied to the view at the rendering level.</p> 14184 * 14185 * <p>If this view overrides {@link #onSetAlpha(int)} to return true, then this view is 14186 * responsible for applying the opacity itself.</p> 14187 * 14188 * <p>On versions {@link android.os.Build.VERSION_CODES#LOLLIPOP_MR1} and below, note that if 14189 * the view is backed by a {@link #setLayerType(int, android.graphics.Paint) layer} and is 14190 * associated with a {@link #setLayerPaint(android.graphics.Paint) layer paint}, setting an 14191 * alpha value less than 1.0 will supersede the alpha of the layer paint.</p> 14192 * 14193 * <p>Starting with {@link android.os.Build.VERSION_CODES#M}, setting a translucent alpha 14194 * value will clip a View to its bounds, unless the View returns <code>false</code> from 14195 * {@link #hasOverlappingRendering}.</p> 14196 * 14197 * @param alpha The opacity of the view. 14198 * 14199 * @see #hasOverlappingRendering() 14200 * @see #setLayerType(int, android.graphics.Paint) 14201 * 14202 * @attr ref android.R.styleable#View_alpha 14203 */ 14204 public void setAlpha(@FloatRange(from=0.0, to=1.0) float alpha) { 14205 ensureTransformationInfo(); 14206 if (mTransformationInfo.mAlpha != alpha) { 14207 // Report visibility changes, which can affect children, to accessibility 14208 if ((alpha == 0) ^ (mTransformationInfo.mAlpha == 0)) { 14209 notifySubtreeAccessibilityStateChangedIfNeeded(); 14210 } 14211 mTransformationInfo.mAlpha = alpha; 14212 if (onSetAlpha((int) (alpha * 255))) { 14213 mPrivateFlags |= PFLAG_ALPHA_SET; 14214 // subclass is handling alpha - don't optimize rendering cache invalidation 14215 invalidateParentCaches(); 14216 invalidate(true); 14217 } else { 14218 mPrivateFlags &= ~PFLAG_ALPHA_SET; 14219 invalidateViewProperty(true, false); 14220 mRenderNode.setAlpha(getFinalAlpha()); 14221 } 14222 } 14223 } 14224 14225 /** 14226 * Faster version of setAlpha() which performs the same steps except there are 14227 * no calls to invalidate(). The caller of this function should perform proper invalidation 14228 * on the parent and this object. The return value indicates whether the subclass handles 14229 * alpha (the return value for onSetAlpha()). 14230 * 14231 * @param alpha The new value for the alpha property 14232 * @return true if the View subclass handles alpha (the return value for onSetAlpha()) and 14233 * the new value for the alpha property is different from the old value 14234 */ 14235 boolean setAlphaNoInvalidation(float alpha) { 14236 ensureTransformationInfo(); 14237 if (mTransformationInfo.mAlpha != alpha) { 14238 mTransformationInfo.mAlpha = alpha; 14239 boolean subclassHandlesAlpha = onSetAlpha((int) (alpha * 255)); 14240 if (subclassHandlesAlpha) { 14241 mPrivateFlags |= PFLAG_ALPHA_SET; 14242 return true; 14243 } else { 14244 mPrivateFlags &= ~PFLAG_ALPHA_SET; 14245 mRenderNode.setAlpha(getFinalAlpha()); 14246 } 14247 } 14248 return false; 14249 } 14250 14251 /** 14252 * This property is hidden and intended only for use by the Fade transition, which 14253 * animates it to produce a visual translucency that does not side-effect (or get 14254 * affected by) the real alpha property. This value is composited with the other 14255 * alpha value (and the AlphaAnimation value, when that is present) to produce 14256 * a final visual translucency result, which is what is passed into the DisplayList. 14257 * 14258 * @hide 14259 */ 14260 public void setTransitionAlpha(float alpha) { 14261 ensureTransformationInfo(); 14262 if (mTransformationInfo.mTransitionAlpha != alpha) { 14263 mTransformationInfo.mTransitionAlpha = alpha; 14264 mPrivateFlags &= ~PFLAG_ALPHA_SET; 14265 invalidateViewProperty(true, false); 14266 mRenderNode.setAlpha(getFinalAlpha()); 14267 } 14268 } 14269 14270 /** 14271 * Calculates the visual alpha of this view, which is a combination of the actual 14272 * alpha value and the transitionAlpha value (if set). 14273 */ 14274 private float getFinalAlpha() { 14275 if (mTransformationInfo != null) { 14276 return mTransformationInfo.mAlpha * mTransformationInfo.mTransitionAlpha; 14277 } 14278 return 1; 14279 } 14280 14281 /** 14282 * This property is hidden and intended only for use by the Fade transition, which 14283 * animates it to produce a visual translucency that does not side-effect (or get 14284 * affected by) the real alpha property. This value is composited with the other 14285 * alpha value (and the AlphaAnimation value, when that is present) to produce 14286 * a final visual translucency result, which is what is passed into the DisplayList. 14287 * 14288 * @hide 14289 */ 14290 @ViewDebug.ExportedProperty(category = "drawing") 14291 public float getTransitionAlpha() { 14292 return mTransformationInfo != null ? mTransformationInfo.mTransitionAlpha : 1; 14293 } 14294 14295 /** 14296 * Top position of this view relative to its parent. 14297 * 14298 * @return The top of this view, in pixels. 14299 */ 14300 @ViewDebug.CapturedViewProperty 14301 public final int getTop() { 14302 return mTop; 14303 } 14304 14305 /** 14306 * Sets the top position of this view relative to its parent. This method is meant to be called 14307 * by the layout system and should not generally be called otherwise, because the property 14308 * may be changed at any time by the layout. 14309 * 14310 * @param top The top of this view, in pixels. 14311 */ 14312 public final void setTop(int top) { 14313 if (top != mTop) { 14314 final boolean matrixIsIdentity = hasIdentityMatrix(); 14315 if (matrixIsIdentity) { 14316 if (mAttachInfo != null) { 14317 int minTop; 14318 int yLoc; 14319 if (top < mTop) { 14320 minTop = top; 14321 yLoc = top - mTop; 14322 } else { 14323 minTop = mTop; 14324 yLoc = 0; 14325 } 14326 invalidate(0, yLoc, mRight - mLeft, mBottom - minTop); 14327 } 14328 } else { 14329 // Double-invalidation is necessary to capture view's old and new areas 14330 invalidate(true); 14331 } 14332 14333 int width = mRight - mLeft; 14334 int oldHeight = mBottom - mTop; 14335 14336 mTop = top; 14337 mRenderNode.setTop(mTop); 14338 14339 sizeChange(width, mBottom - mTop, width, oldHeight); 14340 14341 if (!matrixIsIdentity) { 14342 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 14343 invalidate(true); 14344 } 14345 mBackgroundSizeChanged = true; 14346 mDefaultFocusHighlightSizeChanged = true; 14347 if (mForegroundInfo != null) { 14348 mForegroundInfo.mBoundsChanged = true; 14349 } 14350 invalidateParentIfNeeded(); 14351 if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) { 14352 // View was rejected last time it was drawn by its parent; this may have changed 14353 invalidateParentIfNeeded(); 14354 } 14355 } 14356 } 14357 14358 /** 14359 * Bottom position of this view relative to its parent. 14360 * 14361 * @return The bottom of this view, in pixels. 14362 */ 14363 @ViewDebug.CapturedViewProperty 14364 public final int getBottom() { 14365 return mBottom; 14366 } 14367 14368 /** 14369 * True if this view has changed since the last time being drawn. 14370 * 14371 * @return The dirty state of this view. 14372 */ 14373 public boolean isDirty() { 14374 return (mPrivateFlags & PFLAG_DIRTY_MASK) != 0; 14375 } 14376 14377 /** 14378 * Sets the bottom position of this view relative to its parent. This method is meant to be 14379 * called by the layout system and should not generally be called otherwise, because the 14380 * property may be changed at any time by the layout. 14381 * 14382 * @param bottom The bottom of this view, in pixels. 14383 */ 14384 public final void setBottom(int bottom) { 14385 if (bottom != mBottom) { 14386 final boolean matrixIsIdentity = hasIdentityMatrix(); 14387 if (matrixIsIdentity) { 14388 if (mAttachInfo != null) { 14389 int maxBottom; 14390 if (bottom < mBottom) { 14391 maxBottom = mBottom; 14392 } else { 14393 maxBottom = bottom; 14394 } 14395 invalidate(0, 0, mRight - mLeft, maxBottom - mTop); 14396 } 14397 } else { 14398 // Double-invalidation is necessary to capture view's old and new areas 14399 invalidate(true); 14400 } 14401 14402 int width = mRight - mLeft; 14403 int oldHeight = mBottom - mTop; 14404 14405 mBottom = bottom; 14406 mRenderNode.setBottom(mBottom); 14407 14408 sizeChange(width, mBottom - mTop, width, oldHeight); 14409 14410 if (!matrixIsIdentity) { 14411 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 14412 invalidate(true); 14413 } 14414 mBackgroundSizeChanged = true; 14415 mDefaultFocusHighlightSizeChanged = true; 14416 if (mForegroundInfo != null) { 14417 mForegroundInfo.mBoundsChanged = true; 14418 } 14419 invalidateParentIfNeeded(); 14420 if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) { 14421 // View was rejected last time it was drawn by its parent; this may have changed 14422 invalidateParentIfNeeded(); 14423 } 14424 } 14425 } 14426 14427 /** 14428 * Left position of this view relative to its parent. 14429 * 14430 * @return The left edge of this view, in pixels. 14431 */ 14432 @ViewDebug.CapturedViewProperty 14433 public final int getLeft() { 14434 return mLeft; 14435 } 14436 14437 /** 14438 * Sets the left position of this view relative to its parent. This method is meant to be called 14439 * by the layout system and should not generally be called otherwise, because the property 14440 * may be changed at any time by the layout. 14441 * 14442 * @param left The left of this view, in pixels. 14443 */ 14444 public final void setLeft(int left) { 14445 if (left != mLeft) { 14446 final boolean matrixIsIdentity = hasIdentityMatrix(); 14447 if (matrixIsIdentity) { 14448 if (mAttachInfo != null) { 14449 int minLeft; 14450 int xLoc; 14451 if (left < mLeft) { 14452 minLeft = left; 14453 xLoc = left - mLeft; 14454 } else { 14455 minLeft = mLeft; 14456 xLoc = 0; 14457 } 14458 invalidate(xLoc, 0, mRight - minLeft, mBottom - mTop); 14459 } 14460 } else { 14461 // Double-invalidation is necessary to capture view's old and new areas 14462 invalidate(true); 14463 } 14464 14465 int oldWidth = mRight - mLeft; 14466 int height = mBottom - mTop; 14467 14468 mLeft = left; 14469 mRenderNode.setLeft(left); 14470 14471 sizeChange(mRight - mLeft, height, oldWidth, height); 14472 14473 if (!matrixIsIdentity) { 14474 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 14475 invalidate(true); 14476 } 14477 mBackgroundSizeChanged = true; 14478 mDefaultFocusHighlightSizeChanged = true; 14479 if (mForegroundInfo != null) { 14480 mForegroundInfo.mBoundsChanged = true; 14481 } 14482 invalidateParentIfNeeded(); 14483 if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) { 14484 // View was rejected last time it was drawn by its parent; this may have changed 14485 invalidateParentIfNeeded(); 14486 } 14487 } 14488 } 14489 14490 /** 14491 * Right position of this view relative to its parent. 14492 * 14493 * @return The right edge of this view, in pixels. 14494 */ 14495 @ViewDebug.CapturedViewProperty 14496 public final int getRight() { 14497 return mRight; 14498 } 14499 14500 /** 14501 * Sets the right position of this view relative to its parent. This method is meant to be called 14502 * by the layout system and should not generally be called otherwise, because the property 14503 * may be changed at any time by the layout. 14504 * 14505 * @param right The right of this view, in pixels. 14506 */ 14507 public final void setRight(int right) { 14508 if (right != mRight) { 14509 final boolean matrixIsIdentity = hasIdentityMatrix(); 14510 if (matrixIsIdentity) { 14511 if (mAttachInfo != null) { 14512 int maxRight; 14513 if (right < mRight) { 14514 maxRight = mRight; 14515 } else { 14516 maxRight = right; 14517 } 14518 invalidate(0, 0, maxRight - mLeft, mBottom - mTop); 14519 } 14520 } else { 14521 // Double-invalidation is necessary to capture view's old and new areas 14522 invalidate(true); 14523 } 14524 14525 int oldWidth = mRight - mLeft; 14526 int height = mBottom - mTop; 14527 14528 mRight = right; 14529 mRenderNode.setRight(mRight); 14530 14531 sizeChange(mRight - mLeft, height, oldWidth, height); 14532 14533 if (!matrixIsIdentity) { 14534 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 14535 invalidate(true); 14536 } 14537 mBackgroundSizeChanged = true; 14538 mDefaultFocusHighlightSizeChanged = true; 14539 if (mForegroundInfo != null) { 14540 mForegroundInfo.mBoundsChanged = true; 14541 } 14542 invalidateParentIfNeeded(); 14543 if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) { 14544 // View was rejected last time it was drawn by its parent; this may have changed 14545 invalidateParentIfNeeded(); 14546 } 14547 } 14548 } 14549 14550 /** 14551 * The visual x position of this view, in pixels. This is equivalent to the 14552 * {@link #setTranslationX(float) translationX} property plus the current 14553 * {@link #getLeft() left} property. 14554 * 14555 * @return The visual x position of this view, in pixels. 14556 */ 14557 @ViewDebug.ExportedProperty(category = "drawing") 14558 public float getX() { 14559 return mLeft + getTranslationX(); 14560 } 14561 14562 /** 14563 * Sets the visual x position of this view, in pixels. This is equivalent to setting the 14564 * {@link #setTranslationX(float) translationX} property to be the difference between 14565 * the x value passed in and the current {@link #getLeft() left} property. 14566 * 14567 * @param x The visual x position of this view, in pixels. 14568 */ 14569 public void setX(float x) { 14570 setTranslationX(x - mLeft); 14571 } 14572 14573 /** 14574 * The visual y position of this view, in pixels. This is equivalent to the 14575 * {@link #setTranslationY(float) translationY} property plus the current 14576 * {@link #getTop() top} property. 14577 * 14578 * @return The visual y position of this view, in pixels. 14579 */ 14580 @ViewDebug.ExportedProperty(category = "drawing") 14581 public float getY() { 14582 return mTop + getTranslationY(); 14583 } 14584 14585 /** 14586 * Sets the visual y position of this view, in pixels. This is equivalent to setting the 14587 * {@link #setTranslationY(float) translationY} property to be the difference between 14588 * the y value passed in and the current {@link #getTop() top} property. 14589 * 14590 * @param y The visual y position of this view, in pixels. 14591 */ 14592 public void setY(float y) { 14593 setTranslationY(y - mTop); 14594 } 14595 14596 /** 14597 * The visual z position of this view, in pixels. This is equivalent to the 14598 * {@link #setTranslationZ(float) translationZ} property plus the current 14599 * {@link #getElevation() elevation} property. 14600 * 14601 * @return The visual z position of this view, in pixels. 14602 */ 14603 @ViewDebug.ExportedProperty(category = "drawing") 14604 public float getZ() { 14605 return getElevation() + getTranslationZ(); 14606 } 14607 14608 /** 14609 * Sets the visual z position of this view, in pixels. This is equivalent to setting the 14610 * {@link #setTranslationZ(float) translationZ} property to be the difference between 14611 * the x value passed in and the current {@link #getElevation() elevation} property. 14612 * 14613 * @param z The visual z position of this view, in pixels. 14614 */ 14615 public void setZ(float z) { 14616 setTranslationZ(z - getElevation()); 14617 } 14618 14619 /** 14620 * The base elevation of this view relative to its parent, in pixels. 14621 * 14622 * @return The base depth position of the view, in pixels. 14623 */ 14624 @ViewDebug.ExportedProperty(category = "drawing") 14625 public float getElevation() { 14626 return mRenderNode.getElevation(); 14627 } 14628 14629 /** 14630 * Sets the base elevation of this view, in pixels. 14631 * 14632 * @attr ref android.R.styleable#View_elevation 14633 */ 14634 public void setElevation(float elevation) { 14635 if (elevation != getElevation()) { 14636 invalidateViewProperty(true, false); 14637 mRenderNode.setElevation(elevation); 14638 invalidateViewProperty(false, true); 14639 14640 invalidateParentIfNeededAndWasQuickRejected(); 14641 } 14642 } 14643 14644 /** 14645 * The horizontal location of this view relative to its {@link #getLeft() left} position. 14646 * This position is post-layout, in addition to wherever the object's 14647 * layout placed it. 14648 * 14649 * @return The horizontal position of this view relative to its left position, in pixels. 14650 */ 14651 @ViewDebug.ExportedProperty(category = "drawing") 14652 public float getTranslationX() { 14653 return mRenderNode.getTranslationX(); 14654 } 14655 14656 /** 14657 * Sets the horizontal location of this view relative to its {@link #getLeft() left} position. 14658 * This effectively positions the object post-layout, in addition to wherever the object's 14659 * layout placed it. 14660 * 14661 * @param translationX The horizontal position of this view relative to its left position, 14662 * in pixels. 14663 * 14664 * @attr ref android.R.styleable#View_translationX 14665 */ 14666 public void setTranslationX(float translationX) { 14667 if (translationX != getTranslationX()) { 14668 invalidateViewProperty(true, false); 14669 mRenderNode.setTranslationX(translationX); 14670 invalidateViewProperty(false, true); 14671 14672 invalidateParentIfNeededAndWasQuickRejected(); 14673 notifySubtreeAccessibilityStateChangedIfNeeded(); 14674 } 14675 } 14676 14677 /** 14678 * The vertical location of this view relative to its {@link #getTop() top} position. 14679 * This position is post-layout, in addition to wherever the object's 14680 * layout placed it. 14681 * 14682 * @return The vertical position of this view relative to its top position, 14683 * in pixels. 14684 */ 14685 @ViewDebug.ExportedProperty(category = "drawing") 14686 public float getTranslationY() { 14687 return mRenderNode.getTranslationY(); 14688 } 14689 14690 /** 14691 * Sets the vertical location of this view relative to its {@link #getTop() top} position. 14692 * This effectively positions the object post-layout, in addition to wherever the object's 14693 * layout placed it. 14694 * 14695 * @param translationY The vertical position of this view relative to its top position, 14696 * in pixels. 14697 * 14698 * @attr ref android.R.styleable#View_translationY 14699 */ 14700 public void setTranslationY(float translationY) { 14701 if (translationY != getTranslationY()) { 14702 invalidateViewProperty(true, false); 14703 mRenderNode.setTranslationY(translationY); 14704 invalidateViewProperty(false, true); 14705 14706 invalidateParentIfNeededAndWasQuickRejected(); 14707 notifySubtreeAccessibilityStateChangedIfNeeded(); 14708 } 14709 } 14710 14711 /** 14712 * The depth location of this view relative to its {@link #getElevation() elevation}. 14713 * 14714 * @return The depth of this view relative to its elevation. 14715 */ 14716 @ViewDebug.ExportedProperty(category = "drawing") 14717 public float getTranslationZ() { 14718 return mRenderNode.getTranslationZ(); 14719 } 14720 14721 /** 14722 * Sets the depth location of this view relative to its {@link #getElevation() elevation}. 14723 * 14724 * @attr ref android.R.styleable#View_translationZ 14725 */ 14726 public void setTranslationZ(float translationZ) { 14727 if (translationZ != getTranslationZ()) { 14728 invalidateViewProperty(true, false); 14729 mRenderNode.setTranslationZ(translationZ); 14730 invalidateViewProperty(false, true); 14731 14732 invalidateParentIfNeededAndWasQuickRejected(); 14733 } 14734 } 14735 14736 /** @hide */ 14737 public void setAnimationMatrix(Matrix matrix) { 14738 invalidateViewProperty(true, false); 14739 mRenderNode.setAnimationMatrix(matrix); 14740 invalidateViewProperty(false, true); 14741 14742 invalidateParentIfNeededAndWasQuickRejected(); 14743 } 14744 14745 /** 14746 * Returns the current StateListAnimator if exists. 14747 * 14748 * @return StateListAnimator or null if it does not exists 14749 * @see #setStateListAnimator(android.animation.StateListAnimator) 14750 */ 14751 public StateListAnimator getStateListAnimator() { 14752 return mStateListAnimator; 14753 } 14754 14755 /** 14756 * Attaches the provided StateListAnimator to this View. 14757 * <p> 14758 * Any previously attached StateListAnimator will be detached. 14759 * 14760 * @param stateListAnimator The StateListAnimator to update the view 14761 * @see android.animation.StateListAnimator 14762 */ 14763 public void setStateListAnimator(StateListAnimator stateListAnimator) { 14764 if (mStateListAnimator == stateListAnimator) { 14765 return; 14766 } 14767 if (mStateListAnimator != null) { 14768 mStateListAnimator.setTarget(null); 14769 } 14770 mStateListAnimator = stateListAnimator; 14771 if (stateListAnimator != null) { 14772 stateListAnimator.setTarget(this); 14773 if (isAttachedToWindow()) { 14774 stateListAnimator.setState(getDrawableState()); 14775 } 14776 } 14777 } 14778 14779 /** 14780 * Returns whether the Outline should be used to clip the contents of the View. 14781 * <p> 14782 * Note that this flag will only be respected if the View's Outline returns true from 14783 * {@link Outline#canClip()}. 14784 * 14785 * @see #setOutlineProvider(ViewOutlineProvider) 14786 * @see #setClipToOutline(boolean) 14787 */ 14788 public final boolean getClipToOutline() { 14789 return mRenderNode.getClipToOutline(); 14790 } 14791 14792 /** 14793 * Sets whether the View's Outline should be used to clip the contents of the View. 14794 * <p> 14795 * Only a single non-rectangular clip can be applied on a View at any time. 14796 * Circular clips from a {@link ViewAnimationUtils#createCircularReveal(View, int, int, float, float) 14797 * circular reveal} animation take priority over Outline clipping, and 14798 * child Outline clipping takes priority over Outline clipping done by a 14799 * parent. 14800 * <p> 14801 * Note that this flag will only be respected if the View's Outline returns true from 14802 * {@link Outline#canClip()}. 14803 * 14804 * @see #setOutlineProvider(ViewOutlineProvider) 14805 * @see #getClipToOutline() 14806 */ 14807 public void setClipToOutline(boolean clipToOutline) { 14808 damageInParent(); 14809 if (getClipToOutline() != clipToOutline) { 14810 mRenderNode.setClipToOutline(clipToOutline); 14811 } 14812 } 14813 14814 // correspond to the enum values of View_outlineProvider 14815 private static final int PROVIDER_BACKGROUND = 0; 14816 private static final int PROVIDER_NONE = 1; 14817 private static final int PROVIDER_BOUNDS = 2; 14818 private static final int PROVIDER_PADDED_BOUNDS = 3; 14819 private void setOutlineProviderFromAttribute(int providerInt) { 14820 switch (providerInt) { 14821 case PROVIDER_BACKGROUND: 14822 setOutlineProvider(ViewOutlineProvider.BACKGROUND); 14823 break; 14824 case PROVIDER_NONE: 14825 setOutlineProvider(null); 14826 break; 14827 case PROVIDER_BOUNDS: 14828 setOutlineProvider(ViewOutlineProvider.BOUNDS); 14829 break; 14830 case PROVIDER_PADDED_BOUNDS: 14831 setOutlineProvider(ViewOutlineProvider.PADDED_BOUNDS); 14832 break; 14833 } 14834 } 14835 14836 /** 14837 * Sets the {@link ViewOutlineProvider} of the view, which generates the Outline that defines 14838 * the shape of the shadow it casts, and enables outline clipping. 14839 * <p> 14840 * The default ViewOutlineProvider, {@link ViewOutlineProvider#BACKGROUND}, queries the Outline 14841 * from the View's background drawable, via {@link Drawable#getOutline(Outline)}. Changing the 14842 * outline provider with this method allows this behavior to be overridden. 14843 * <p> 14844 * If the ViewOutlineProvider is null, if querying it for an outline returns false, 14845 * or if the produced Outline is {@link Outline#isEmpty()}, shadows will not be cast. 14846 * <p> 14847 * Only outlines that return true from {@link Outline#canClip()} may be used for clipping. 14848 * 14849 * @see #setClipToOutline(boolean) 14850 * @see #getClipToOutline() 14851 * @see #getOutlineProvider() 14852 */ 14853 public void setOutlineProvider(ViewOutlineProvider provider) { 14854 mOutlineProvider = provider; 14855 invalidateOutline(); 14856 } 14857 14858 /** 14859 * Returns the current {@link ViewOutlineProvider} of the view, which generates the Outline 14860 * that defines the shape of the shadow it casts, and enables outline clipping. 14861 * 14862 * @see #setOutlineProvider(ViewOutlineProvider) 14863 */ 14864 public ViewOutlineProvider getOutlineProvider() { 14865 return mOutlineProvider; 14866 } 14867 14868 /** 14869 * Called to rebuild this View's Outline from its {@link ViewOutlineProvider outline provider} 14870 * 14871 * @see #setOutlineProvider(ViewOutlineProvider) 14872 */ 14873 public void invalidateOutline() { 14874 rebuildOutline(); 14875 14876 notifySubtreeAccessibilityStateChangedIfNeeded(); 14877 invalidateViewProperty(false, false); 14878 } 14879 14880 /** 14881 * Internal version of {@link #invalidateOutline()} which invalidates the 14882 * outline without invalidating the view itself. This is intended to be called from 14883 * within methods in the View class itself which are the result of the view being 14884 * invalidated already. For example, when we are drawing the background of a View, 14885 * we invalidate the outline in case it changed in the meantime, but we do not 14886 * need to invalidate the view because we're already drawing the background as part 14887 * of drawing the view in response to an earlier invalidation of the view. 14888 */ 14889 private void rebuildOutline() { 14890 // Unattached views ignore this signal, and outline is recomputed in onAttachedToWindow() 14891 if (mAttachInfo == null) return; 14892 14893 if (mOutlineProvider == null) { 14894 // no provider, remove outline 14895 mRenderNode.setOutline(null); 14896 } else { 14897 final Outline outline = mAttachInfo.mTmpOutline; 14898 outline.setEmpty(); 14899 outline.setAlpha(1.0f); 14900 14901 mOutlineProvider.getOutline(this, outline); 14902 mRenderNode.setOutline(outline); 14903 } 14904 } 14905 14906 /** 14907 * HierarchyViewer only 14908 * 14909 * @hide 14910 */ 14911 @ViewDebug.ExportedProperty(category = "drawing") 14912 public boolean hasShadow() { 14913 return mRenderNode.hasShadow(); 14914 } 14915 14916 14917 /** @hide */ 14918 public void setRevealClip(boolean shouldClip, float x, float y, float radius) { 14919 mRenderNode.setRevealClip(shouldClip, x, y, radius); 14920 invalidateViewProperty(false, false); 14921 } 14922 14923 /** 14924 * Hit rectangle in parent's coordinates 14925 * 14926 * @param outRect The hit rectangle of the view. 14927 */ 14928 public void getHitRect(Rect outRect) { 14929 if (hasIdentityMatrix() || mAttachInfo == null) { 14930 outRect.set(mLeft, mTop, mRight, mBottom); 14931 } else { 14932 final RectF tmpRect = mAttachInfo.mTmpTransformRect; 14933 tmpRect.set(0, 0, getWidth(), getHeight()); 14934 getMatrix().mapRect(tmpRect); // TODO: mRenderNode.mapRect(tmpRect) 14935 outRect.set((int) tmpRect.left + mLeft, (int) tmpRect.top + mTop, 14936 (int) tmpRect.right + mLeft, (int) tmpRect.bottom + mTop); 14937 } 14938 } 14939 14940 /** 14941 * Determines whether the given point, in local coordinates is inside the view. 14942 */ 14943 /*package*/ final boolean pointInView(float localX, float localY) { 14944 return pointInView(localX, localY, 0); 14945 } 14946 14947 /** 14948 * Utility method to determine whether the given point, in local coordinates, 14949 * is inside the view, where the area of the view is expanded by the slop factor. 14950 * This method is called while processing touch-move events to determine if the event 14951 * is still within the view. 14952 * 14953 * @hide 14954 */ 14955 public boolean pointInView(float localX, float localY, float slop) { 14956 return localX >= -slop && localY >= -slop && localX < ((mRight - mLeft) + slop) && 14957 localY < ((mBottom - mTop) + slop); 14958 } 14959 14960 /** 14961 * When a view has focus and the user navigates away from it, the next view is searched for 14962 * starting from the rectangle filled in by this method. 14963 * 14964 * By default, the rectangle is the {@link #getDrawingRect(android.graphics.Rect)}) 14965 * of the view. However, if your view maintains some idea of internal selection, 14966 * such as a cursor, or a selected row or column, you should override this method and 14967 * fill in a more specific rectangle. 14968 * 14969 * @param r The rectangle to fill in, in this view's coordinates. 14970 */ 14971 public void getFocusedRect(Rect r) { 14972 getDrawingRect(r); 14973 } 14974 14975 /** 14976 * If some part of this view is not clipped by any of its parents, then 14977 * return that area in r in global (root) coordinates. To convert r to local 14978 * coordinates (without taking possible View rotations into account), offset 14979 * it by -globalOffset (e.g. r.offset(-globalOffset.x, -globalOffset.y)). 14980 * If the view is completely clipped or translated out, return false. 14981 * 14982 * @param r If true is returned, r holds the global coordinates of the 14983 * visible portion of this view. 14984 * @param globalOffset If true is returned, globalOffset holds the dx,dy 14985 * between this view and its root. globalOffet may be null. 14986 * @return true if r is non-empty (i.e. part of the view is visible at the 14987 * root level. 14988 */ 14989 public boolean getGlobalVisibleRect(Rect r, Point globalOffset) { 14990 int width = mRight - mLeft; 14991 int height = mBottom - mTop; 14992 if (width > 0 && height > 0) { 14993 r.set(0, 0, width, height); 14994 if (globalOffset != null) { 14995 globalOffset.set(-mScrollX, -mScrollY); 14996 } 14997 return mParent == null || mParent.getChildVisibleRect(this, r, globalOffset); 14998 } 14999 return false; 15000 } 15001 15002 public final boolean getGlobalVisibleRect(Rect r) { 15003 return getGlobalVisibleRect(r, null); 15004 } 15005 15006 public final boolean getLocalVisibleRect(Rect r) { 15007 final Point offset = mAttachInfo != null ? mAttachInfo.mPoint : new Point(); 15008 if (getGlobalVisibleRect(r, offset)) { 15009 r.offset(-offset.x, -offset.y); // make r local 15010 return true; 15011 } 15012 return false; 15013 } 15014 15015 /** 15016 * Offset this view's vertical location by the specified number of pixels. 15017 * 15018 * @param offset the number of pixels to offset the view by 15019 */ 15020 public void offsetTopAndBottom(int offset) { 15021 if (offset != 0) { 15022 final boolean matrixIsIdentity = hasIdentityMatrix(); 15023 if (matrixIsIdentity) { 15024 if (isHardwareAccelerated()) { 15025 invalidateViewProperty(false, false); 15026 } else { 15027 final ViewParent p = mParent; 15028 if (p != null && mAttachInfo != null) { 15029 final Rect r = mAttachInfo.mTmpInvalRect; 15030 int minTop; 15031 int maxBottom; 15032 int yLoc; 15033 if (offset < 0) { 15034 minTop = mTop + offset; 15035 maxBottom = mBottom; 15036 yLoc = offset; 15037 } else { 15038 minTop = mTop; 15039 maxBottom = mBottom + offset; 15040 yLoc = 0; 15041 } 15042 r.set(0, yLoc, mRight - mLeft, maxBottom - minTop); 15043 p.invalidateChild(this, r); 15044 } 15045 } 15046 } else { 15047 invalidateViewProperty(false, false); 15048 } 15049 15050 mTop += offset; 15051 mBottom += offset; 15052 mRenderNode.offsetTopAndBottom(offset); 15053 if (isHardwareAccelerated()) { 15054 invalidateViewProperty(false, false); 15055 invalidateParentIfNeededAndWasQuickRejected(); 15056 } else { 15057 if (!matrixIsIdentity) { 15058 invalidateViewProperty(false, true); 15059 } 15060 invalidateParentIfNeeded(); 15061 } 15062 notifySubtreeAccessibilityStateChangedIfNeeded(); 15063 } 15064 } 15065 15066 /** 15067 * Offset this view's horizontal location by the specified amount of pixels. 15068 * 15069 * @param offset the number of pixels to offset the view by 15070 */ 15071 public void offsetLeftAndRight(int offset) { 15072 if (offset != 0) { 15073 final boolean matrixIsIdentity = hasIdentityMatrix(); 15074 if (matrixIsIdentity) { 15075 if (isHardwareAccelerated()) { 15076 invalidateViewProperty(false, false); 15077 } else { 15078 final ViewParent p = mParent; 15079 if (p != null && mAttachInfo != null) { 15080 final Rect r = mAttachInfo.mTmpInvalRect; 15081 int minLeft; 15082 int maxRight; 15083 if (offset < 0) { 15084 minLeft = mLeft + offset; 15085 maxRight = mRight; 15086 } else { 15087 minLeft = mLeft; 15088 maxRight = mRight + offset; 15089 } 15090 r.set(0, 0, maxRight - minLeft, mBottom - mTop); 15091 p.invalidateChild(this, r); 15092 } 15093 } 15094 } else { 15095 invalidateViewProperty(false, false); 15096 } 15097 15098 mLeft += offset; 15099 mRight += offset; 15100 mRenderNode.offsetLeftAndRight(offset); 15101 if (isHardwareAccelerated()) { 15102 invalidateViewProperty(false, false); 15103 invalidateParentIfNeededAndWasQuickRejected(); 15104 } else { 15105 if (!matrixIsIdentity) { 15106 invalidateViewProperty(false, true); 15107 } 15108 invalidateParentIfNeeded(); 15109 } 15110 notifySubtreeAccessibilityStateChangedIfNeeded(); 15111 } 15112 } 15113 15114 /** 15115 * Get the LayoutParams associated with this view. All views should have 15116 * layout parameters. These supply parameters to the <i>parent</i> of this 15117 * view specifying how it should be arranged. There are many subclasses of 15118 * ViewGroup.LayoutParams, and these correspond to the different subclasses 15119 * of ViewGroup that are responsible for arranging their children. 15120 * 15121 * This method may return null if this View is not attached to a parent 15122 * ViewGroup or {@link #setLayoutParams(android.view.ViewGroup.LayoutParams)} 15123 * was not invoked successfully. When a View is attached to a parent 15124 * ViewGroup, this method must not return null. 15125 * 15126 * @return The LayoutParams associated with this view, or null if no 15127 * parameters have been set yet 15128 */ 15129 @ViewDebug.ExportedProperty(deepExport = true, prefix = "layout_") 15130 public ViewGroup.LayoutParams getLayoutParams() { 15131 return mLayoutParams; 15132 } 15133 15134 /** 15135 * Set the layout parameters associated with this view. These supply 15136 * parameters to the <i>parent</i> of this view specifying how it should be 15137 * arranged. There are many subclasses of ViewGroup.LayoutParams, and these 15138 * correspond to the different subclasses of ViewGroup that are responsible 15139 * for arranging their children. 15140 * 15141 * @param params The layout parameters for this view, cannot be null 15142 */ 15143 public void setLayoutParams(ViewGroup.LayoutParams params) { 15144 if (params == null) { 15145 throw new NullPointerException("Layout parameters cannot be null"); 15146 } 15147 mLayoutParams = params; 15148 resolveLayoutParams(); 15149 if (mParent instanceof ViewGroup) { 15150 ((ViewGroup) mParent).onSetLayoutParams(this, params); 15151 } 15152 requestLayout(); 15153 } 15154 15155 /** 15156 * Resolve the layout parameters depending on the resolved layout direction 15157 * 15158 * @hide 15159 */ 15160 public void resolveLayoutParams() { 15161 if (mLayoutParams != null) { 15162 mLayoutParams.resolveLayoutDirection(getLayoutDirection()); 15163 } 15164 } 15165 15166 /** 15167 * Set the scrolled position of your view. This will cause a call to 15168 * {@link #onScrollChanged(int, int, int, int)} and the view will be 15169 * invalidated. 15170 * @param x the x position to scroll to 15171 * @param y the y position to scroll to 15172 */ 15173 public void scrollTo(int x, int y) { 15174 if (mScrollX != x || mScrollY != y) { 15175 int oldX = mScrollX; 15176 int oldY = mScrollY; 15177 mScrollX = x; 15178 mScrollY = y; 15179 invalidateParentCaches(); 15180 onScrollChanged(mScrollX, mScrollY, oldX, oldY); 15181 if (!awakenScrollBars()) { 15182 postInvalidateOnAnimation(); 15183 } 15184 } 15185 } 15186 15187 /** 15188 * Move the scrolled position of your view. This will cause a call to 15189 * {@link #onScrollChanged(int, int, int, int)} and the view will be 15190 * invalidated. 15191 * @param x the amount of pixels to scroll by horizontally 15192 * @param y the amount of pixels to scroll by vertically 15193 */ 15194 public void scrollBy(int x, int y) { 15195 scrollTo(mScrollX + x, mScrollY + y); 15196 } 15197 15198 /** 15199 * <p>Trigger the scrollbars to draw. When invoked this method starts an 15200 * animation to fade the scrollbars out after a default delay. If a subclass 15201 * provides animated scrolling, the start delay should equal the duration 15202 * of the scrolling animation.</p> 15203 * 15204 * <p>The animation starts only if at least one of the scrollbars is 15205 * enabled, as specified by {@link #isHorizontalScrollBarEnabled()} and 15206 * {@link #isVerticalScrollBarEnabled()}. When the animation is started, 15207 * this method returns true, and false otherwise. If the animation is 15208 * started, this method calls {@link #invalidate()}; in that case the 15209 * caller should not call {@link #invalidate()}.</p> 15210 * 15211 * <p>This method should be invoked every time a subclass directly updates 15212 * the scroll parameters.</p> 15213 * 15214 * <p>This method is automatically invoked by {@link #scrollBy(int, int)} 15215 * and {@link #scrollTo(int, int)}.</p> 15216 * 15217 * @return true if the animation is played, false otherwise 15218 * 15219 * @see #awakenScrollBars(int) 15220 * @see #scrollBy(int, int) 15221 * @see #scrollTo(int, int) 15222 * @see #isHorizontalScrollBarEnabled() 15223 * @see #isVerticalScrollBarEnabled() 15224 * @see #setHorizontalScrollBarEnabled(boolean) 15225 * @see #setVerticalScrollBarEnabled(boolean) 15226 */ 15227 protected boolean awakenScrollBars() { 15228 return mScrollCache != null && 15229 awakenScrollBars(mScrollCache.scrollBarDefaultDelayBeforeFade, true); 15230 } 15231 15232 /** 15233 * Trigger the scrollbars to draw. 15234 * This method differs from awakenScrollBars() only in its default duration. 15235 * initialAwakenScrollBars() will show the scroll bars for longer than 15236 * usual to give the user more of a chance to notice them. 15237 * 15238 * @return true if the animation is played, false otherwise. 15239 */ 15240 private boolean initialAwakenScrollBars() { 15241 return mScrollCache != null && 15242 awakenScrollBars(mScrollCache.scrollBarDefaultDelayBeforeFade * 4, true); 15243 } 15244 15245 /** 15246 * <p> 15247 * Trigger the scrollbars to draw. When invoked this method starts an 15248 * animation to fade the scrollbars out after a fixed delay. If a subclass 15249 * provides animated scrolling, the start delay should equal the duration of 15250 * the scrolling animation. 15251 * </p> 15252 * 15253 * <p> 15254 * The animation starts only if at least one of the scrollbars is enabled, 15255 * as specified by {@link #isHorizontalScrollBarEnabled()} and 15256 * {@link #isVerticalScrollBarEnabled()}. When the animation is started, 15257 * this method returns true, and false otherwise. If the animation is 15258 * started, this method calls {@link #invalidate()}; in that case the caller 15259 * should not call {@link #invalidate()}. 15260 * </p> 15261 * 15262 * <p> 15263 * This method should be invoked every time a subclass directly updates the 15264 * scroll parameters. 15265 * </p> 15266 * 15267 * @param startDelay the delay, in milliseconds, after which the animation 15268 * should start; when the delay is 0, the animation starts 15269 * immediately 15270 * @return true if the animation is played, false otherwise 15271 * 15272 * @see #scrollBy(int, int) 15273 * @see #scrollTo(int, int) 15274 * @see #isHorizontalScrollBarEnabled() 15275 * @see #isVerticalScrollBarEnabled() 15276 * @see #setHorizontalScrollBarEnabled(boolean) 15277 * @see #setVerticalScrollBarEnabled(boolean) 15278 */ 15279 protected boolean awakenScrollBars(int startDelay) { 15280 return awakenScrollBars(startDelay, true); 15281 } 15282 15283 /** 15284 * <p> 15285 * Trigger the scrollbars to draw. When invoked this method starts an 15286 * animation to fade the scrollbars out after a fixed delay. If a subclass 15287 * provides animated scrolling, the start delay should equal the duration of 15288 * the scrolling animation. 15289 * </p> 15290 * 15291 * <p> 15292 * The animation starts only if at least one of the scrollbars is enabled, 15293 * as specified by {@link #isHorizontalScrollBarEnabled()} and 15294 * {@link #isVerticalScrollBarEnabled()}. When the animation is started, 15295 * this method returns true, and false otherwise. If the animation is 15296 * started, this method calls {@link #invalidate()} if the invalidate parameter 15297 * is set to true; in that case the caller 15298 * should not call {@link #invalidate()}. 15299 * </p> 15300 * 15301 * <p> 15302 * This method should be invoked every time a subclass directly updates the 15303 * scroll parameters. 15304 * </p> 15305 * 15306 * @param startDelay the delay, in milliseconds, after which the animation 15307 * should start; when the delay is 0, the animation starts 15308 * immediately 15309 * 15310 * @param invalidate Whether this method should call invalidate 15311 * 15312 * @return true if the animation is played, false otherwise 15313 * 15314 * @see #scrollBy(int, int) 15315 * @see #scrollTo(int, int) 15316 * @see #isHorizontalScrollBarEnabled() 15317 * @see #isVerticalScrollBarEnabled() 15318 * @see #setHorizontalScrollBarEnabled(boolean) 15319 * @see #setVerticalScrollBarEnabled(boolean) 15320 */ 15321 protected boolean awakenScrollBars(int startDelay, boolean invalidate) { 15322 final ScrollabilityCache scrollCache = mScrollCache; 15323 15324 if (scrollCache == null || !scrollCache.fadeScrollBars) { 15325 return false; 15326 } 15327 15328 if (scrollCache.scrollBar == null) { 15329 scrollCache.scrollBar = new ScrollBarDrawable(); 15330 scrollCache.scrollBar.setState(getDrawableState()); 15331 scrollCache.scrollBar.setCallback(this); 15332 } 15333 15334 if (isHorizontalScrollBarEnabled() || isVerticalScrollBarEnabled()) { 15335 15336 if (invalidate) { 15337 // Invalidate to show the scrollbars 15338 postInvalidateOnAnimation(); 15339 } 15340 15341 if (scrollCache.state == ScrollabilityCache.OFF) { 15342 // FIXME: this is copied from WindowManagerService. 15343 // We should get this value from the system when it 15344 // is possible to do so. 15345 final int KEY_REPEAT_FIRST_DELAY = 750; 15346 startDelay = Math.max(KEY_REPEAT_FIRST_DELAY, startDelay); 15347 } 15348 15349 // Tell mScrollCache when we should start fading. This may 15350 // extend the fade start time if one was already scheduled 15351 long fadeStartTime = AnimationUtils.currentAnimationTimeMillis() + startDelay; 15352 scrollCache.fadeStartTime = fadeStartTime; 15353 scrollCache.state = ScrollabilityCache.ON; 15354 15355 // Schedule our fader to run, unscheduling any old ones first 15356 if (mAttachInfo != null) { 15357 mAttachInfo.mHandler.removeCallbacks(scrollCache); 15358 mAttachInfo.mHandler.postAtTime(scrollCache, fadeStartTime); 15359 } 15360 15361 return true; 15362 } 15363 15364 return false; 15365 } 15366 15367 /** 15368 * Do not invalidate views which are not visible and which are not running an animation. They 15369 * will not get drawn and they should not set dirty flags as if they will be drawn 15370 */ 15371 private boolean skipInvalidate() { 15372 return (mViewFlags & VISIBILITY_MASK) != VISIBLE && mCurrentAnimation == null && 15373 (!(mParent instanceof ViewGroup) || 15374 !((ViewGroup) mParent).isViewTransitioning(this)); 15375 } 15376 15377 /** 15378 * Mark the area defined by dirty as needing to be drawn. If the view is 15379 * visible, {@link #onDraw(android.graphics.Canvas)} will be called at some 15380 * point in the future. 15381 * <p> 15382 * This must be called from a UI thread. To call from a non-UI thread, call 15383 * {@link #postInvalidate()}. 15384 * <p> 15385 * <b>WARNING:</b> In API 19 and below, this method may be destructive to 15386 * {@code dirty}. 15387 * 15388 * @param dirty the rectangle representing the bounds of the dirty region 15389 */ 15390 public void invalidate(Rect dirty) { 15391 final int scrollX = mScrollX; 15392 final int scrollY = mScrollY; 15393 invalidateInternal(dirty.left - scrollX, dirty.top - scrollY, 15394 dirty.right - scrollX, dirty.bottom - scrollY, true, false); 15395 } 15396 15397 /** 15398 * Mark the area defined by the rect (l,t,r,b) as needing to be drawn. The 15399 * coordinates of the dirty rect are relative to the view. If the view is 15400 * visible, {@link #onDraw(android.graphics.Canvas)} will be called at some 15401 * point in the future. 15402 * <p> 15403 * This must be called from a UI thread. To call from a non-UI thread, call 15404 * {@link #postInvalidate()}. 15405 * 15406 * @param l the left position of the dirty region 15407 * @param t the top position of the dirty region 15408 * @param r the right position of the dirty region 15409 * @param b the bottom position of the dirty region 15410 */ 15411 public void invalidate(int l, int t, int r, int b) { 15412 final int scrollX = mScrollX; 15413 final int scrollY = mScrollY; 15414 invalidateInternal(l - scrollX, t - scrollY, r - scrollX, b - scrollY, true, false); 15415 } 15416 15417 /** 15418 * Invalidate the whole view. If the view is visible, 15419 * {@link #onDraw(android.graphics.Canvas)} will be called at some point in 15420 * the future. 15421 * <p> 15422 * This must be called from a UI thread. To call from a non-UI thread, call 15423 * {@link #postInvalidate()}. 15424 */ 15425 public void invalidate() { 15426 invalidate(true); 15427 } 15428 15429 /** 15430 * This is where the invalidate() work actually happens. A full invalidate() 15431 * causes the drawing cache to be invalidated, but this function can be 15432 * called with invalidateCache set to false to skip that invalidation step 15433 * for cases that do not need it (for example, a component that remains at 15434 * the same dimensions with the same content). 15435 * 15436 * @param invalidateCache Whether the drawing cache for this view should be 15437 * invalidated as well. This is usually true for a full 15438 * invalidate, but may be set to false if the View's contents or 15439 * dimensions have not changed. 15440 * @hide 15441 */ 15442 public void invalidate(boolean invalidateCache) { 15443 invalidateInternal(0, 0, mRight - mLeft, mBottom - mTop, invalidateCache, true); 15444 } 15445 15446 void invalidateInternal(int l, int t, int r, int b, boolean invalidateCache, 15447 boolean fullInvalidate) { 15448 if (mGhostView != null) { 15449 mGhostView.invalidate(true); 15450 return; 15451 } 15452 15453 if (skipInvalidate()) { 15454 return; 15455 } 15456 15457 if ((mPrivateFlags & (PFLAG_DRAWN | PFLAG_HAS_BOUNDS)) == (PFLAG_DRAWN | PFLAG_HAS_BOUNDS) 15458 || (invalidateCache && (mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == PFLAG_DRAWING_CACHE_VALID) 15459 || (mPrivateFlags & PFLAG_INVALIDATED) != PFLAG_INVALIDATED 15460 || (fullInvalidate && isOpaque() != mLastIsOpaque)) { 15461 if (fullInvalidate) { 15462 mLastIsOpaque = isOpaque(); 15463 mPrivateFlags &= ~PFLAG_DRAWN; 15464 } 15465 15466 mPrivateFlags |= PFLAG_DIRTY; 15467 15468 if (invalidateCache) { 15469 mPrivateFlags |= PFLAG_INVALIDATED; 15470 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; 15471 } 15472 15473 // Propagate the damage rectangle to the parent view. 15474 final AttachInfo ai = mAttachInfo; 15475 final ViewParent p = mParent; 15476 if (p != null && ai != null && l < r && t < b) { 15477 final Rect damage = ai.mTmpInvalRect; 15478 damage.set(l, t, r, b); 15479 p.invalidateChild(this, damage); 15480 } 15481 15482 // Damage the entire projection receiver, if necessary. 15483 if (mBackground != null && mBackground.isProjected()) { 15484 final View receiver = getProjectionReceiver(); 15485 if (receiver != null) { 15486 receiver.damageInParent(); 15487 } 15488 } 15489 } 15490 } 15491 15492 /** 15493 * @return this view's projection receiver, or {@code null} if none exists 15494 */ 15495 private View getProjectionReceiver() { 15496 ViewParent p = getParent(); 15497 while (p != null && p instanceof View) { 15498 final View v = (View) p; 15499 if (v.isProjectionReceiver()) { 15500 return v; 15501 } 15502 p = p.getParent(); 15503 } 15504 15505 return null; 15506 } 15507 15508 /** 15509 * @return whether the view is a projection receiver 15510 */ 15511 private boolean isProjectionReceiver() { 15512 return mBackground != null; 15513 } 15514 15515 /** 15516 * Quick invalidation for View property changes (alpha, translationXY, etc.). We don't want to 15517 * set any flags or handle all of the cases handled by the default invalidation methods. 15518 * Instead, we just want to schedule a traversal in ViewRootImpl with the appropriate 15519 * dirty rect. This method calls into fast invalidation methods in ViewGroup that 15520 * walk up the hierarchy, transforming the dirty rect as necessary. 15521 * 15522 * The method also handles normal invalidation logic if display list properties are not 15523 * being used in this view. The invalidateParent and forceRedraw flags are used by that 15524 * backup approach, to handle these cases used in the various property-setting methods. 15525 * 15526 * @param invalidateParent Force a call to invalidateParentCaches() if display list properties 15527 * are not being used in this view 15528 * @param forceRedraw Mark the view as DRAWN to force the invalidation to propagate, if display 15529 * list properties are not being used in this view 15530 */ 15531 void invalidateViewProperty(boolean invalidateParent, boolean forceRedraw) { 15532 if (!isHardwareAccelerated() 15533 || !mRenderNode.isValid() 15534 || (mPrivateFlags & PFLAG_DRAW_ANIMATION) != 0) { 15535 if (invalidateParent) { 15536 invalidateParentCaches(); 15537 } 15538 if (forceRedraw) { 15539 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 15540 } 15541 invalidate(false); 15542 } else { 15543 damageInParent(); 15544 } 15545 } 15546 15547 /** 15548 * Tells the parent view to damage this view's bounds. 15549 * 15550 * @hide 15551 */ 15552 protected void damageInParent() { 15553 if (mParent != null && mAttachInfo != null) { 15554 mParent.onDescendantInvalidated(this, this); 15555 } 15556 } 15557 15558 /** 15559 * Utility method to transform a given Rect by the current matrix of this view. 15560 */ 15561 void transformRect(final Rect rect) { 15562 if (!getMatrix().isIdentity()) { 15563 RectF boundingRect = mAttachInfo.mTmpTransformRect; 15564 boundingRect.set(rect); 15565 getMatrix().mapRect(boundingRect); 15566 rect.set((int) Math.floor(boundingRect.left), 15567 (int) Math.floor(boundingRect.top), 15568 (int) Math.ceil(boundingRect.right), 15569 (int) Math.ceil(boundingRect.bottom)); 15570 } 15571 } 15572 15573 /** 15574 * Used to indicate that the parent of this view should clear its caches. This functionality 15575 * is used to force the parent to rebuild its display list (when hardware-accelerated), 15576 * which is necessary when various parent-managed properties of the view change, such as 15577 * alpha, translationX/Y, scrollX/Y, scaleX/Y, and rotation/X/Y. This method only 15578 * clears the parent caches and does not causes an invalidate event. 15579 * 15580 * @hide 15581 */ 15582 protected void invalidateParentCaches() { 15583 if (mParent instanceof View) { 15584 ((View) mParent).mPrivateFlags |= PFLAG_INVALIDATED; 15585 } 15586 } 15587 15588 /** 15589 * Used to indicate that the parent of this view should be invalidated. This functionality 15590 * is used to force the parent to rebuild its display list (when hardware-accelerated), 15591 * which is necessary when various parent-managed properties of the view change, such as 15592 * alpha, translationX/Y, scrollX/Y, scaleX/Y, and rotation/X/Y. This method will propagate 15593 * an invalidation event to the parent. 15594 * 15595 * @hide 15596 */ 15597 protected void invalidateParentIfNeeded() { 15598 if (isHardwareAccelerated() && mParent instanceof View) { 15599 ((View) mParent).invalidate(true); 15600 } 15601 } 15602 15603 /** 15604 * @hide 15605 */ 15606 protected void invalidateParentIfNeededAndWasQuickRejected() { 15607 if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) != 0) { 15608 // View was rejected last time it was drawn by its parent; this may have changed 15609 invalidateParentIfNeeded(); 15610 } 15611 } 15612 15613 /** 15614 * Indicates whether this View is opaque. An opaque View guarantees that it will 15615 * draw all the pixels overlapping its bounds using a fully opaque color. 15616 * 15617 * Subclasses of View should override this method whenever possible to indicate 15618 * whether an instance is opaque. Opaque Views are treated in a special way by 15619 * the View hierarchy, possibly allowing it to perform optimizations during 15620 * invalidate/draw passes. 15621 * 15622 * @return True if this View is guaranteed to be fully opaque, false otherwise. 15623 */ 15624 @ViewDebug.ExportedProperty(category = "drawing") 15625 public boolean isOpaque() { 15626 return (mPrivateFlags & PFLAG_OPAQUE_MASK) == PFLAG_OPAQUE_MASK && 15627 getFinalAlpha() >= 1.0f; 15628 } 15629 15630 /** 15631 * @hide 15632 */ 15633 protected void computeOpaqueFlags() { 15634 // Opaque if: 15635 // - Has a background 15636 // - Background is opaque 15637 // - Doesn't have scrollbars or scrollbars overlay 15638 15639 if (mBackground != null && mBackground.getOpacity() == PixelFormat.OPAQUE) { 15640 mPrivateFlags |= PFLAG_OPAQUE_BACKGROUND; 15641 } else { 15642 mPrivateFlags &= ~PFLAG_OPAQUE_BACKGROUND; 15643 } 15644 15645 final int flags = mViewFlags; 15646 if (((flags & SCROLLBARS_VERTICAL) == 0 && (flags & SCROLLBARS_HORIZONTAL) == 0) || 15647 (flags & SCROLLBARS_STYLE_MASK) == SCROLLBARS_INSIDE_OVERLAY || 15648 (flags & SCROLLBARS_STYLE_MASK) == SCROLLBARS_OUTSIDE_OVERLAY) { 15649 mPrivateFlags |= PFLAG_OPAQUE_SCROLLBARS; 15650 } else { 15651 mPrivateFlags &= ~PFLAG_OPAQUE_SCROLLBARS; 15652 } 15653 } 15654 15655 /** 15656 * @hide 15657 */ 15658 protected boolean hasOpaqueScrollbars() { 15659 return (mPrivateFlags & PFLAG_OPAQUE_SCROLLBARS) == PFLAG_OPAQUE_SCROLLBARS; 15660 } 15661 15662 /** 15663 * @return A handler associated with the thread running the View. This 15664 * handler can be used to pump events in the UI events queue. 15665 */ 15666 public Handler getHandler() { 15667 final AttachInfo attachInfo = mAttachInfo; 15668 if (attachInfo != null) { 15669 return attachInfo.mHandler; 15670 } 15671 return null; 15672 } 15673 15674 /** 15675 * Returns the queue of runnable for this view. 15676 * 15677 * @return the queue of runnables for this view 15678 */ 15679 private HandlerActionQueue getRunQueue() { 15680 if (mRunQueue == null) { 15681 mRunQueue = new HandlerActionQueue(); 15682 } 15683 return mRunQueue; 15684 } 15685 15686 /** 15687 * Gets the view root associated with the View. 15688 * @return The view root, or null if none. 15689 * @hide 15690 */ 15691 public ViewRootImpl getViewRootImpl() { 15692 if (mAttachInfo != null) { 15693 return mAttachInfo.mViewRootImpl; 15694 } 15695 return null; 15696 } 15697 15698 /** 15699 * @hide 15700 */ 15701 public ThreadedRenderer getThreadedRenderer() { 15702 return mAttachInfo != null ? mAttachInfo.mThreadedRenderer : null; 15703 } 15704 15705 /** 15706 * <p>Causes the Runnable to be added to the message queue. 15707 * The runnable will be run on the user interface thread.</p> 15708 * 15709 * @param action The Runnable that will be executed. 15710 * 15711 * @return Returns true if the Runnable was successfully placed in to the 15712 * message queue. Returns false on failure, usually because the 15713 * looper processing the message queue is exiting. 15714 * 15715 * @see #postDelayed 15716 * @see #removeCallbacks 15717 */ 15718 public boolean post(Runnable action) { 15719 final AttachInfo attachInfo = mAttachInfo; 15720 if (attachInfo != null) { 15721 return attachInfo.mHandler.post(action); 15722 } 15723 15724 // Postpone the runnable until we know on which thread it needs to run. 15725 // Assume that the runnable will be successfully placed after attach. 15726 getRunQueue().post(action); 15727 return true; 15728 } 15729 15730 /** 15731 * <p>Causes the Runnable to be added to the message queue, to be run 15732 * after the specified amount of time elapses. 15733 * The runnable will be run on the user interface thread.</p> 15734 * 15735 * @param action The Runnable that will be executed. 15736 * @param delayMillis The delay (in milliseconds) until the Runnable 15737 * will be executed. 15738 * 15739 * @return true if the Runnable was successfully placed in to the 15740 * message queue. Returns false on failure, usually because the 15741 * looper processing the message queue is exiting. Note that a 15742 * result of true does not mean the Runnable will be processed -- 15743 * if the looper is quit before the delivery time of the message 15744 * occurs then the message will be dropped. 15745 * 15746 * @see #post 15747 * @see #removeCallbacks 15748 */ 15749 public boolean postDelayed(Runnable action, long delayMillis) { 15750 final AttachInfo attachInfo = mAttachInfo; 15751 if (attachInfo != null) { 15752 return attachInfo.mHandler.postDelayed(action, delayMillis); 15753 } 15754 15755 // Postpone the runnable until we know on which thread it needs to run. 15756 // Assume that the runnable will be successfully placed after attach. 15757 getRunQueue().postDelayed(action, delayMillis); 15758 return true; 15759 } 15760 15761 /** 15762 * <p>Causes the Runnable to execute on the next animation time step. 15763 * The runnable will be run on the user interface thread.</p> 15764 * 15765 * @param action The Runnable that will be executed. 15766 * 15767 * @see #postOnAnimationDelayed 15768 * @see #removeCallbacks 15769 */ 15770 public void postOnAnimation(Runnable action) { 15771 final AttachInfo attachInfo = mAttachInfo; 15772 if (attachInfo != null) { 15773 attachInfo.mViewRootImpl.mChoreographer.postCallback( 15774 Choreographer.CALLBACK_ANIMATION, action, null); 15775 } else { 15776 // Postpone the runnable until we know 15777 // on which thread it needs to run. 15778 getRunQueue().post(action); 15779 } 15780 } 15781 15782 /** 15783 * <p>Causes the Runnable to execute on the next animation time step, 15784 * after the specified amount of time elapses. 15785 * The runnable will be run on the user interface thread.</p> 15786 * 15787 * @param action The Runnable that will be executed. 15788 * @param delayMillis The delay (in milliseconds) until the Runnable 15789 * will be executed. 15790 * 15791 * @see #postOnAnimation 15792 * @see #removeCallbacks 15793 */ 15794 public void postOnAnimationDelayed(Runnable action, long delayMillis) { 15795 final AttachInfo attachInfo = mAttachInfo; 15796 if (attachInfo != null) { 15797 attachInfo.mViewRootImpl.mChoreographer.postCallbackDelayed( 15798 Choreographer.CALLBACK_ANIMATION, action, null, delayMillis); 15799 } else { 15800 // Postpone the runnable until we know 15801 // on which thread it needs to run. 15802 getRunQueue().postDelayed(action, delayMillis); 15803 } 15804 } 15805 15806 /** 15807 * <p>Removes the specified Runnable from the message queue.</p> 15808 * 15809 * @param action The Runnable to remove from the message handling queue 15810 * 15811 * @return true if this view could ask the Handler to remove the Runnable, 15812 * false otherwise. When the returned value is true, the Runnable 15813 * may or may not have been actually removed from the message queue 15814 * (for instance, if the Runnable was not in the queue already.) 15815 * 15816 * @see #post 15817 * @see #postDelayed 15818 * @see #postOnAnimation 15819 * @see #postOnAnimationDelayed 15820 */ 15821 public boolean removeCallbacks(Runnable action) { 15822 if (action != null) { 15823 final AttachInfo attachInfo = mAttachInfo; 15824 if (attachInfo != null) { 15825 attachInfo.mHandler.removeCallbacks(action); 15826 attachInfo.mViewRootImpl.mChoreographer.removeCallbacks( 15827 Choreographer.CALLBACK_ANIMATION, action, null); 15828 } 15829 getRunQueue().removeCallbacks(action); 15830 } 15831 return true; 15832 } 15833 15834 /** 15835 * <p>Cause an invalidate to happen on a subsequent cycle through the event loop. 15836 * Use this to invalidate the View from a non-UI thread.</p> 15837 * 15838 * <p>This method can be invoked from outside of the UI thread 15839 * only when this View is attached to a window.</p> 15840 * 15841 * @see #invalidate() 15842 * @see #postInvalidateDelayed(long) 15843 */ 15844 public void postInvalidate() { 15845 postInvalidateDelayed(0); 15846 } 15847 15848 /** 15849 * <p>Cause an invalidate of the specified area to happen on a subsequent cycle 15850 * through the event loop. Use this to invalidate the View from a non-UI thread.</p> 15851 * 15852 * <p>This method can be invoked from outside of the UI thread 15853 * only when this View is attached to a window.</p> 15854 * 15855 * @param left The left coordinate of the rectangle to invalidate. 15856 * @param top The top coordinate of the rectangle to invalidate. 15857 * @param right The right coordinate of the rectangle to invalidate. 15858 * @param bottom The bottom coordinate of the rectangle to invalidate. 15859 * 15860 * @see #invalidate(int, int, int, int) 15861 * @see #invalidate(Rect) 15862 * @see #postInvalidateDelayed(long, int, int, int, int) 15863 */ 15864 public void postInvalidate(int left, int top, int right, int bottom) { 15865 postInvalidateDelayed(0, left, top, right, bottom); 15866 } 15867 15868 /** 15869 * <p>Cause an invalidate to happen on a subsequent cycle through the event 15870 * loop. Waits for the specified amount of time.</p> 15871 * 15872 * <p>This method can be invoked from outside of the UI thread 15873 * only when this View is attached to a window.</p> 15874 * 15875 * @param delayMilliseconds the duration in milliseconds to delay the 15876 * invalidation by 15877 * 15878 * @see #invalidate() 15879 * @see #postInvalidate() 15880 */ 15881 public void postInvalidateDelayed(long delayMilliseconds) { 15882 // We try only with the AttachInfo because there's no point in invalidating 15883 // if we are not attached to our window 15884 final AttachInfo attachInfo = mAttachInfo; 15885 if (attachInfo != null) { 15886 attachInfo.mViewRootImpl.dispatchInvalidateDelayed(this, delayMilliseconds); 15887 } 15888 } 15889 15890 /** 15891 * <p>Cause an invalidate of the specified area to happen on a subsequent cycle 15892 * through the event loop. Waits for the specified amount of time.</p> 15893 * 15894 * <p>This method can be invoked from outside of the UI thread 15895 * only when this View is attached to a window.</p> 15896 * 15897 * @param delayMilliseconds the duration in milliseconds to delay the 15898 * invalidation by 15899 * @param left The left coordinate of the rectangle to invalidate. 15900 * @param top The top coordinate of the rectangle to invalidate. 15901 * @param right The right coordinate of the rectangle to invalidate. 15902 * @param bottom The bottom coordinate of the rectangle to invalidate. 15903 * 15904 * @see #invalidate(int, int, int, int) 15905 * @see #invalidate(Rect) 15906 * @see #postInvalidate(int, int, int, int) 15907 */ 15908 public void postInvalidateDelayed(long delayMilliseconds, int left, int top, 15909 int right, int bottom) { 15910 15911 // We try only with the AttachInfo because there's no point in invalidating 15912 // if we are not attached to our window 15913 final AttachInfo attachInfo = mAttachInfo; 15914 if (attachInfo != null) { 15915 final AttachInfo.InvalidateInfo info = AttachInfo.InvalidateInfo.obtain(); 15916 info.target = this; 15917 info.left = left; 15918 info.top = top; 15919 info.right = right; 15920 info.bottom = bottom; 15921 15922 attachInfo.mViewRootImpl.dispatchInvalidateRectDelayed(info, delayMilliseconds); 15923 } 15924 } 15925 15926 /** 15927 * <p>Cause an invalidate to happen on the next animation time step, typically the 15928 * next display frame.</p> 15929 * 15930 * <p>This method can be invoked from outside of the UI thread 15931 * only when this View is attached to a window.</p> 15932 * 15933 * @see #invalidate() 15934 */ 15935 public void postInvalidateOnAnimation() { 15936 // We try only with the AttachInfo because there's no point in invalidating 15937 // if we are not attached to our window 15938 final AttachInfo attachInfo = mAttachInfo; 15939 if (attachInfo != null) { 15940 attachInfo.mViewRootImpl.dispatchInvalidateOnAnimation(this); 15941 } 15942 } 15943 15944 /** 15945 * <p>Cause an invalidate of the specified area to happen on the next animation 15946 * time step, typically the next display frame.</p> 15947 * 15948 * <p>This method can be invoked from outside of the UI thread 15949 * only when this View is attached to a window.</p> 15950 * 15951 * @param left The left coordinate of the rectangle to invalidate. 15952 * @param top The top coordinate of the rectangle to invalidate. 15953 * @param right The right coordinate of the rectangle to invalidate. 15954 * @param bottom The bottom coordinate of the rectangle to invalidate. 15955 * 15956 * @see #invalidate(int, int, int, int) 15957 * @see #invalidate(Rect) 15958 */ 15959 public void postInvalidateOnAnimation(int left, int top, int right, int bottom) { 15960 // We try only with the AttachInfo because there's no point in invalidating 15961 // if we are not attached to our window 15962 final AttachInfo attachInfo = mAttachInfo; 15963 if (attachInfo != null) { 15964 final AttachInfo.InvalidateInfo info = AttachInfo.InvalidateInfo.obtain(); 15965 info.target = this; 15966 info.left = left; 15967 info.top = top; 15968 info.right = right; 15969 info.bottom = bottom; 15970 15971 attachInfo.mViewRootImpl.dispatchInvalidateRectOnAnimation(info); 15972 } 15973 } 15974 15975 /** 15976 * Post a callback to send a {@link AccessibilityEvent#TYPE_VIEW_SCROLLED} event. 15977 * This event is sent at most once every 15978 * {@link ViewConfiguration#getSendRecurringAccessibilityEventsInterval()}. 15979 */ 15980 private void postSendViewScrolledAccessibilityEventCallback() { 15981 if (mSendViewScrolledAccessibilityEvent == null) { 15982 mSendViewScrolledAccessibilityEvent = new SendViewScrolledAccessibilityEvent(); 15983 } 15984 if (!mSendViewScrolledAccessibilityEvent.mIsPending) { 15985 mSendViewScrolledAccessibilityEvent.mIsPending = true; 15986 postDelayed(mSendViewScrolledAccessibilityEvent, 15987 ViewConfiguration.getSendRecurringAccessibilityEventsInterval()); 15988 } 15989 } 15990 15991 /** 15992 * Called by a parent to request that a child update its values for mScrollX 15993 * and mScrollY if necessary. This will typically be done if the child is 15994 * animating a scroll using a {@link android.widget.Scroller Scroller} 15995 * object. 15996 */ 15997 public void computeScroll() { 15998 } 15999 16000 /** 16001 * <p>Indicate whether the horizontal edges are faded when the view is 16002 * scrolled horizontally.</p> 16003 * 16004 * @return true if the horizontal edges should are faded on scroll, false 16005 * otherwise 16006 * 16007 * @see #setHorizontalFadingEdgeEnabled(boolean) 16008 * 16009 * @attr ref android.R.styleable#View_requiresFadingEdge 16010 */ 16011 public boolean isHorizontalFadingEdgeEnabled() { 16012 return (mViewFlags & FADING_EDGE_HORIZONTAL) == FADING_EDGE_HORIZONTAL; 16013 } 16014 16015 /** 16016 * <p>Define whether the horizontal edges should be faded when this view 16017 * is scrolled horizontally.</p> 16018 * 16019 * @param horizontalFadingEdgeEnabled true if the horizontal edges should 16020 * be faded when the view is scrolled 16021 * horizontally 16022 * 16023 * @see #isHorizontalFadingEdgeEnabled() 16024 * 16025 * @attr ref android.R.styleable#View_requiresFadingEdge 16026 */ 16027 public void setHorizontalFadingEdgeEnabled(boolean horizontalFadingEdgeEnabled) { 16028 if (isHorizontalFadingEdgeEnabled() != horizontalFadingEdgeEnabled) { 16029 if (horizontalFadingEdgeEnabled) { 16030 initScrollCache(); 16031 } 16032 16033 mViewFlags ^= FADING_EDGE_HORIZONTAL; 16034 } 16035 } 16036 16037 /** 16038 * <p>Indicate whether the vertical edges are faded when the view is 16039 * scrolled horizontally.</p> 16040 * 16041 * @return true if the vertical edges should are faded on scroll, false 16042 * otherwise 16043 * 16044 * @see #setVerticalFadingEdgeEnabled(boolean) 16045 * 16046 * @attr ref android.R.styleable#View_requiresFadingEdge 16047 */ 16048 public boolean isVerticalFadingEdgeEnabled() { 16049 return (mViewFlags & FADING_EDGE_VERTICAL) == FADING_EDGE_VERTICAL; 16050 } 16051 16052 /** 16053 * <p>Define whether the vertical edges should be faded when this view 16054 * is scrolled vertically.</p> 16055 * 16056 * @param verticalFadingEdgeEnabled true if the vertical edges should 16057 * be faded when the view is scrolled 16058 * vertically 16059 * 16060 * @see #isVerticalFadingEdgeEnabled() 16061 * 16062 * @attr ref android.R.styleable#View_requiresFadingEdge 16063 */ 16064 public void setVerticalFadingEdgeEnabled(boolean verticalFadingEdgeEnabled) { 16065 if (isVerticalFadingEdgeEnabled() != verticalFadingEdgeEnabled) { 16066 if (verticalFadingEdgeEnabled) { 16067 initScrollCache(); 16068 } 16069 16070 mViewFlags ^= FADING_EDGE_VERTICAL; 16071 } 16072 } 16073 16074 /** 16075 * Returns the strength, or intensity, of the top faded edge. The strength is 16076 * a value between 0.0 (no fade) and 1.0 (full fade). The default implementation 16077 * returns 0.0 or 1.0 but no value in between. 16078 * 16079 * Subclasses should override this method to provide a smoother fade transition 16080 * when scrolling occurs. 16081 * 16082 * @return the intensity of the top fade as a float between 0.0f and 1.0f 16083 */ 16084 protected float getTopFadingEdgeStrength() { 16085 return computeVerticalScrollOffset() > 0 ? 1.0f : 0.0f; 16086 } 16087 16088 /** 16089 * Returns the strength, or intensity, of the bottom faded edge. The strength is 16090 * a value between 0.0 (no fade) and 1.0 (full fade). The default implementation 16091 * returns 0.0 or 1.0 but no value in between. 16092 * 16093 * Subclasses should override this method to provide a smoother fade transition 16094 * when scrolling occurs. 16095 * 16096 * @return the intensity of the bottom fade as a float between 0.0f and 1.0f 16097 */ 16098 protected float getBottomFadingEdgeStrength() { 16099 return computeVerticalScrollOffset() + computeVerticalScrollExtent() < 16100 computeVerticalScrollRange() ? 1.0f : 0.0f; 16101 } 16102 16103 /** 16104 * Returns the strength, or intensity, of the left faded edge. The strength is 16105 * a value between 0.0 (no fade) and 1.0 (full fade). The default implementation 16106 * returns 0.0 or 1.0 but no value in between. 16107 * 16108 * Subclasses should override this method to provide a smoother fade transition 16109 * when scrolling occurs. 16110 * 16111 * @return the intensity of the left fade as a float between 0.0f and 1.0f 16112 */ 16113 protected float getLeftFadingEdgeStrength() { 16114 return computeHorizontalScrollOffset() > 0 ? 1.0f : 0.0f; 16115 } 16116 16117 /** 16118 * Returns the strength, or intensity, of the right faded edge. The strength is 16119 * a value between 0.0 (no fade) and 1.0 (full fade). The default implementation 16120 * returns 0.0 or 1.0 but no value in between. 16121 * 16122 * Subclasses should override this method to provide a smoother fade transition 16123 * when scrolling occurs. 16124 * 16125 * @return the intensity of the right fade as a float between 0.0f and 1.0f 16126 */ 16127 protected float getRightFadingEdgeStrength() { 16128 return computeHorizontalScrollOffset() + computeHorizontalScrollExtent() < 16129 computeHorizontalScrollRange() ? 1.0f : 0.0f; 16130 } 16131 16132 /** 16133 * <p>Indicate whether the horizontal scrollbar should be drawn or not. The 16134 * scrollbar is not drawn by default.</p> 16135 * 16136 * @return true if the horizontal scrollbar should be painted, false 16137 * otherwise 16138 * 16139 * @see #setHorizontalScrollBarEnabled(boolean) 16140 */ 16141 public boolean isHorizontalScrollBarEnabled() { 16142 return (mViewFlags & SCROLLBARS_HORIZONTAL) == SCROLLBARS_HORIZONTAL; 16143 } 16144 16145 /** 16146 * <p>Define whether the horizontal scrollbar should be drawn or not. The 16147 * scrollbar is not drawn by default.</p> 16148 * 16149 * @param horizontalScrollBarEnabled true if the horizontal scrollbar should 16150 * be painted 16151 * 16152 * @see #isHorizontalScrollBarEnabled() 16153 */ 16154 public void setHorizontalScrollBarEnabled(boolean horizontalScrollBarEnabled) { 16155 if (isHorizontalScrollBarEnabled() != horizontalScrollBarEnabled) { 16156 mViewFlags ^= SCROLLBARS_HORIZONTAL; 16157 computeOpaqueFlags(); 16158 resolvePadding(); 16159 } 16160 } 16161 16162 /** 16163 * <p>Indicate whether the vertical scrollbar should be drawn or not. The 16164 * scrollbar is not drawn by default.</p> 16165 * 16166 * @return true if the vertical scrollbar should be painted, false 16167 * otherwise 16168 * 16169 * @see #setVerticalScrollBarEnabled(boolean) 16170 */ 16171 public boolean isVerticalScrollBarEnabled() { 16172 return (mViewFlags & SCROLLBARS_VERTICAL) == SCROLLBARS_VERTICAL; 16173 } 16174 16175 /** 16176 * <p>Define whether the vertical scrollbar should be drawn or not. The 16177 * scrollbar is not drawn by default.</p> 16178 * 16179 * @param verticalScrollBarEnabled true if the vertical scrollbar should 16180 * be painted 16181 * 16182 * @see #isVerticalScrollBarEnabled() 16183 */ 16184 public void setVerticalScrollBarEnabled(boolean verticalScrollBarEnabled) { 16185 if (isVerticalScrollBarEnabled() != verticalScrollBarEnabled) { 16186 mViewFlags ^= SCROLLBARS_VERTICAL; 16187 computeOpaqueFlags(); 16188 resolvePadding(); 16189 } 16190 } 16191 16192 /** 16193 * @hide 16194 */ 16195 protected void recomputePadding() { 16196 internalSetPadding(mUserPaddingLeft, mPaddingTop, mUserPaddingRight, mUserPaddingBottom); 16197 } 16198 16199 /** 16200 * Define whether scrollbars will fade when the view is not scrolling. 16201 * 16202 * @param fadeScrollbars whether to enable fading 16203 * 16204 * @attr ref android.R.styleable#View_fadeScrollbars 16205 */ 16206 public void setScrollbarFadingEnabled(boolean fadeScrollbars) { 16207 initScrollCache(); 16208 final ScrollabilityCache scrollabilityCache = mScrollCache; 16209 scrollabilityCache.fadeScrollBars = fadeScrollbars; 16210 if (fadeScrollbars) { 16211 scrollabilityCache.state = ScrollabilityCache.OFF; 16212 } else { 16213 scrollabilityCache.state = ScrollabilityCache.ON; 16214 } 16215 } 16216 16217 /** 16218 * 16219 * Returns true if scrollbars will fade when this view is not scrolling 16220 * 16221 * @return true if scrollbar fading is enabled 16222 * 16223 * @attr ref android.R.styleable#View_fadeScrollbars 16224 */ 16225 public boolean isScrollbarFadingEnabled() { 16226 return mScrollCache != null && mScrollCache.fadeScrollBars; 16227 } 16228 16229 /** 16230 * 16231 * Returns the delay before scrollbars fade. 16232 * 16233 * @return the delay before scrollbars fade 16234 * 16235 * @attr ref android.R.styleable#View_scrollbarDefaultDelayBeforeFade 16236 */ 16237 public int getScrollBarDefaultDelayBeforeFade() { 16238 return mScrollCache == null ? ViewConfiguration.getScrollDefaultDelay() : 16239 mScrollCache.scrollBarDefaultDelayBeforeFade; 16240 } 16241 16242 /** 16243 * Define the delay before scrollbars fade. 16244 * 16245 * @param scrollBarDefaultDelayBeforeFade - the delay before scrollbars fade 16246 * 16247 * @attr ref android.R.styleable#View_scrollbarDefaultDelayBeforeFade 16248 */ 16249 public void setScrollBarDefaultDelayBeforeFade(int scrollBarDefaultDelayBeforeFade) { 16250 getScrollCache().scrollBarDefaultDelayBeforeFade = scrollBarDefaultDelayBeforeFade; 16251 } 16252 16253 /** 16254 * 16255 * Returns the scrollbar fade duration. 16256 * 16257 * @return the scrollbar fade duration, in milliseconds 16258 * 16259 * @attr ref android.R.styleable#View_scrollbarFadeDuration 16260 */ 16261 public int getScrollBarFadeDuration() { 16262 return mScrollCache == null ? ViewConfiguration.getScrollBarFadeDuration() : 16263 mScrollCache.scrollBarFadeDuration; 16264 } 16265 16266 /** 16267 * Define the scrollbar fade duration. 16268 * 16269 * @param scrollBarFadeDuration - the scrollbar fade duration, in milliseconds 16270 * 16271 * @attr ref android.R.styleable#View_scrollbarFadeDuration 16272 */ 16273 public void setScrollBarFadeDuration(int scrollBarFadeDuration) { 16274 getScrollCache().scrollBarFadeDuration = scrollBarFadeDuration; 16275 } 16276 16277 /** 16278 * 16279 * Returns the scrollbar size. 16280 * 16281 * @return the scrollbar size 16282 * 16283 * @attr ref android.R.styleable#View_scrollbarSize 16284 */ 16285 public int getScrollBarSize() { 16286 return mScrollCache == null ? ViewConfiguration.get(mContext).getScaledScrollBarSize() : 16287 mScrollCache.scrollBarSize; 16288 } 16289 16290 /** 16291 * Define the scrollbar size. 16292 * 16293 * @param scrollBarSize - the scrollbar size 16294 * 16295 * @attr ref android.R.styleable#View_scrollbarSize 16296 */ 16297 public void setScrollBarSize(int scrollBarSize) { 16298 getScrollCache().scrollBarSize = scrollBarSize; 16299 } 16300 16301 /** 16302 * <p>Specify the style of the scrollbars. The scrollbars can be overlaid or 16303 * inset. When inset, they add to the padding of the view. And the scrollbars 16304 * can be drawn inside the padding area or on the edge of the view. For example, 16305 * if a view has a background drawable and you want to draw the scrollbars 16306 * inside the padding specified by the drawable, you can use 16307 * SCROLLBARS_INSIDE_OVERLAY or SCROLLBARS_INSIDE_INSET. If you want them to 16308 * appear at the edge of the view, ignoring the padding, then you can use 16309 * SCROLLBARS_OUTSIDE_OVERLAY or SCROLLBARS_OUTSIDE_INSET.</p> 16310 * @param style the style of the scrollbars. Should be one of 16311 * SCROLLBARS_INSIDE_OVERLAY, SCROLLBARS_INSIDE_INSET, 16312 * SCROLLBARS_OUTSIDE_OVERLAY or SCROLLBARS_OUTSIDE_INSET. 16313 * @see #SCROLLBARS_INSIDE_OVERLAY 16314 * @see #SCROLLBARS_INSIDE_INSET 16315 * @see #SCROLLBARS_OUTSIDE_OVERLAY 16316 * @see #SCROLLBARS_OUTSIDE_INSET 16317 * 16318 * @attr ref android.R.styleable#View_scrollbarStyle 16319 */ 16320 public void setScrollBarStyle(@ScrollBarStyle int style) { 16321 if (style != (mViewFlags & SCROLLBARS_STYLE_MASK)) { 16322 mViewFlags = (mViewFlags & ~SCROLLBARS_STYLE_MASK) | (style & SCROLLBARS_STYLE_MASK); 16323 computeOpaqueFlags(); 16324 resolvePadding(); 16325 } 16326 } 16327 16328 /** 16329 * <p>Returns the current scrollbar style.</p> 16330 * @return the current scrollbar style 16331 * @see #SCROLLBARS_INSIDE_OVERLAY 16332 * @see #SCROLLBARS_INSIDE_INSET 16333 * @see #SCROLLBARS_OUTSIDE_OVERLAY 16334 * @see #SCROLLBARS_OUTSIDE_INSET 16335 * 16336 * @attr ref android.R.styleable#View_scrollbarStyle 16337 */ 16338 @ViewDebug.ExportedProperty(mapping = { 16339 @ViewDebug.IntToString(from = SCROLLBARS_INSIDE_OVERLAY, to = "INSIDE_OVERLAY"), 16340 @ViewDebug.IntToString(from = SCROLLBARS_INSIDE_INSET, to = "INSIDE_INSET"), 16341 @ViewDebug.IntToString(from = SCROLLBARS_OUTSIDE_OVERLAY, to = "OUTSIDE_OVERLAY"), 16342 @ViewDebug.IntToString(from = SCROLLBARS_OUTSIDE_INSET, to = "OUTSIDE_INSET") 16343 }) 16344 @ScrollBarStyle 16345 public int getScrollBarStyle() { 16346 return mViewFlags & SCROLLBARS_STYLE_MASK; 16347 } 16348 16349 /** 16350 * <p>Compute the horizontal range that the horizontal scrollbar 16351 * represents.</p> 16352 * 16353 * <p>The range is expressed in arbitrary units that must be the same as the 16354 * units used by {@link #computeHorizontalScrollExtent()} and 16355 * {@link #computeHorizontalScrollOffset()}.</p> 16356 * 16357 * <p>The default range is the drawing width of this view.</p> 16358 * 16359 * @return the total horizontal range represented by the horizontal 16360 * scrollbar 16361 * 16362 * @see #computeHorizontalScrollExtent() 16363 * @see #computeHorizontalScrollOffset() 16364 * @see android.widget.ScrollBarDrawable 16365 */ 16366 protected int computeHorizontalScrollRange() { 16367 return getWidth(); 16368 } 16369 16370 /** 16371 * <p>Compute the horizontal offset of the horizontal scrollbar's thumb 16372 * within the horizontal range. This value is used to compute the position 16373 * of the thumb within the scrollbar's track.</p> 16374 * 16375 * <p>The range is expressed in arbitrary units that must be the same as the 16376 * units used by {@link #computeHorizontalScrollRange()} and 16377 * {@link #computeHorizontalScrollExtent()}.</p> 16378 * 16379 * <p>The default offset is the scroll offset of this view.</p> 16380 * 16381 * @return the horizontal offset of the scrollbar's thumb 16382 * 16383 * @see #computeHorizontalScrollRange() 16384 * @see #computeHorizontalScrollExtent() 16385 * @see android.widget.ScrollBarDrawable 16386 */ 16387 protected int computeHorizontalScrollOffset() { 16388 return mScrollX; 16389 } 16390 16391 /** 16392 * <p>Compute the horizontal extent of the horizontal scrollbar's thumb 16393 * within the horizontal range. This value is used to compute the length 16394 * of the thumb within the scrollbar's track.</p> 16395 * 16396 * <p>The range is expressed in arbitrary units that must be the same as the 16397 * units used by {@link #computeHorizontalScrollRange()} and 16398 * {@link #computeHorizontalScrollOffset()}.</p> 16399 * 16400 * <p>The default extent is the drawing width of this view.</p> 16401 * 16402 * @return the horizontal extent of the scrollbar's thumb 16403 * 16404 * @see #computeHorizontalScrollRange() 16405 * @see #computeHorizontalScrollOffset() 16406 * @see android.widget.ScrollBarDrawable 16407 */ 16408 protected int computeHorizontalScrollExtent() { 16409 return getWidth(); 16410 } 16411 16412 /** 16413 * <p>Compute the vertical range that the vertical scrollbar represents.</p> 16414 * 16415 * <p>The range is expressed in arbitrary units that must be the same as the 16416 * units used by {@link #computeVerticalScrollExtent()} and 16417 * {@link #computeVerticalScrollOffset()}.</p> 16418 * 16419 * @return the total vertical range represented by the vertical scrollbar 16420 * 16421 * <p>The default range is the drawing height of this view.</p> 16422 * 16423 * @see #computeVerticalScrollExtent() 16424 * @see #computeVerticalScrollOffset() 16425 * @see android.widget.ScrollBarDrawable 16426 */ 16427 protected int computeVerticalScrollRange() { 16428 return getHeight(); 16429 } 16430 16431 /** 16432 * <p>Compute the vertical offset of the vertical scrollbar's thumb 16433 * within the horizontal range. This value is used to compute the position 16434 * of the thumb within the scrollbar's track.</p> 16435 * 16436 * <p>The range is expressed in arbitrary units that must be the same as the 16437 * units used by {@link #computeVerticalScrollRange()} and 16438 * {@link #computeVerticalScrollExtent()}.</p> 16439 * 16440 * <p>The default offset is the scroll offset of this view.</p> 16441 * 16442 * @return the vertical offset of the scrollbar's thumb 16443 * 16444 * @see #computeVerticalScrollRange() 16445 * @see #computeVerticalScrollExtent() 16446 * @see android.widget.ScrollBarDrawable 16447 */ 16448 protected int computeVerticalScrollOffset() { 16449 return mScrollY; 16450 } 16451 16452 /** 16453 * <p>Compute the vertical extent of the vertical scrollbar's thumb 16454 * within the vertical range. This value is used to compute the length 16455 * of the thumb within the scrollbar's track.</p> 16456 * 16457 * <p>The range is expressed in arbitrary units that must be the same as the 16458 * units used by {@link #computeVerticalScrollRange()} and 16459 * {@link #computeVerticalScrollOffset()}.</p> 16460 * 16461 * <p>The default extent is the drawing height of this view.</p> 16462 * 16463 * @return the vertical extent of the scrollbar's thumb 16464 * 16465 * @see #computeVerticalScrollRange() 16466 * @see #computeVerticalScrollOffset() 16467 * @see android.widget.ScrollBarDrawable 16468 */ 16469 protected int computeVerticalScrollExtent() { 16470 return getHeight(); 16471 } 16472 16473 /** 16474 * Check if this view can be scrolled horizontally in a certain direction. 16475 * 16476 * @param direction Negative to check scrolling left, positive to check scrolling right. 16477 * @return true if this view can be scrolled in the specified direction, false otherwise. 16478 */ 16479 public boolean canScrollHorizontally(int direction) { 16480 final int offset = computeHorizontalScrollOffset(); 16481 final int range = computeHorizontalScrollRange() - computeHorizontalScrollExtent(); 16482 if (range == 0) return false; 16483 if (direction < 0) { 16484 return offset > 0; 16485 } else { 16486 return offset < range - 1; 16487 } 16488 } 16489 16490 /** 16491 * Check if this view can be scrolled vertically in a certain direction. 16492 * 16493 * @param direction Negative to check scrolling up, positive to check scrolling down. 16494 * @return true if this view can be scrolled in the specified direction, false otherwise. 16495 */ 16496 public boolean canScrollVertically(int direction) { 16497 final int offset = computeVerticalScrollOffset(); 16498 final int range = computeVerticalScrollRange() - computeVerticalScrollExtent(); 16499 if (range == 0) return false; 16500 if (direction < 0) { 16501 return offset > 0; 16502 } else { 16503 return offset < range - 1; 16504 } 16505 } 16506 16507 void getScrollIndicatorBounds(@NonNull Rect out) { 16508 out.left = mScrollX; 16509 out.right = mScrollX + mRight - mLeft; 16510 out.top = mScrollY; 16511 out.bottom = mScrollY + mBottom - mTop; 16512 } 16513 16514 private void onDrawScrollIndicators(Canvas c) { 16515 if ((mPrivateFlags3 & SCROLL_INDICATORS_PFLAG3_MASK) == 0) { 16516 // No scroll indicators enabled. 16517 return; 16518 } 16519 16520 final Drawable dr = mScrollIndicatorDrawable; 16521 if (dr == null) { 16522 // Scroll indicators aren't supported here. 16523 return; 16524 } 16525 16526 final int h = dr.getIntrinsicHeight(); 16527 final int w = dr.getIntrinsicWidth(); 16528 final Rect rect = mAttachInfo.mTmpInvalRect; 16529 getScrollIndicatorBounds(rect); 16530 16531 if ((mPrivateFlags3 & PFLAG3_SCROLL_INDICATOR_TOP) != 0) { 16532 final boolean canScrollUp = canScrollVertically(-1); 16533 if (canScrollUp) { 16534 dr.setBounds(rect.left, rect.top, rect.right, rect.top + h); 16535 dr.draw(c); 16536 } 16537 } 16538 16539 if ((mPrivateFlags3 & PFLAG3_SCROLL_INDICATOR_BOTTOM) != 0) { 16540 final boolean canScrollDown = canScrollVertically(1); 16541 if (canScrollDown) { 16542 dr.setBounds(rect.left, rect.bottom - h, rect.right, rect.bottom); 16543 dr.draw(c); 16544 } 16545 } 16546 16547 final int leftRtl; 16548 final int rightRtl; 16549 if (getLayoutDirection() == LAYOUT_DIRECTION_RTL) { 16550 leftRtl = PFLAG3_SCROLL_INDICATOR_END; 16551 rightRtl = PFLAG3_SCROLL_INDICATOR_START; 16552 } else { 16553 leftRtl = PFLAG3_SCROLL_INDICATOR_START; 16554 rightRtl = PFLAG3_SCROLL_INDICATOR_END; 16555 } 16556 16557 final int leftMask = PFLAG3_SCROLL_INDICATOR_LEFT | leftRtl; 16558 if ((mPrivateFlags3 & leftMask) != 0) { 16559 final boolean canScrollLeft = canScrollHorizontally(-1); 16560 if (canScrollLeft) { 16561 dr.setBounds(rect.left, rect.top, rect.left + w, rect.bottom); 16562 dr.draw(c); 16563 } 16564 } 16565 16566 final int rightMask = PFLAG3_SCROLL_INDICATOR_RIGHT | rightRtl; 16567 if ((mPrivateFlags3 & rightMask) != 0) { 16568 final boolean canScrollRight = canScrollHorizontally(1); 16569 if (canScrollRight) { 16570 dr.setBounds(rect.right - w, rect.top, rect.right, rect.bottom); 16571 dr.draw(c); 16572 } 16573 } 16574 } 16575 16576 private void getHorizontalScrollBarBounds(@Nullable Rect drawBounds, 16577 @Nullable Rect touchBounds) { 16578 final Rect bounds = drawBounds != null ? drawBounds : touchBounds; 16579 if (bounds == null) { 16580 return; 16581 } 16582 final int inside = (mViewFlags & SCROLLBARS_OUTSIDE_MASK) == 0 ? ~0 : 0; 16583 final boolean drawVerticalScrollBar = isVerticalScrollBarEnabled() 16584 && !isVerticalScrollBarHidden(); 16585 final int size = getHorizontalScrollbarHeight(); 16586 final int verticalScrollBarGap = drawVerticalScrollBar ? 16587 getVerticalScrollbarWidth() : 0; 16588 final int width = mRight - mLeft; 16589 final int height = mBottom - mTop; 16590 bounds.top = mScrollY + height - size - (mUserPaddingBottom & inside); 16591 bounds.left = mScrollX + (mPaddingLeft & inside); 16592 bounds.right = mScrollX + width - (mUserPaddingRight & inside) - verticalScrollBarGap; 16593 bounds.bottom = bounds.top + size; 16594 16595 if (touchBounds == null) { 16596 return; 16597 } 16598 if (touchBounds != bounds) { 16599 touchBounds.set(bounds); 16600 } 16601 final int minTouchTarget = mScrollCache.scrollBarMinTouchTarget; 16602 if (touchBounds.height() < minTouchTarget) { 16603 final int adjust = (minTouchTarget - touchBounds.height()) / 2; 16604 touchBounds.bottom = Math.min(touchBounds.bottom + adjust, mScrollY + height); 16605 touchBounds.top = touchBounds.bottom - minTouchTarget; 16606 } 16607 if (touchBounds.width() < minTouchTarget) { 16608 final int adjust = (minTouchTarget - touchBounds.width()) / 2; 16609 touchBounds.left -= adjust; 16610 touchBounds.right = touchBounds.left + minTouchTarget; 16611 } 16612 } 16613 16614 private void getVerticalScrollBarBounds(@Nullable Rect bounds, @Nullable Rect touchBounds) { 16615 if (mRoundScrollbarRenderer == null) { 16616 getStraightVerticalScrollBarBounds(bounds, touchBounds); 16617 } else { 16618 getRoundVerticalScrollBarBounds(bounds != null ? bounds : touchBounds); 16619 } 16620 } 16621 16622 private void getRoundVerticalScrollBarBounds(Rect bounds) { 16623 final int width = mRight - mLeft; 16624 final int height = mBottom - mTop; 16625 // Do not take padding into account as we always want the scrollbars 16626 // to hug the screen for round wearable devices. 16627 bounds.left = mScrollX; 16628 bounds.top = mScrollY; 16629 bounds.right = bounds.left + width; 16630 bounds.bottom = mScrollY + height; 16631 } 16632 16633 private void getStraightVerticalScrollBarBounds(@Nullable Rect drawBounds, 16634 @Nullable Rect touchBounds) { 16635 final Rect bounds = drawBounds != null ? drawBounds : touchBounds; 16636 if (bounds == null) { 16637 return; 16638 } 16639 final int inside = (mViewFlags & SCROLLBARS_OUTSIDE_MASK) == 0 ? ~0 : 0; 16640 final int size = getVerticalScrollbarWidth(); 16641 int verticalScrollbarPosition = mVerticalScrollbarPosition; 16642 if (verticalScrollbarPosition == SCROLLBAR_POSITION_DEFAULT) { 16643 verticalScrollbarPosition = isLayoutRtl() ? 16644 SCROLLBAR_POSITION_LEFT : SCROLLBAR_POSITION_RIGHT; 16645 } 16646 final int width = mRight - mLeft; 16647 final int height = mBottom - mTop; 16648 switch (verticalScrollbarPosition) { 16649 default: 16650 case SCROLLBAR_POSITION_RIGHT: 16651 bounds.left = mScrollX + width - size - (mUserPaddingRight & inside); 16652 break; 16653 case SCROLLBAR_POSITION_LEFT: 16654 bounds.left = mScrollX + (mUserPaddingLeft & inside); 16655 break; 16656 } 16657 bounds.top = mScrollY + (mPaddingTop & inside); 16658 bounds.right = bounds.left + size; 16659 bounds.bottom = mScrollY + height - (mUserPaddingBottom & inside); 16660 16661 if (touchBounds == null) { 16662 return; 16663 } 16664 if (touchBounds != bounds) { 16665 touchBounds.set(bounds); 16666 } 16667 final int minTouchTarget = mScrollCache.scrollBarMinTouchTarget; 16668 if (touchBounds.width() < minTouchTarget) { 16669 final int adjust = (minTouchTarget - touchBounds.width()) / 2; 16670 if (verticalScrollbarPosition == SCROLLBAR_POSITION_RIGHT) { 16671 touchBounds.right = Math.min(touchBounds.right + adjust, mScrollX + width); 16672 touchBounds.left = touchBounds.right - minTouchTarget; 16673 } else { 16674 touchBounds.left = Math.max(touchBounds.left + adjust, mScrollX); 16675 touchBounds.right = touchBounds.left + minTouchTarget; 16676 } 16677 } 16678 if (touchBounds.height() < minTouchTarget) { 16679 final int adjust = (minTouchTarget - touchBounds.height()) / 2; 16680 touchBounds.top -= adjust; 16681 touchBounds.bottom = touchBounds.top + minTouchTarget; 16682 } 16683 } 16684 16685 /** 16686 * <p>Request the drawing of the horizontal and the vertical scrollbar. The 16687 * scrollbars are painted only if they have been awakened first.</p> 16688 * 16689 * @param canvas the canvas on which to draw the scrollbars 16690 * 16691 * @see #awakenScrollBars(int) 16692 */ 16693 protected final void onDrawScrollBars(Canvas canvas) { 16694 // scrollbars are drawn only when the animation is running 16695 final ScrollabilityCache cache = mScrollCache; 16696 16697 if (cache != null) { 16698 16699 int state = cache.state; 16700 16701 if (state == ScrollabilityCache.OFF) { 16702 return; 16703 } 16704 16705 boolean invalidate = false; 16706 16707 if (state == ScrollabilityCache.FADING) { 16708 // We're fading -- get our fade interpolation 16709 if (cache.interpolatorValues == null) { 16710 cache.interpolatorValues = new float[1]; 16711 } 16712 16713 float[] values = cache.interpolatorValues; 16714 16715 // Stops the animation if we're done 16716 if (cache.scrollBarInterpolator.timeToValues(values) == 16717 Interpolator.Result.FREEZE_END) { 16718 cache.state = ScrollabilityCache.OFF; 16719 } else { 16720 cache.scrollBar.mutate().setAlpha(Math.round(values[0])); 16721 } 16722 16723 // This will make the scroll bars inval themselves after 16724 // drawing. We only want this when we're fading so that 16725 // we prevent excessive redraws 16726 invalidate = true; 16727 } else { 16728 // We're just on -- but we may have been fading before so 16729 // reset alpha 16730 cache.scrollBar.mutate().setAlpha(255); 16731 } 16732 16733 final boolean drawHorizontalScrollBar = isHorizontalScrollBarEnabled(); 16734 final boolean drawVerticalScrollBar = isVerticalScrollBarEnabled() 16735 && !isVerticalScrollBarHidden(); 16736 16737 // Fork out the scroll bar drawing for round wearable devices. 16738 if (mRoundScrollbarRenderer != null) { 16739 if (drawVerticalScrollBar) { 16740 final Rect bounds = cache.mScrollBarBounds; 16741 getVerticalScrollBarBounds(bounds, null); 16742 mRoundScrollbarRenderer.drawRoundScrollbars( 16743 canvas, (float) cache.scrollBar.getAlpha() / 255f, bounds); 16744 if (invalidate) { 16745 invalidate(); 16746 } 16747 } 16748 // Do not draw horizontal scroll bars for round wearable devices. 16749 } else if (drawVerticalScrollBar || drawHorizontalScrollBar) { 16750 final ScrollBarDrawable scrollBar = cache.scrollBar; 16751 16752 if (drawHorizontalScrollBar) { 16753 scrollBar.setParameters(computeHorizontalScrollRange(), 16754 computeHorizontalScrollOffset(), 16755 computeHorizontalScrollExtent(), false); 16756 final Rect bounds = cache.mScrollBarBounds; 16757 getHorizontalScrollBarBounds(bounds, null); 16758 onDrawHorizontalScrollBar(canvas, scrollBar, bounds.left, bounds.top, 16759 bounds.right, bounds.bottom); 16760 if (invalidate) { 16761 invalidate(bounds); 16762 } 16763 } 16764 16765 if (drawVerticalScrollBar) { 16766 scrollBar.setParameters(computeVerticalScrollRange(), 16767 computeVerticalScrollOffset(), 16768 computeVerticalScrollExtent(), true); 16769 final Rect bounds = cache.mScrollBarBounds; 16770 getVerticalScrollBarBounds(bounds, null); 16771 onDrawVerticalScrollBar(canvas, scrollBar, bounds.left, bounds.top, 16772 bounds.right, bounds.bottom); 16773 if (invalidate) { 16774 invalidate(bounds); 16775 } 16776 } 16777 } 16778 } 16779 } 16780 16781 /** 16782 * Override this if the vertical scrollbar needs to be hidden in a subclass, like when 16783 * FastScroller is visible. 16784 * @return whether to temporarily hide the vertical scrollbar 16785 * @hide 16786 */ 16787 protected boolean isVerticalScrollBarHidden() { 16788 return false; 16789 } 16790 16791 /** 16792 * <p>Draw the horizontal scrollbar if 16793 * {@link #isHorizontalScrollBarEnabled()} returns true.</p> 16794 * 16795 * @param canvas the canvas on which to draw the scrollbar 16796 * @param scrollBar the scrollbar's drawable 16797 * 16798 * @see #isHorizontalScrollBarEnabled() 16799 * @see #computeHorizontalScrollRange() 16800 * @see #computeHorizontalScrollExtent() 16801 * @see #computeHorizontalScrollOffset() 16802 * @see android.widget.ScrollBarDrawable 16803 * @hide 16804 */ 16805 protected void onDrawHorizontalScrollBar(Canvas canvas, Drawable scrollBar, 16806 int l, int t, int r, int b) { 16807 scrollBar.setBounds(l, t, r, b); 16808 scrollBar.draw(canvas); 16809 } 16810 16811 /** 16812 * <p>Draw the vertical scrollbar if {@link #isVerticalScrollBarEnabled()} 16813 * returns true.</p> 16814 * 16815 * @param canvas the canvas on which to draw the scrollbar 16816 * @param scrollBar the scrollbar's drawable 16817 * 16818 * @see #isVerticalScrollBarEnabled() 16819 * @see #computeVerticalScrollRange() 16820 * @see #computeVerticalScrollExtent() 16821 * @see #computeVerticalScrollOffset() 16822 * @see android.widget.ScrollBarDrawable 16823 * @hide 16824 */ 16825 protected void onDrawVerticalScrollBar(Canvas canvas, Drawable scrollBar, 16826 int l, int t, int r, int b) { 16827 scrollBar.setBounds(l, t, r, b); 16828 scrollBar.draw(canvas); 16829 } 16830 16831 /** 16832 * Implement this to do your drawing. 16833 * 16834 * @param canvas the canvas on which the background will be drawn 16835 */ 16836 protected void onDraw(Canvas canvas) { 16837 } 16838 16839 /* 16840 * Caller is responsible for calling requestLayout if necessary. 16841 * (This allows addViewInLayout to not request a new layout.) 16842 */ 16843 void assignParent(ViewParent parent) { 16844 if (mParent == null) { 16845 mParent = parent; 16846 } else if (parent == null) { 16847 mParent = null; 16848 } else { 16849 throw new RuntimeException("view " + this + " being added, but" 16850 + " it already has a parent"); 16851 } 16852 } 16853 16854 /** 16855 * This is called when the view is attached to a window. At this point it 16856 * has a Surface and will start drawing. Note that this function is 16857 * guaranteed to be called before {@link #onDraw(android.graphics.Canvas)}, 16858 * however it may be called any time before the first onDraw -- including 16859 * before or after {@link #onMeasure(int, int)}. 16860 * 16861 * @see #onDetachedFromWindow() 16862 */ 16863 @CallSuper 16864 protected void onAttachedToWindow() { 16865 if ((mPrivateFlags & PFLAG_REQUEST_TRANSPARENT_REGIONS) != 0) { 16866 mParent.requestTransparentRegion(this); 16867 } 16868 16869 mPrivateFlags3 &= ~PFLAG3_IS_LAID_OUT; 16870 16871 jumpDrawablesToCurrentState(); 16872 16873 resetSubtreeAccessibilityStateChanged(); 16874 16875 // rebuild, since Outline not maintained while View is detached 16876 rebuildOutline(); 16877 16878 if (isFocused()) { 16879 InputMethodManager imm = InputMethodManager.peekInstance(); 16880 if (imm != null) { 16881 imm.focusIn(this); 16882 } 16883 } 16884 } 16885 16886 /** 16887 * Resolve all RTL related properties. 16888 * 16889 * @return true if resolution of RTL properties has been done 16890 * 16891 * @hide 16892 */ 16893 public boolean resolveRtlPropertiesIfNeeded() { 16894 if (!needRtlPropertiesResolution()) return false; 16895 16896 // Order is important here: LayoutDirection MUST be resolved first 16897 if (!isLayoutDirectionResolved()) { 16898 resolveLayoutDirection(); 16899 resolveLayoutParams(); 16900 } 16901 // ... then we can resolve the others properties depending on the resolved LayoutDirection. 16902 if (!isTextDirectionResolved()) { 16903 resolveTextDirection(); 16904 } 16905 if (!isTextAlignmentResolved()) { 16906 resolveTextAlignment(); 16907 } 16908 // Should resolve Drawables before Padding because we need the layout direction of the 16909 // Drawable to correctly resolve Padding. 16910 if (!areDrawablesResolved()) { 16911 resolveDrawables(); 16912 } 16913 if (!isPaddingResolved()) { 16914 resolvePadding(); 16915 } 16916 onRtlPropertiesChanged(getLayoutDirection()); 16917 return true; 16918 } 16919 16920 /** 16921 * Reset resolution of all RTL related properties. 16922 * 16923 * @hide 16924 */ 16925 public void resetRtlProperties() { 16926 resetResolvedLayoutDirection(); 16927 resetResolvedTextDirection(); 16928 resetResolvedTextAlignment(); 16929 resetResolvedPadding(); 16930 resetResolvedDrawables(); 16931 } 16932 16933 /** 16934 * @see #onScreenStateChanged(int) 16935 */ 16936 void dispatchScreenStateChanged(int screenState) { 16937 onScreenStateChanged(screenState); 16938 } 16939 16940 /** 16941 * This method is called whenever the state of the screen this view is 16942 * attached to changes. A state change will usually occurs when the screen 16943 * turns on or off (whether it happens automatically or the user does it 16944 * manually.) 16945 * 16946 * @param screenState The new state of the screen. Can be either 16947 * {@link #SCREEN_STATE_ON} or {@link #SCREEN_STATE_OFF} 16948 */ 16949 public void onScreenStateChanged(int screenState) { 16950 } 16951 16952 /** 16953 * @see #onMovedToDisplay(int, Configuration) 16954 */ 16955 void dispatchMovedToDisplay(Display display, Configuration config) { 16956 mAttachInfo.mDisplay = display; 16957 mAttachInfo.mDisplayState = display.getState(); 16958 onMovedToDisplay(display.getDisplayId(), config); 16959 } 16960 16961 /** 16962 * Called by the system when the hosting activity is moved from one display to another without 16963 * recreation. This means that the activity is declared to handle all changes to configuration 16964 * that happened when it was switched to another display, so it wasn't destroyed and created 16965 * again. 16966 * 16967 * <p>This call will be followed by {@link #onConfigurationChanged(Configuration)} if the 16968 * applied configuration actually changed. It is up to app developer to choose whether to handle 16969 * the change in this method or in the following {@link #onConfigurationChanged(Configuration)} 16970 * call. 16971 * 16972 * <p>Use this callback to track changes to the displays if some functionality relies on an 16973 * association with some display properties. 16974 * 16975 * @param displayId The id of the display to which the view was moved. 16976 * @param config Configuration of the resources on new display after move. 16977 * 16978 * @see #onConfigurationChanged(Configuration) 16979 * @hide 16980 */ 16981 public void onMovedToDisplay(int displayId, Configuration config) { 16982 } 16983 16984 /** 16985 * Return true if the application tag in the AndroidManifest has set "supportRtl" to true 16986 */ 16987 private boolean hasRtlSupport() { 16988 return mContext.getApplicationInfo().hasRtlSupport(); 16989 } 16990 16991 /** 16992 * Return true if we are in RTL compatibility mode (either before Jelly Bean MR1 or 16993 * RTL not supported) 16994 */ 16995 private boolean isRtlCompatibilityMode() { 16996 final int targetSdkVersion = getContext().getApplicationInfo().targetSdkVersion; 16997 return targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR1 || !hasRtlSupport(); 16998 } 16999 17000 /** 17001 * @return true if RTL properties need resolution. 17002 * 17003 */ 17004 private boolean needRtlPropertiesResolution() { 17005 return (mPrivateFlags2 & ALL_RTL_PROPERTIES_RESOLVED) != ALL_RTL_PROPERTIES_RESOLVED; 17006 } 17007 17008 /** 17009 * Called when any RTL property (layout direction or text direction or text alignment) has 17010 * been changed. 17011 * 17012 * Subclasses need to override this method to take care of cached information that depends on the 17013 * resolved layout direction, or to inform child views that inherit their layout direction. 17014 * 17015 * The default implementation does nothing. 17016 * 17017 * @param layoutDirection the direction of the layout 17018 * 17019 * @see #LAYOUT_DIRECTION_LTR 17020 * @see #LAYOUT_DIRECTION_RTL 17021 */ 17022 public void onRtlPropertiesChanged(@ResolvedLayoutDir int layoutDirection) { 17023 } 17024 17025 /** 17026 * Resolve and cache the layout direction. LTR is set initially. This is implicitly supposing 17027 * that the parent directionality can and will be resolved before its children. 17028 * 17029 * @return true if resolution has been done, false otherwise. 17030 * 17031 * @hide 17032 */ 17033 public boolean resolveLayoutDirection() { 17034 // Clear any previous layout direction resolution 17035 mPrivateFlags2 &= ~PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK; 17036 17037 if (hasRtlSupport()) { 17038 // Set resolved depending on layout direction 17039 switch ((mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_MASK) >> 17040 PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT) { 17041 case LAYOUT_DIRECTION_INHERIT: 17042 // We cannot resolve yet. LTR is by default and let the resolution happen again 17043 // later to get the correct resolved value 17044 if (!canResolveLayoutDirection()) return false; 17045 17046 // Parent has not yet resolved, LTR is still the default 17047 try { 17048 if (!mParent.isLayoutDirectionResolved()) return false; 17049 17050 if (mParent.getLayoutDirection() == LAYOUT_DIRECTION_RTL) { 17051 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL; 17052 } 17053 } catch (AbstractMethodError e) { 17054 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 17055 " does not fully implement ViewParent", e); 17056 } 17057 break; 17058 case LAYOUT_DIRECTION_RTL: 17059 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL; 17060 break; 17061 case LAYOUT_DIRECTION_LOCALE: 17062 if((LAYOUT_DIRECTION_RTL == 17063 TextUtils.getLayoutDirectionFromLocale(Locale.getDefault()))) { 17064 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL; 17065 } 17066 break; 17067 default: 17068 // Nothing to do, LTR by default 17069 } 17070 } 17071 17072 // Set to resolved 17073 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED; 17074 return true; 17075 } 17076 17077 /** 17078 * Check if layout direction resolution can be done. 17079 * 17080 * @return true if layout direction resolution can be done otherwise return false. 17081 */ 17082 public boolean canResolveLayoutDirection() { 17083 switch (getRawLayoutDirection()) { 17084 case LAYOUT_DIRECTION_INHERIT: 17085 if (mParent != null) { 17086 try { 17087 return mParent.canResolveLayoutDirection(); 17088 } catch (AbstractMethodError e) { 17089 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 17090 " does not fully implement ViewParent", e); 17091 } 17092 } 17093 return false; 17094 17095 default: 17096 return true; 17097 } 17098 } 17099 17100 /** 17101 * Reset the resolved layout direction. Layout direction will be resolved during a call to 17102 * {@link #onMeasure(int, int)}. 17103 * 17104 * @hide 17105 */ 17106 public void resetResolvedLayoutDirection() { 17107 // Reset the current resolved bits 17108 mPrivateFlags2 &= ~PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK; 17109 } 17110 17111 /** 17112 * @return true if the layout direction is inherited. 17113 * 17114 * @hide 17115 */ 17116 public boolean isLayoutDirectionInherited() { 17117 return (getRawLayoutDirection() == LAYOUT_DIRECTION_INHERIT); 17118 } 17119 17120 /** 17121 * @return true if layout direction has been resolved. 17122 */ 17123 public boolean isLayoutDirectionResolved() { 17124 return (mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_RESOLVED) == PFLAG2_LAYOUT_DIRECTION_RESOLVED; 17125 } 17126 17127 /** 17128 * Return if padding has been resolved 17129 * 17130 * @hide 17131 */ 17132 boolean isPaddingResolved() { 17133 return (mPrivateFlags2 & PFLAG2_PADDING_RESOLVED) == PFLAG2_PADDING_RESOLVED; 17134 } 17135 17136 /** 17137 * Resolves padding depending on layout direction, if applicable, and 17138 * recomputes internal padding values to adjust for scroll bars. 17139 * 17140 * @hide 17141 */ 17142 public void resolvePadding() { 17143 final int resolvedLayoutDirection = getLayoutDirection(); 17144 17145 if (!isRtlCompatibilityMode()) { 17146 // Post Jelly Bean MR1 case: we need to take the resolved layout direction into account. 17147 // If start / end padding are defined, they will be resolved (hence overriding) to 17148 // left / right or right / left depending on the resolved layout direction. 17149 // If start / end padding are not defined, use the left / right ones. 17150 if (mBackground != null && (!mLeftPaddingDefined || !mRightPaddingDefined)) { 17151 Rect padding = sThreadLocal.get(); 17152 if (padding == null) { 17153 padding = new Rect(); 17154 sThreadLocal.set(padding); 17155 } 17156 mBackground.getPadding(padding); 17157 if (!mLeftPaddingDefined) { 17158 mUserPaddingLeftInitial = padding.left; 17159 } 17160 if (!mRightPaddingDefined) { 17161 mUserPaddingRightInitial = padding.right; 17162 } 17163 } 17164 switch (resolvedLayoutDirection) { 17165 case LAYOUT_DIRECTION_RTL: 17166 if (mUserPaddingStart != UNDEFINED_PADDING) { 17167 mUserPaddingRight = mUserPaddingStart; 17168 } else { 17169 mUserPaddingRight = mUserPaddingRightInitial; 17170 } 17171 if (mUserPaddingEnd != UNDEFINED_PADDING) { 17172 mUserPaddingLeft = mUserPaddingEnd; 17173 } else { 17174 mUserPaddingLeft = mUserPaddingLeftInitial; 17175 } 17176 break; 17177 case LAYOUT_DIRECTION_LTR: 17178 default: 17179 if (mUserPaddingStart != UNDEFINED_PADDING) { 17180 mUserPaddingLeft = mUserPaddingStart; 17181 } else { 17182 mUserPaddingLeft = mUserPaddingLeftInitial; 17183 } 17184 if (mUserPaddingEnd != UNDEFINED_PADDING) { 17185 mUserPaddingRight = mUserPaddingEnd; 17186 } else { 17187 mUserPaddingRight = mUserPaddingRightInitial; 17188 } 17189 } 17190 17191 mUserPaddingBottom = (mUserPaddingBottom >= 0) ? mUserPaddingBottom : mPaddingBottom; 17192 } 17193 17194 internalSetPadding(mUserPaddingLeft, mPaddingTop, mUserPaddingRight, mUserPaddingBottom); 17195 onRtlPropertiesChanged(resolvedLayoutDirection); 17196 17197 mPrivateFlags2 |= PFLAG2_PADDING_RESOLVED; 17198 } 17199 17200 /** 17201 * Reset the resolved layout direction. 17202 * 17203 * @hide 17204 */ 17205 public void resetResolvedPadding() { 17206 resetResolvedPaddingInternal(); 17207 } 17208 17209 /** 17210 * Used when we only want to reset *this* view's padding and not trigger overrides 17211 * in ViewGroup that reset children too. 17212 */ 17213 void resetResolvedPaddingInternal() { 17214 mPrivateFlags2 &= ~PFLAG2_PADDING_RESOLVED; 17215 } 17216 17217 /** 17218 * This is called when the view is detached from a window. At this point it 17219 * no longer has a surface for drawing. 17220 * 17221 * @see #onAttachedToWindow() 17222 */ 17223 @CallSuper 17224 protected void onDetachedFromWindow() { 17225 } 17226 17227 /** 17228 * This is a framework-internal mirror of onDetachedFromWindow() that's called 17229 * after onDetachedFromWindow(). 17230 * 17231 * If you override this you *MUST* call super.onDetachedFromWindowInternal()! 17232 * The super method should be called at the end of the overridden method to ensure 17233 * subclasses are destroyed first 17234 * 17235 * @hide 17236 */ 17237 @CallSuper 17238 protected void onDetachedFromWindowInternal() { 17239 mPrivateFlags &= ~PFLAG_CANCEL_NEXT_UP_EVENT; 17240 mPrivateFlags3 &= ~PFLAG3_IS_LAID_OUT; 17241 mPrivateFlags3 &= ~PFLAG3_TEMPORARY_DETACH; 17242 17243 removeUnsetPressCallback(); 17244 removeLongPressCallback(); 17245 removePerformClickCallback(); 17246 removeSendViewScrolledAccessibilityEventCallback(); 17247 stopNestedScroll(); 17248 17249 // Anything that started animating right before detach should already 17250 // be in its final state when re-attached. 17251 jumpDrawablesToCurrentState(); 17252 17253 destroyDrawingCache(); 17254 17255 cleanupDraw(); 17256 mCurrentAnimation = null; 17257 17258 if ((mViewFlags & TOOLTIP) == TOOLTIP) { 17259 hideTooltip(); 17260 } 17261 } 17262 17263 private void cleanupDraw() { 17264 resetDisplayList(); 17265 if (mAttachInfo != null) { 17266 mAttachInfo.mViewRootImpl.cancelInvalidate(this); 17267 } 17268 } 17269 17270 void invalidateInheritedLayoutMode(int layoutModeOfRoot) { 17271 } 17272 17273 /** 17274 * @return The number of times this view has been attached to a window 17275 */ 17276 protected int getWindowAttachCount() { 17277 return mWindowAttachCount; 17278 } 17279 17280 /** 17281 * Retrieve a unique token identifying the window this view is attached to. 17282 * @return Return the window's token for use in 17283 * {@link WindowManager.LayoutParams#token WindowManager.LayoutParams.token}. 17284 */ 17285 public IBinder getWindowToken() { 17286 return mAttachInfo != null ? mAttachInfo.mWindowToken : null; 17287 } 17288 17289 /** 17290 * Retrieve the {@link WindowId} for the window this view is 17291 * currently attached to. 17292 */ 17293 public WindowId getWindowId() { 17294 if (mAttachInfo == null) { 17295 return null; 17296 } 17297 if (mAttachInfo.mWindowId == null) { 17298 try { 17299 mAttachInfo.mIWindowId = mAttachInfo.mSession.getWindowId( 17300 mAttachInfo.mWindowToken); 17301 mAttachInfo.mWindowId = new WindowId( 17302 mAttachInfo.mIWindowId); 17303 } catch (RemoteException e) { 17304 } 17305 } 17306 return mAttachInfo.mWindowId; 17307 } 17308 17309 /** 17310 * Retrieve a unique token identifying the top-level "real" window of 17311 * the window that this view is attached to. That is, this is like 17312 * {@link #getWindowToken}, except if the window this view in is a panel 17313 * window (attached to another containing window), then the token of 17314 * the containing window is returned instead. 17315 * 17316 * @return Returns the associated window token, either 17317 * {@link #getWindowToken()} or the containing window's token. 17318 */ 17319 public IBinder getApplicationWindowToken() { 17320 AttachInfo ai = mAttachInfo; 17321 if (ai != null) { 17322 IBinder appWindowToken = ai.mPanelParentWindowToken; 17323 if (appWindowToken == null) { 17324 appWindowToken = ai.mWindowToken; 17325 } 17326 return appWindowToken; 17327 } 17328 return null; 17329 } 17330 17331 /** 17332 * Gets the logical display to which the view's window has been attached. 17333 * 17334 * @return The logical display, or null if the view is not currently attached to a window. 17335 */ 17336 public Display getDisplay() { 17337 return mAttachInfo != null ? mAttachInfo.mDisplay : null; 17338 } 17339 17340 /** 17341 * Retrieve private session object this view hierarchy is using to 17342 * communicate with the window manager. 17343 * @return the session object to communicate with the window manager 17344 */ 17345 /*package*/ IWindowSession getWindowSession() { 17346 return mAttachInfo != null ? mAttachInfo.mSession : null; 17347 } 17348 17349 /** 17350 * Return the visibility value of the least visible component passed. 17351 */ 17352 int combineVisibility(int vis1, int vis2) { 17353 // This works because VISIBLE < INVISIBLE < GONE. 17354 return Math.max(vis1, vis2); 17355 } 17356 17357 /** 17358 * @param info the {@link android.view.View.AttachInfo} to associated with 17359 * this view 17360 */ 17361 void dispatchAttachedToWindow(AttachInfo info, int visibility) { 17362 mAttachInfo = info; 17363 if (mOverlay != null) { 17364 mOverlay.getOverlayView().dispatchAttachedToWindow(info, visibility); 17365 } 17366 mWindowAttachCount++; 17367 // We will need to evaluate the drawable state at least once. 17368 mPrivateFlags |= PFLAG_DRAWABLE_STATE_DIRTY; 17369 if (mFloatingTreeObserver != null) { 17370 info.mTreeObserver.merge(mFloatingTreeObserver); 17371 mFloatingTreeObserver = null; 17372 } 17373 17374 registerPendingFrameMetricsObservers(); 17375 17376 if ((mPrivateFlags&PFLAG_SCROLL_CONTAINER) != 0) { 17377 mAttachInfo.mScrollContainers.add(this); 17378 mPrivateFlags |= PFLAG_SCROLL_CONTAINER_ADDED; 17379 } 17380 // Transfer all pending runnables. 17381 if (mRunQueue != null) { 17382 mRunQueue.executeActions(info.mHandler); 17383 mRunQueue = null; 17384 } 17385 performCollectViewAttributes(mAttachInfo, visibility); 17386 onAttachedToWindow(); 17387 17388 ListenerInfo li = mListenerInfo; 17389 final CopyOnWriteArrayList<OnAttachStateChangeListener> listeners = 17390 li != null ? li.mOnAttachStateChangeListeners : null; 17391 if (listeners != null && listeners.size() > 0) { 17392 // NOTE: because of the use of CopyOnWriteArrayList, we *must* use an iterator to 17393 // perform the dispatching. The iterator is a safe guard against listeners that 17394 // could mutate the list by calling the various add/remove methods. This prevents 17395 // the array from being modified while we iterate it. 17396 for (OnAttachStateChangeListener listener : listeners) { 17397 listener.onViewAttachedToWindow(this); 17398 } 17399 } 17400 17401 int vis = info.mWindowVisibility; 17402 if (vis != GONE) { 17403 onWindowVisibilityChanged(vis); 17404 if (isShown()) { 17405 // Calling onVisibilityAggregated directly here since the subtree will also 17406 // receive dispatchAttachedToWindow and this same call 17407 onVisibilityAggregated(vis == VISIBLE); 17408 } 17409 } 17410 17411 // Send onVisibilityChanged directly instead of dispatchVisibilityChanged. 17412 // As all views in the subtree will already receive dispatchAttachedToWindow 17413 // traversing the subtree again here is not desired. 17414 onVisibilityChanged(this, visibility); 17415 17416 if ((mPrivateFlags&PFLAG_DRAWABLE_STATE_DIRTY) != 0) { 17417 // If nobody has evaluated the drawable state yet, then do it now. 17418 refreshDrawableState(); 17419 } 17420 needGlobalAttributesUpdate(false); 17421 17422 notifyEnterOrExitForAutoFillIfNeeded(true); 17423 } 17424 17425 void dispatchDetachedFromWindow() { 17426 AttachInfo info = mAttachInfo; 17427 if (info != null) { 17428 int vis = info.mWindowVisibility; 17429 if (vis != GONE) { 17430 onWindowVisibilityChanged(GONE); 17431 if (isShown()) { 17432 // Invoking onVisibilityAggregated directly here since the subtree 17433 // will also receive detached from window 17434 onVisibilityAggregated(false); 17435 } 17436 } 17437 } 17438 17439 onDetachedFromWindow(); 17440 onDetachedFromWindowInternal(); 17441 17442 InputMethodManager imm = InputMethodManager.peekInstance(); 17443 if (imm != null) { 17444 imm.onViewDetachedFromWindow(this); 17445 } 17446 17447 ListenerInfo li = mListenerInfo; 17448 final CopyOnWriteArrayList<OnAttachStateChangeListener> listeners = 17449 li != null ? li.mOnAttachStateChangeListeners : null; 17450 if (listeners != null && listeners.size() > 0) { 17451 // NOTE: because of the use of CopyOnWriteArrayList, we *must* use an iterator to 17452 // perform the dispatching. The iterator is a safe guard against listeners that 17453 // could mutate the list by calling the various add/remove methods. This prevents 17454 // the array from being modified while we iterate it. 17455 for (OnAttachStateChangeListener listener : listeners) { 17456 listener.onViewDetachedFromWindow(this); 17457 } 17458 } 17459 17460 if ((mPrivateFlags & PFLAG_SCROLL_CONTAINER_ADDED) != 0) { 17461 mAttachInfo.mScrollContainers.remove(this); 17462 mPrivateFlags &= ~PFLAG_SCROLL_CONTAINER_ADDED; 17463 } 17464 17465 mAttachInfo = null; 17466 if (mOverlay != null) { 17467 mOverlay.getOverlayView().dispatchDetachedFromWindow(); 17468 } 17469 17470 notifyEnterOrExitForAutoFillIfNeeded(false); 17471 } 17472 17473 /** 17474 * Cancel any deferred high-level input events that were previously posted to the event queue. 17475 * 17476 * <p>Many views post high-level events such as click handlers to the event queue 17477 * to run deferred in order to preserve a desired user experience - clearing visible 17478 * pressed states before executing, etc. This method will abort any events of this nature 17479 * that are currently in flight.</p> 17480 * 17481 * <p>Custom views that generate their own high-level deferred input events should override 17482 * {@link #onCancelPendingInputEvents()} and remove those pending events from the queue.</p> 17483 * 17484 * <p>This will also cancel pending input events for any child views.</p> 17485 * 17486 * <p>Note that this may not be sufficient as a debouncing strategy for clicks in all cases. 17487 * This will not impact newer events posted after this call that may occur as a result of 17488 * lower-level input events still waiting in the queue. If you are trying to prevent 17489 * double-submitted events for the duration of some sort of asynchronous transaction 17490 * you should also take other steps to protect against unexpected double inputs e.g. calling 17491 * {@link #setEnabled(boolean) setEnabled(false)} and re-enabling the view when 17492 * the transaction completes, tracking already submitted transaction IDs, etc.</p> 17493 */ 17494 public final void cancelPendingInputEvents() { 17495 dispatchCancelPendingInputEvents(); 17496 } 17497 17498 /** 17499 * Called by {@link #cancelPendingInputEvents()} to cancel input events in flight. 17500 * Overridden by ViewGroup to dispatch. Package scoped to prevent app-side meddling. 17501 */ 17502 void dispatchCancelPendingInputEvents() { 17503 mPrivateFlags3 &= ~PFLAG3_CALLED_SUPER; 17504 onCancelPendingInputEvents(); 17505 if ((mPrivateFlags3 & PFLAG3_CALLED_SUPER) != PFLAG3_CALLED_SUPER) { 17506 throw new SuperNotCalledException("View " + getClass().getSimpleName() + 17507 " did not call through to super.onCancelPendingInputEvents()"); 17508 } 17509 } 17510 17511 /** 17512 * Called as the result of a call to {@link #cancelPendingInputEvents()} on this view or 17513 * a parent view. 17514 * 17515 * <p>This method is responsible for removing any pending high-level input events that were 17516 * posted to the event queue to run later. Custom view classes that post their own deferred 17517 * high-level events via {@link #post(Runnable)}, {@link #postDelayed(Runnable, long)} or 17518 * {@link android.os.Handler} should override this method, call 17519 * <code>super.onCancelPendingInputEvents()</code> and remove those callbacks as appropriate. 17520 * </p> 17521 */ 17522 public void onCancelPendingInputEvents() { 17523 removePerformClickCallback(); 17524 cancelLongPress(); 17525 mPrivateFlags3 |= PFLAG3_CALLED_SUPER; 17526 } 17527 17528 /** 17529 * Store this view hierarchy's frozen state into the given container. 17530 * 17531 * @param container The SparseArray in which to save the view's state. 17532 * 17533 * @see #restoreHierarchyState(android.util.SparseArray) 17534 * @see #dispatchSaveInstanceState(android.util.SparseArray) 17535 * @see #onSaveInstanceState() 17536 */ 17537 public void saveHierarchyState(SparseArray<Parcelable> container) { 17538 dispatchSaveInstanceState(container); 17539 } 17540 17541 /** 17542 * Called by {@link #saveHierarchyState(android.util.SparseArray)} to store the state for 17543 * this view and its children. May be overridden to modify how freezing happens to a 17544 * view's children; for example, some views may want to not store state for their children. 17545 * 17546 * @param container The SparseArray in which to save the view's state. 17547 * 17548 * @see #dispatchRestoreInstanceState(android.util.SparseArray) 17549 * @see #saveHierarchyState(android.util.SparseArray) 17550 * @see #onSaveInstanceState() 17551 */ 17552 protected void dispatchSaveInstanceState(SparseArray<Parcelable> container) { 17553 if (mID != NO_ID && (mViewFlags & SAVE_DISABLED_MASK) == 0) { 17554 mPrivateFlags &= ~PFLAG_SAVE_STATE_CALLED; 17555 Parcelable state = onSaveInstanceState(); 17556 if ((mPrivateFlags & PFLAG_SAVE_STATE_CALLED) == 0) { 17557 throw new IllegalStateException( 17558 "Derived class did not call super.onSaveInstanceState()"); 17559 } 17560 if (state != null) { 17561 // Log.i("View", "Freezing #" + Integer.toHexString(mID) 17562 // + ": " + state); 17563 container.put(mID, state); 17564 } 17565 } 17566 } 17567 17568 /** 17569 * Hook allowing a view to generate a representation of its internal state 17570 * that can later be used to create a new instance with that same state. 17571 * This state should only contain information that is not persistent or can 17572 * not be reconstructed later. For example, you will never store your 17573 * current position on screen because that will be computed again when a 17574 * new instance of the view is placed in its view hierarchy. 17575 * <p> 17576 * Some examples of things you may store here: the current cursor position 17577 * in a text view (but usually not the text itself since that is stored in a 17578 * content provider or other persistent storage), the currently selected 17579 * item in a list view. 17580 * 17581 * @return Returns a Parcelable object containing the view's current dynamic 17582 * state, or null if there is nothing interesting to save. 17583 * @see #onRestoreInstanceState(Parcelable) 17584 * @see #saveHierarchyState(SparseArray) 17585 * @see #dispatchSaveInstanceState(SparseArray) 17586 * @see #setSaveEnabled(boolean) 17587 */ 17588 @CallSuper 17589 @Nullable protected Parcelable onSaveInstanceState() { 17590 mPrivateFlags |= PFLAG_SAVE_STATE_CALLED; 17591 if (mStartActivityRequestWho != null || isAutofilled() 17592 || mAutofillViewId > LAST_APP_AUTOFILL_ID) { 17593 BaseSavedState state = new BaseSavedState(AbsSavedState.EMPTY_STATE); 17594 17595 if (mStartActivityRequestWho != null) { 17596 state.mSavedData |= BaseSavedState.START_ACTIVITY_REQUESTED_WHO_SAVED; 17597 } 17598 17599 if (isAutofilled()) { 17600 state.mSavedData |= BaseSavedState.IS_AUTOFILLED; 17601 } 17602 17603 if (mAutofillViewId > LAST_APP_AUTOFILL_ID) { 17604 state.mSavedData |= BaseSavedState.AUTOFILL_ID; 17605 } 17606 17607 state.mStartActivityRequestWhoSaved = mStartActivityRequestWho; 17608 state.mIsAutofilled = isAutofilled(); 17609 state.mAutofillViewId = mAutofillViewId; 17610 return state; 17611 } 17612 return BaseSavedState.EMPTY_STATE; 17613 } 17614 17615 /** 17616 * Restore this view hierarchy's frozen state from the given container. 17617 * 17618 * @param container The SparseArray which holds previously frozen states. 17619 * 17620 * @see #saveHierarchyState(android.util.SparseArray) 17621 * @see #dispatchRestoreInstanceState(android.util.SparseArray) 17622 * @see #onRestoreInstanceState(android.os.Parcelable) 17623 */ 17624 public void restoreHierarchyState(SparseArray<Parcelable> container) { 17625 dispatchRestoreInstanceState(container); 17626 } 17627 17628 /** 17629 * Called by {@link #restoreHierarchyState(android.util.SparseArray)} to retrieve the 17630 * state for this view and its children. May be overridden to modify how restoring 17631 * happens to a view's children; for example, some views may want to not store state 17632 * for their children. 17633 * 17634 * @param container The SparseArray which holds previously saved state. 17635 * 17636 * @see #dispatchSaveInstanceState(android.util.SparseArray) 17637 * @see #restoreHierarchyState(android.util.SparseArray) 17638 * @see #onRestoreInstanceState(android.os.Parcelable) 17639 */ 17640 protected void dispatchRestoreInstanceState(SparseArray<Parcelable> container) { 17641 if (mID != NO_ID) { 17642 Parcelable state = container.get(mID); 17643 if (state != null) { 17644 // Log.i("View", "Restoreing #" + Integer.toHexString(mID) 17645 // + ": " + state); 17646 mPrivateFlags &= ~PFLAG_SAVE_STATE_CALLED; 17647 onRestoreInstanceState(state); 17648 if ((mPrivateFlags & PFLAG_SAVE_STATE_CALLED) == 0) { 17649 throw new IllegalStateException( 17650 "Derived class did not call super.onRestoreInstanceState()"); 17651 } 17652 } 17653 } 17654 } 17655 17656 /** 17657 * Hook allowing a view to re-apply a representation of its internal state that had previously 17658 * been generated by {@link #onSaveInstanceState}. This function will never be called with a 17659 * null state. 17660 * 17661 * @param state The frozen state that had previously been returned by 17662 * {@link #onSaveInstanceState}. 17663 * 17664 * @see #onSaveInstanceState() 17665 * @see #restoreHierarchyState(android.util.SparseArray) 17666 * @see #dispatchRestoreInstanceState(android.util.SparseArray) 17667 */ 17668 @CallSuper 17669 protected void onRestoreInstanceState(Parcelable state) { 17670 mPrivateFlags |= PFLAG_SAVE_STATE_CALLED; 17671 if (state != null && !(state instanceof AbsSavedState)) { 17672 throw new IllegalArgumentException("Wrong state class, expecting View State but " 17673 + "received " + state.getClass().toString() + " instead. This usually happens " 17674 + "when two views of different type have the same id in the same hierarchy. " 17675 + "This view's id is " + ViewDebug.resolveId(mContext, getId()) + ". Make sure " 17676 + "other views do not use the same id."); 17677 } 17678 if (state != null && state instanceof BaseSavedState) { 17679 BaseSavedState baseState = (BaseSavedState) state; 17680 17681 if ((baseState.mSavedData & BaseSavedState.START_ACTIVITY_REQUESTED_WHO_SAVED) != 0) { 17682 mStartActivityRequestWho = baseState.mStartActivityRequestWhoSaved; 17683 } 17684 if ((baseState.mSavedData & BaseSavedState.IS_AUTOFILLED) != 0) { 17685 setAutofilled(baseState.mIsAutofilled); 17686 } 17687 if ((baseState.mSavedData & BaseSavedState.AUTOFILL_ID) != 0) { 17688 // It can happen that views have the same view id and the restoration path will not 17689 // be able to distinguish between them. The autofill id needs to be unique though. 17690 // Hence prevent the same autofill view id from being restored multiple times. 17691 ((BaseSavedState) state).mSavedData &= ~BaseSavedState.AUTOFILL_ID; 17692 17693 mAutofillViewId = baseState.mAutofillViewId; 17694 } 17695 } 17696 } 17697 17698 /** 17699 * <p>Return the time at which the drawing of the view hierarchy started.</p> 17700 * 17701 * @return the drawing start time in milliseconds 17702 */ 17703 public long getDrawingTime() { 17704 return mAttachInfo != null ? mAttachInfo.mDrawingTime : 0; 17705 } 17706 17707 /** 17708 * <p>Enables or disables the duplication of the parent's state into this view. When 17709 * duplication is enabled, this view gets its drawable state from its parent rather 17710 * than from its own internal properties.</p> 17711 * 17712 * <p>Note: in the current implementation, setting this property to true after the 17713 * view was added to a ViewGroup might have no effect at all. This property should 17714 * always be used from XML or set to true before adding this view to a ViewGroup.</p> 17715 * 17716 * <p>Note: if this view's parent addStateFromChildren property is enabled and this 17717 * property is enabled, an exception will be thrown.</p> 17718 * 17719 * <p>Note: if the child view uses and updates additional states which are unknown to the 17720 * parent, these states should not be affected by this method.</p> 17721 * 17722 * @param enabled True to enable duplication of the parent's drawable state, false 17723 * to disable it. 17724 * 17725 * @see #getDrawableState() 17726 * @see #isDuplicateParentStateEnabled() 17727 */ 17728 public void setDuplicateParentStateEnabled(boolean enabled) { 17729 setFlags(enabled ? DUPLICATE_PARENT_STATE : 0, DUPLICATE_PARENT_STATE); 17730 } 17731 17732 /** 17733 * <p>Indicates whether this duplicates its drawable state from its parent.</p> 17734 * 17735 * @return True if this view's drawable state is duplicated from the parent, 17736 * false otherwise 17737 * 17738 * @see #getDrawableState() 17739 * @see #setDuplicateParentStateEnabled(boolean) 17740 */ 17741 public boolean isDuplicateParentStateEnabled() { 17742 return (mViewFlags & DUPLICATE_PARENT_STATE) == DUPLICATE_PARENT_STATE; 17743 } 17744 17745 /** 17746 * <p>Specifies the type of layer backing this view. The layer can be 17747 * {@link #LAYER_TYPE_NONE}, {@link #LAYER_TYPE_SOFTWARE} or 17748 * {@link #LAYER_TYPE_HARDWARE}.</p> 17749 * 17750 * <p>A layer is associated with an optional {@link android.graphics.Paint} 17751 * instance that controls how the layer is composed on screen. The following 17752 * properties of the paint are taken into account when composing the layer:</p> 17753 * <ul> 17754 * <li>{@link android.graphics.Paint#getAlpha() Translucency (alpha)}</li> 17755 * <li>{@link android.graphics.Paint#getXfermode() Blending mode}</li> 17756 * <li>{@link android.graphics.Paint#getColorFilter() Color filter}</li> 17757 * </ul> 17758 * 17759 * <p>If this view has an alpha value set to < 1.0 by calling 17760 * {@link #setAlpha(float)}, the alpha value of the layer's paint is superseded 17761 * by this view's alpha value.</p> 17762 * 17763 * <p>Refer to the documentation of {@link #LAYER_TYPE_NONE}, 17764 * {@link #LAYER_TYPE_SOFTWARE} and {@link #LAYER_TYPE_HARDWARE} 17765 * for more information on when and how to use layers.</p> 17766 * 17767 * @param layerType The type of layer to use with this view, must be one of 17768 * {@link #LAYER_TYPE_NONE}, {@link #LAYER_TYPE_SOFTWARE} or 17769 * {@link #LAYER_TYPE_HARDWARE} 17770 * @param paint The paint used to compose the layer. This argument is optional 17771 * and can be null. It is ignored when the layer type is 17772 * {@link #LAYER_TYPE_NONE} 17773 * 17774 * @see #getLayerType() 17775 * @see #LAYER_TYPE_NONE 17776 * @see #LAYER_TYPE_SOFTWARE 17777 * @see #LAYER_TYPE_HARDWARE 17778 * @see #setAlpha(float) 17779 * 17780 * @attr ref android.R.styleable#View_layerType 17781 */ 17782 public void setLayerType(int layerType, @Nullable Paint paint) { 17783 if (layerType < LAYER_TYPE_NONE || layerType > LAYER_TYPE_HARDWARE) { 17784 throw new IllegalArgumentException("Layer type can only be one of: LAYER_TYPE_NONE, " 17785 + "LAYER_TYPE_SOFTWARE or LAYER_TYPE_HARDWARE"); 17786 } 17787 17788 boolean typeChanged = mRenderNode.setLayerType(layerType); 17789 17790 if (!typeChanged) { 17791 setLayerPaint(paint); 17792 return; 17793 } 17794 17795 if (layerType != LAYER_TYPE_SOFTWARE) { 17796 // Destroy any previous software drawing cache if present 17797 // NOTE: even if previous layer type is HW, we do this to ensure we've cleaned up 17798 // drawing cache created in View#draw when drawing to a SW canvas. 17799 destroyDrawingCache(); 17800 } 17801 17802 mLayerType = layerType; 17803 mLayerPaint = mLayerType == LAYER_TYPE_NONE ? null : paint; 17804 mRenderNode.setLayerPaint(mLayerPaint); 17805 17806 // draw() behaves differently if we are on a layer, so we need to 17807 // invalidate() here 17808 invalidateParentCaches(); 17809 invalidate(true); 17810 } 17811 17812 /** 17813 * Updates the {@link Paint} object used with the current layer (used only if the current 17814 * layer type is not set to {@link #LAYER_TYPE_NONE}). Changed properties of the Paint 17815 * provided to {@link #setLayerType(int, android.graphics.Paint)} will be used the next time 17816 * the View is redrawn, but {@link #setLayerPaint(android.graphics.Paint)} must be called to 17817 * ensure that the view gets redrawn immediately. 17818 * 17819 * <p>A layer is associated with an optional {@link android.graphics.Paint} 17820 * instance that controls how the layer is composed on screen. The following 17821 * properties of the paint are taken into account when composing the layer:</p> 17822 * <ul> 17823 * <li>{@link android.graphics.Paint#getAlpha() Translucency (alpha)}</li> 17824 * <li>{@link android.graphics.Paint#getXfermode() Blending mode}</li> 17825 * <li>{@link android.graphics.Paint#getColorFilter() Color filter}</li> 17826 * </ul> 17827 * 17828 * <p>If this view has an alpha value set to < 1.0 by calling {@link #setAlpha(float)}, the 17829 * alpha value of the layer's paint is superseded by this view's alpha value.</p> 17830 * 17831 * @param paint The paint used to compose the layer. This argument is optional 17832 * and can be null. It is ignored when the layer type is 17833 * {@link #LAYER_TYPE_NONE} 17834 * 17835 * @see #setLayerType(int, android.graphics.Paint) 17836 */ 17837 public void setLayerPaint(@Nullable Paint paint) { 17838 int layerType = getLayerType(); 17839 if (layerType != LAYER_TYPE_NONE) { 17840 mLayerPaint = paint; 17841 if (layerType == LAYER_TYPE_HARDWARE) { 17842 if (mRenderNode.setLayerPaint(paint)) { 17843 invalidateViewProperty(false, false); 17844 } 17845 } else { 17846 invalidate(); 17847 } 17848 } 17849 } 17850 17851 /** 17852 * Indicates what type of layer is currently associated with this view. By default 17853 * a view does not have a layer, and the layer type is {@link #LAYER_TYPE_NONE}. 17854 * Refer to the documentation of {@link #setLayerType(int, android.graphics.Paint)} 17855 * for more information on the different types of layers. 17856 * 17857 * @return {@link #LAYER_TYPE_NONE}, {@link #LAYER_TYPE_SOFTWARE} or 17858 * {@link #LAYER_TYPE_HARDWARE} 17859 * 17860 * @see #setLayerType(int, android.graphics.Paint) 17861 * @see #buildLayer() 17862 * @see #LAYER_TYPE_NONE 17863 * @see #LAYER_TYPE_SOFTWARE 17864 * @see #LAYER_TYPE_HARDWARE 17865 */ 17866 public int getLayerType() { 17867 return mLayerType; 17868 } 17869 17870 /** 17871 * Forces this view's layer to be created and this view to be rendered 17872 * into its layer. If this view's layer type is set to {@link #LAYER_TYPE_NONE}, 17873 * invoking this method will have no effect. 17874 * 17875 * This method can for instance be used to render a view into its layer before 17876 * starting an animation. If this view is complex, rendering into the layer 17877 * before starting the animation will avoid skipping frames. 17878 * 17879 * @throws IllegalStateException If this view is not attached to a window 17880 * 17881 * @see #setLayerType(int, android.graphics.Paint) 17882 */ 17883 public void buildLayer() { 17884 if (mLayerType == LAYER_TYPE_NONE) return; 17885 17886 final AttachInfo attachInfo = mAttachInfo; 17887 if (attachInfo == null) { 17888 throw new IllegalStateException("This view must be attached to a window first"); 17889 } 17890 17891 if (getWidth() == 0 || getHeight() == 0) { 17892 return; 17893 } 17894 17895 switch (mLayerType) { 17896 case LAYER_TYPE_HARDWARE: 17897 updateDisplayListIfDirty(); 17898 if (attachInfo.mThreadedRenderer != null && mRenderNode.isValid()) { 17899 attachInfo.mThreadedRenderer.buildLayer(mRenderNode); 17900 } 17901 break; 17902 case LAYER_TYPE_SOFTWARE: 17903 buildDrawingCache(true); 17904 break; 17905 } 17906 } 17907 17908 /** 17909 * Destroys all hardware rendering resources. This method is invoked 17910 * when the system needs to reclaim resources. Upon execution of this 17911 * method, you should free any OpenGL resources created by the view. 17912 * 17913 * Note: you <strong>must</strong> call 17914 * <code>super.destroyHardwareResources()</code> when overriding 17915 * this method. 17916 * 17917 * @hide 17918 */ 17919 @CallSuper 17920 protected void destroyHardwareResources() { 17921 if (mOverlay != null) { 17922 mOverlay.getOverlayView().destroyHardwareResources(); 17923 } 17924 if (mGhostView != null) { 17925 mGhostView.destroyHardwareResources(); 17926 } 17927 } 17928 17929 /** 17930 * <p>Enables or disables the drawing cache. When the drawing cache is enabled, the next call 17931 * to {@link #getDrawingCache()} or {@link #buildDrawingCache()} will draw the view in a 17932 * bitmap. Calling {@link #draw(android.graphics.Canvas)} will not draw from the cache when 17933 * the cache is enabled. To benefit from the cache, you must request the drawing cache by 17934 * calling {@link #getDrawingCache()} and draw it on screen if the returned bitmap is not 17935 * null.</p> 17936 * 17937 * <p>Enabling the drawing cache is similar to 17938 * {@link #setLayerType(int, android.graphics.Paint) setting a layer} when hardware 17939 * acceleration is turned off. When hardware acceleration is turned on, enabling the 17940 * drawing cache has no effect on rendering because the system uses a different mechanism 17941 * for acceleration which ignores the flag. If you want to use a Bitmap for the view, even 17942 * when hardware acceleration is enabled, see {@link #setLayerType(int, android.graphics.Paint)} 17943 * for information on how to enable software and hardware layers.</p> 17944 * 17945 * <p>This API can be used to manually generate 17946 * a bitmap copy of this view, by setting the flag to <code>true</code> and calling 17947 * {@link #getDrawingCache()}.</p> 17948 * 17949 * @param enabled true to enable the drawing cache, false otherwise 17950 * 17951 * @see #isDrawingCacheEnabled() 17952 * @see #getDrawingCache() 17953 * @see #buildDrawingCache() 17954 * @see #setLayerType(int, android.graphics.Paint) 17955 */ 17956 public void setDrawingCacheEnabled(boolean enabled) { 17957 mCachingFailed = false; 17958 setFlags(enabled ? DRAWING_CACHE_ENABLED : 0, DRAWING_CACHE_ENABLED); 17959 } 17960 17961 /** 17962 * <p>Indicates whether the drawing cache is enabled for this view.</p> 17963 * 17964 * @return true if the drawing cache is enabled 17965 * 17966 * @see #setDrawingCacheEnabled(boolean) 17967 * @see #getDrawingCache() 17968 */ 17969 @ViewDebug.ExportedProperty(category = "drawing") 17970 public boolean isDrawingCacheEnabled() { 17971 return (mViewFlags & DRAWING_CACHE_ENABLED) == DRAWING_CACHE_ENABLED; 17972 } 17973 17974 /** 17975 * Debugging utility which recursively outputs the dirty state of a view and its 17976 * descendants. 17977 * 17978 * @hide 17979 */ 17980 @SuppressWarnings({"UnusedDeclaration"}) 17981 public void outputDirtyFlags(String indent, boolean clear, int clearMask) { 17982 Log.d("View", indent + this + " DIRTY(" + (mPrivateFlags & View.PFLAG_DIRTY_MASK) + 17983 ") DRAWN(" + (mPrivateFlags & PFLAG_DRAWN) + ")" + " CACHE_VALID(" + 17984 (mPrivateFlags & View.PFLAG_DRAWING_CACHE_VALID) + 17985 ") INVALIDATED(" + (mPrivateFlags & PFLAG_INVALIDATED) + ")"); 17986 if (clear) { 17987 mPrivateFlags &= clearMask; 17988 } 17989 if (this instanceof ViewGroup) { 17990 ViewGroup parent = (ViewGroup) this; 17991 final int count = parent.getChildCount(); 17992 for (int i = 0; i < count; i++) { 17993 final View child = parent.getChildAt(i); 17994 child.outputDirtyFlags(indent + " ", clear, clearMask); 17995 } 17996 } 17997 } 17998 17999 /** 18000 * This method is used by ViewGroup to cause its children to restore or recreate their 18001 * display lists. It is called by getDisplayList() when the parent ViewGroup does not need 18002 * to recreate its own display list, which would happen if it went through the normal 18003 * draw/dispatchDraw mechanisms. 18004 * 18005 * @hide 18006 */ 18007 protected void dispatchGetDisplayList() {} 18008 18009 /** 18010 * A view that is not attached or hardware accelerated cannot create a display list. 18011 * This method checks these conditions and returns the appropriate result. 18012 * 18013 * @return true if view has the ability to create a display list, false otherwise. 18014 * 18015 * @hide 18016 */ 18017 public boolean canHaveDisplayList() { 18018 return !(mAttachInfo == null || mAttachInfo.mThreadedRenderer == null); 18019 } 18020 18021 /** 18022 * Gets the RenderNode for the view, and updates its DisplayList (if needed and supported) 18023 * @hide 18024 */ 18025 @NonNull 18026 public RenderNode updateDisplayListIfDirty() { 18027 final RenderNode renderNode = mRenderNode; 18028 if (!canHaveDisplayList()) { 18029 // can't populate RenderNode, don't try 18030 return renderNode; 18031 } 18032 18033 if ((mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == 0 18034 || !renderNode.isValid() 18035 || (mRecreateDisplayList)) { 18036 // Don't need to recreate the display list, just need to tell our 18037 // children to restore/recreate theirs 18038 if (renderNode.isValid() 18039 && !mRecreateDisplayList) { 18040 mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID; 18041 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 18042 dispatchGetDisplayList(); 18043 18044 return renderNode; // no work needed 18045 } 18046 18047 // If we got here, we're recreating it. Mark it as such to ensure that 18048 // we copy in child display lists into ours in drawChild() 18049 mRecreateDisplayList = true; 18050 18051 int width = mRight - mLeft; 18052 int height = mBottom - mTop; 18053 int layerType = getLayerType(); 18054 18055 final DisplayListCanvas canvas = renderNode.start(width, height); 18056 canvas.setHighContrastText(mAttachInfo.mHighContrastText); 18057 18058 try { 18059 if (layerType == LAYER_TYPE_SOFTWARE) { 18060 buildDrawingCache(true); 18061 Bitmap cache = getDrawingCache(true); 18062 if (cache != null) { 18063 canvas.drawBitmap(cache, 0, 0, mLayerPaint); 18064 } 18065 } else { 18066 computeScroll(); 18067 18068 canvas.translate(-mScrollX, -mScrollY); 18069 mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID; 18070 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 18071 18072 // Fast path for layouts with no backgrounds 18073 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { 18074 dispatchDraw(canvas); 18075 drawAutofilledHighlight(canvas); 18076 if (mOverlay != null && !mOverlay.isEmpty()) { 18077 mOverlay.getOverlayView().draw(canvas); 18078 } 18079 if (debugDraw()) { 18080 debugDrawFocus(canvas); 18081 } 18082 } else { 18083 draw(canvas); 18084 } 18085 } 18086 } finally { 18087 renderNode.end(canvas); 18088 setDisplayListProperties(renderNode); 18089 } 18090 } else { 18091 mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID; 18092 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 18093 } 18094 return renderNode; 18095 } 18096 18097 private void resetDisplayList() { 18098 mRenderNode.discardDisplayList(); 18099 if (mBackgroundRenderNode != null) { 18100 mBackgroundRenderNode.discardDisplayList(); 18101 } 18102 } 18103 18104 /** 18105 * <p>Calling this method is equivalent to calling <code>getDrawingCache(false)</code>.</p> 18106 * 18107 * @return A non-scaled bitmap representing this view or null if cache is disabled. 18108 * 18109 * @see #getDrawingCache(boolean) 18110 */ 18111 public Bitmap getDrawingCache() { 18112 return getDrawingCache(false); 18113 } 18114 18115 /** 18116 * <p>Returns the bitmap in which this view drawing is cached. The returned bitmap 18117 * is null when caching is disabled. If caching is enabled and the cache is not ready, 18118 * this method will create it. Calling {@link #draw(android.graphics.Canvas)} will not 18119 * draw from the cache when the cache is enabled. To benefit from the cache, you must 18120 * request the drawing cache by calling this method and draw it on screen if the 18121 * returned bitmap is not null.</p> 18122 * 18123 * <p>Note about auto scaling in compatibility mode: When auto scaling is not enabled, 18124 * this method will create a bitmap of the same size as this view. Because this bitmap 18125 * will be drawn scaled by the parent ViewGroup, the result on screen might show 18126 * scaling artifacts. To avoid such artifacts, you should call this method by setting 18127 * the auto scaling to true. Doing so, however, will generate a bitmap of a different 18128 * size than the view. This implies that your application must be able to handle this 18129 * size.</p> 18130 * 18131 * @param autoScale Indicates whether the generated bitmap should be scaled based on 18132 * the current density of the screen when the application is in compatibility 18133 * mode. 18134 * 18135 * @return A bitmap representing this view or null if cache is disabled. 18136 * 18137 * @see #setDrawingCacheEnabled(boolean) 18138 * @see #isDrawingCacheEnabled() 18139 * @see #buildDrawingCache(boolean) 18140 * @see #destroyDrawingCache() 18141 */ 18142 public Bitmap getDrawingCache(boolean autoScale) { 18143 if ((mViewFlags & WILL_NOT_CACHE_DRAWING) == WILL_NOT_CACHE_DRAWING) { 18144 return null; 18145 } 18146 if ((mViewFlags & DRAWING_CACHE_ENABLED) == DRAWING_CACHE_ENABLED) { 18147 buildDrawingCache(autoScale); 18148 } 18149 return autoScale ? mDrawingCache : mUnscaledDrawingCache; 18150 } 18151 18152 /** 18153 * <p>Frees the resources used by the drawing cache. If you call 18154 * {@link #buildDrawingCache()} manually without calling 18155 * {@link #setDrawingCacheEnabled(boolean) setDrawingCacheEnabled(true)}, you 18156 * should cleanup the cache with this method afterwards.</p> 18157 * 18158 * @see #setDrawingCacheEnabled(boolean) 18159 * @see #buildDrawingCache() 18160 * @see #getDrawingCache() 18161 */ 18162 public void destroyDrawingCache() { 18163 if (mDrawingCache != null) { 18164 mDrawingCache.recycle(); 18165 mDrawingCache = null; 18166 } 18167 if (mUnscaledDrawingCache != null) { 18168 mUnscaledDrawingCache.recycle(); 18169 mUnscaledDrawingCache = null; 18170 } 18171 } 18172 18173 /** 18174 * Setting a solid background color for the drawing cache's bitmaps will improve 18175 * performance and memory usage. Note, though that this should only be used if this 18176 * view will always be drawn on top of a solid color. 18177 * 18178 * @param color The background color to use for the drawing cache's bitmap 18179 * 18180 * @see #setDrawingCacheEnabled(boolean) 18181 * @see #buildDrawingCache() 18182 * @see #getDrawingCache() 18183 */ 18184 public void setDrawingCacheBackgroundColor(@ColorInt int color) { 18185 if (color != mDrawingCacheBackgroundColor) { 18186 mDrawingCacheBackgroundColor = color; 18187 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; 18188 } 18189 } 18190 18191 /** 18192 * @see #setDrawingCacheBackgroundColor(int) 18193 * 18194 * @return The background color to used for the drawing cache's bitmap 18195 */ 18196 @ColorInt 18197 public int getDrawingCacheBackgroundColor() { 18198 return mDrawingCacheBackgroundColor; 18199 } 18200 18201 /** 18202 * <p>Calling this method is equivalent to calling <code>buildDrawingCache(false)</code>.</p> 18203 * 18204 * @see #buildDrawingCache(boolean) 18205 */ 18206 public void buildDrawingCache() { 18207 buildDrawingCache(false); 18208 } 18209 18210 /** 18211 * <p>Forces the drawing cache to be built if the drawing cache is invalid.</p> 18212 * 18213 * <p>If you call {@link #buildDrawingCache()} manually without calling 18214 * {@link #setDrawingCacheEnabled(boolean) setDrawingCacheEnabled(true)}, you 18215 * should cleanup the cache by calling {@link #destroyDrawingCache()} afterwards.</p> 18216 * 18217 * <p>Note about auto scaling in compatibility mode: When auto scaling is not enabled, 18218 * this method will create a bitmap of the same size as this view. Because this bitmap 18219 * will be drawn scaled by the parent ViewGroup, the result on screen might show 18220 * scaling artifacts. To avoid such artifacts, you should call this method by setting 18221 * the auto scaling to true. Doing so, however, will generate a bitmap of a different 18222 * size than the view. This implies that your application must be able to handle this 18223 * size.</p> 18224 * 18225 * <p>You should avoid calling this method when hardware acceleration is enabled. If 18226 * you do not need the drawing cache bitmap, calling this method will increase memory 18227 * usage and cause the view to be rendered in software once, thus negatively impacting 18228 * performance.</p> 18229 * 18230 * @see #getDrawingCache() 18231 * @see #destroyDrawingCache() 18232 */ 18233 public void buildDrawingCache(boolean autoScale) { 18234 if ((mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == 0 || (autoScale ? 18235 mDrawingCache == null : mUnscaledDrawingCache == null)) { 18236 if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) { 18237 Trace.traceBegin(Trace.TRACE_TAG_VIEW, 18238 "buildDrawingCache/SW Layer for " + getClass().getSimpleName()); 18239 } 18240 try { 18241 buildDrawingCacheImpl(autoScale); 18242 } finally { 18243 Trace.traceEnd(Trace.TRACE_TAG_VIEW); 18244 } 18245 } 18246 } 18247 18248 /** 18249 * private, internal implementation of buildDrawingCache, used to enable tracing 18250 */ 18251 private void buildDrawingCacheImpl(boolean autoScale) { 18252 mCachingFailed = false; 18253 18254 int width = mRight - mLeft; 18255 int height = mBottom - mTop; 18256 18257 final AttachInfo attachInfo = mAttachInfo; 18258 final boolean scalingRequired = attachInfo != null && attachInfo.mScalingRequired; 18259 18260 if (autoScale && scalingRequired) { 18261 width = (int) ((width * attachInfo.mApplicationScale) + 0.5f); 18262 height = (int) ((height * attachInfo.mApplicationScale) + 0.5f); 18263 } 18264 18265 final int drawingCacheBackgroundColor = mDrawingCacheBackgroundColor; 18266 final boolean opaque = drawingCacheBackgroundColor != 0 || isOpaque(); 18267 final boolean use32BitCache = attachInfo != null && attachInfo.mUse32BitDrawingCache; 18268 18269 final long projectedBitmapSize = width * height * (opaque && !use32BitCache ? 2 : 4); 18270 final long drawingCacheSize = 18271 ViewConfiguration.get(mContext).getScaledMaximumDrawingCacheSize(); 18272 if (width <= 0 || height <= 0 || projectedBitmapSize > drawingCacheSize) { 18273 if (width > 0 && height > 0) { 18274 Log.w(VIEW_LOG_TAG, getClass().getSimpleName() + " not displayed because it is" 18275 + " too large to fit into a software layer (or drawing cache), needs " 18276 + projectedBitmapSize + " bytes, only " 18277 + drawingCacheSize + " available"); 18278 } 18279 destroyDrawingCache(); 18280 mCachingFailed = true; 18281 return; 18282 } 18283 18284 boolean clear = true; 18285 Bitmap bitmap = autoScale ? mDrawingCache : mUnscaledDrawingCache; 18286 18287 if (bitmap == null || bitmap.getWidth() != width || bitmap.getHeight() != height) { 18288 Bitmap.Config quality; 18289 if (!opaque) { 18290 // Never pick ARGB_4444 because it looks awful 18291 // Keep the DRAWING_CACHE_QUALITY_LOW flag just in case 18292 switch (mViewFlags & DRAWING_CACHE_QUALITY_MASK) { 18293 case DRAWING_CACHE_QUALITY_AUTO: 18294 case DRAWING_CACHE_QUALITY_LOW: 18295 case DRAWING_CACHE_QUALITY_HIGH: 18296 default: 18297 quality = Bitmap.Config.ARGB_8888; 18298 break; 18299 } 18300 } else { 18301 // Optimization for translucent windows 18302 // If the window is translucent, use a 32 bits bitmap to benefit from memcpy() 18303 quality = use32BitCache ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565; 18304 } 18305 18306 // Try to cleanup memory 18307 if (bitmap != null) bitmap.recycle(); 18308 18309 try { 18310 bitmap = Bitmap.createBitmap(mResources.getDisplayMetrics(), 18311 width, height, quality); 18312 bitmap.setDensity(getResources().getDisplayMetrics().densityDpi); 18313 if (autoScale) { 18314 mDrawingCache = bitmap; 18315 } else { 18316 mUnscaledDrawingCache = bitmap; 18317 } 18318 if (opaque && use32BitCache) bitmap.setHasAlpha(false); 18319 } catch (OutOfMemoryError e) { 18320 // If there is not enough memory to create the bitmap cache, just 18321 // ignore the issue as bitmap caches are not required to draw the 18322 // view hierarchy 18323 if (autoScale) { 18324 mDrawingCache = null; 18325 } else { 18326 mUnscaledDrawingCache = null; 18327 } 18328 mCachingFailed = true; 18329 return; 18330 } 18331 18332 clear = drawingCacheBackgroundColor != 0; 18333 } 18334 18335 Canvas canvas; 18336 if (attachInfo != null) { 18337 canvas = attachInfo.mCanvas; 18338 if (canvas == null) { 18339 canvas = new Canvas(); 18340 } 18341 canvas.setBitmap(bitmap); 18342 // Temporarily clobber the cached Canvas in case one of our children 18343 // is also using a drawing cache. Without this, the children would 18344 // steal the canvas by attaching their own bitmap to it and bad, bad 18345 // thing would happen (invisible views, corrupted drawings, etc.) 18346 attachInfo.mCanvas = null; 18347 } else { 18348 // This case should hopefully never or seldom happen 18349 canvas = new Canvas(bitmap); 18350 } 18351 18352 if (clear) { 18353 bitmap.eraseColor(drawingCacheBackgroundColor); 18354 } 18355 18356 computeScroll(); 18357 final int restoreCount = canvas.save(); 18358 18359 if (autoScale && scalingRequired) { 18360 final float scale = attachInfo.mApplicationScale; 18361 canvas.scale(scale, scale); 18362 } 18363 18364 canvas.translate(-mScrollX, -mScrollY); 18365 18366 mPrivateFlags |= PFLAG_DRAWN; 18367 if (mAttachInfo == null || !mAttachInfo.mHardwareAccelerated || 18368 mLayerType != LAYER_TYPE_NONE) { 18369 mPrivateFlags |= PFLAG_DRAWING_CACHE_VALID; 18370 } 18371 18372 // Fast path for layouts with no backgrounds 18373 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { 18374 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 18375 dispatchDraw(canvas); 18376 drawAutofilledHighlight(canvas); 18377 if (mOverlay != null && !mOverlay.isEmpty()) { 18378 mOverlay.getOverlayView().draw(canvas); 18379 } 18380 } else { 18381 draw(canvas); 18382 } 18383 18384 canvas.restoreToCount(restoreCount); 18385 canvas.setBitmap(null); 18386 18387 if (attachInfo != null) { 18388 // Restore the cached Canvas for our siblings 18389 attachInfo.mCanvas = canvas; 18390 } 18391 } 18392 18393 /** 18394 * Create a snapshot of the view into a bitmap. We should probably make 18395 * some form of this public, but should think about the API. 18396 * 18397 * @hide 18398 */ 18399 public Bitmap createSnapshot(Bitmap.Config quality, int backgroundColor, boolean skipChildren) { 18400 int width = mRight - mLeft; 18401 int height = mBottom - mTop; 18402 18403 final AttachInfo attachInfo = mAttachInfo; 18404 final float scale = attachInfo != null ? attachInfo.mApplicationScale : 1.0f; 18405 width = (int) ((width * scale) + 0.5f); 18406 height = (int) ((height * scale) + 0.5f); 18407 18408 Bitmap bitmap = Bitmap.createBitmap(mResources.getDisplayMetrics(), 18409 width > 0 ? width : 1, height > 0 ? height : 1, quality); 18410 if (bitmap == null) { 18411 throw new OutOfMemoryError(); 18412 } 18413 18414 Resources resources = getResources(); 18415 if (resources != null) { 18416 bitmap.setDensity(resources.getDisplayMetrics().densityDpi); 18417 } 18418 18419 Canvas canvas; 18420 if (attachInfo != null) { 18421 canvas = attachInfo.mCanvas; 18422 if (canvas == null) { 18423 canvas = new Canvas(); 18424 } 18425 canvas.setBitmap(bitmap); 18426 // Temporarily clobber the cached Canvas in case one of our children 18427 // is also using a drawing cache. Without this, the children would 18428 // steal the canvas by attaching their own bitmap to it and bad, bad 18429 // things would happen (invisible views, corrupted drawings, etc.) 18430 attachInfo.mCanvas = null; 18431 } else { 18432 // This case should hopefully never or seldom happen 18433 canvas = new Canvas(bitmap); 18434 } 18435 boolean enabledHwBitmapsInSwMode = canvas.isHwBitmapsInSwModeEnabled(); 18436 canvas.setHwBitmapsInSwModeEnabled(true); 18437 if ((backgroundColor & 0xff000000) != 0) { 18438 bitmap.eraseColor(backgroundColor); 18439 } 18440 18441 computeScroll(); 18442 final int restoreCount = canvas.save(); 18443 canvas.scale(scale, scale); 18444 canvas.translate(-mScrollX, -mScrollY); 18445 18446 // Temporarily remove the dirty mask 18447 int flags = mPrivateFlags; 18448 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 18449 18450 // Fast path for layouts with no backgrounds 18451 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { 18452 dispatchDraw(canvas); 18453 drawAutofilledHighlight(canvas); 18454 if (mOverlay != null && !mOverlay.isEmpty()) { 18455 mOverlay.getOverlayView().draw(canvas); 18456 } 18457 } else { 18458 draw(canvas); 18459 } 18460 18461 mPrivateFlags = flags; 18462 18463 canvas.restoreToCount(restoreCount); 18464 canvas.setBitmap(null); 18465 canvas.setHwBitmapsInSwModeEnabled(enabledHwBitmapsInSwMode); 18466 18467 if (attachInfo != null) { 18468 // Restore the cached Canvas for our siblings 18469 attachInfo.mCanvas = canvas; 18470 } 18471 18472 return bitmap; 18473 } 18474 18475 /** 18476 * Indicates whether this View is currently in edit mode. A View is usually 18477 * in edit mode when displayed within a developer tool. For instance, if 18478 * this View is being drawn by a visual user interface builder, this method 18479 * should return true. 18480 * 18481 * Subclasses should check the return value of this method to provide 18482 * different behaviors if their normal behavior might interfere with the 18483 * host environment. For instance: the class spawns a thread in its 18484 * constructor, the drawing code relies on device-specific features, etc. 18485 * 18486 * This method is usually checked in the drawing code of custom widgets. 18487 * 18488 * @return True if this View is in edit mode, false otherwise. 18489 */ 18490 public boolean isInEditMode() { 18491 return false; 18492 } 18493 18494 /** 18495 * If the View draws content inside its padding and enables fading edges, 18496 * it needs to support padding offsets. Padding offsets are added to the 18497 * fading edges to extend the length of the fade so that it covers pixels 18498 * drawn inside the padding. 18499 * 18500 * Subclasses of this class should override this method if they need 18501 * to draw content inside the padding. 18502 * 18503 * @return True if padding offset must be applied, false otherwise. 18504 * 18505 * @see #getLeftPaddingOffset() 18506 * @see #getRightPaddingOffset() 18507 * @see #getTopPaddingOffset() 18508 * @see #getBottomPaddingOffset() 18509 * 18510 * @since CURRENT 18511 */ 18512 protected boolean isPaddingOffsetRequired() { 18513 return false; 18514 } 18515 18516 /** 18517 * Amount by which to extend the left fading region. Called only when 18518 * {@link #isPaddingOffsetRequired()} returns true. 18519 * 18520 * @return The left padding offset in pixels. 18521 * 18522 * @see #isPaddingOffsetRequired() 18523 * 18524 * @since CURRENT 18525 */ 18526 protected int getLeftPaddingOffset() { 18527 return 0; 18528 } 18529 18530 /** 18531 * Amount by which to extend the right fading region. Called only when 18532 * {@link #isPaddingOffsetRequired()} returns true. 18533 * 18534 * @return The right padding offset in pixels. 18535 * 18536 * @see #isPaddingOffsetRequired() 18537 * 18538 * @since CURRENT 18539 */ 18540 protected int getRightPaddingOffset() { 18541 return 0; 18542 } 18543 18544 /** 18545 * Amount by which to extend the top fading region. Called only when 18546 * {@link #isPaddingOffsetRequired()} returns true. 18547 * 18548 * @return The top padding offset in pixels. 18549 * 18550 * @see #isPaddingOffsetRequired() 18551 * 18552 * @since CURRENT 18553 */ 18554 protected int getTopPaddingOffset() { 18555 return 0; 18556 } 18557 18558 /** 18559 * Amount by which to extend the bottom fading region. Called only when 18560 * {@link #isPaddingOffsetRequired()} returns true. 18561 * 18562 * @return The bottom padding offset in pixels. 18563 * 18564 * @see #isPaddingOffsetRequired() 18565 * 18566 * @since CURRENT 18567 */ 18568 protected int getBottomPaddingOffset() { 18569 return 0; 18570 } 18571 18572 /** 18573 * @hide 18574 * @param offsetRequired 18575 */ 18576 protected int getFadeTop(boolean offsetRequired) { 18577 int top = mPaddingTop; 18578 if (offsetRequired) top += getTopPaddingOffset(); 18579 return top; 18580 } 18581 18582 /** 18583 * @hide 18584 * @param offsetRequired 18585 */ 18586 protected int getFadeHeight(boolean offsetRequired) { 18587 int padding = mPaddingTop; 18588 if (offsetRequired) padding += getTopPaddingOffset(); 18589 return mBottom - mTop - mPaddingBottom - padding; 18590 } 18591 18592 /** 18593 * <p>Indicates whether this view is attached to a hardware accelerated 18594 * window or not.</p> 18595 * 18596 * <p>Even if this method returns true, it does not mean that every call 18597 * to {@link #draw(android.graphics.Canvas)} will be made with an hardware 18598 * accelerated {@link android.graphics.Canvas}. For instance, if this view 18599 * is drawn onto an offscreen {@link android.graphics.Bitmap} and its 18600 * window is hardware accelerated, 18601 * {@link android.graphics.Canvas#isHardwareAccelerated()} will likely 18602 * return false, and this method will return true.</p> 18603 * 18604 * @return True if the view is attached to a window and the window is 18605 * hardware accelerated; false in any other case. 18606 */ 18607 @ViewDebug.ExportedProperty(category = "drawing") 18608 public boolean isHardwareAccelerated() { 18609 return mAttachInfo != null && mAttachInfo.mHardwareAccelerated; 18610 } 18611 18612 /** 18613 * Sets a rectangular area on this view to which the view will be clipped 18614 * when it is drawn. Setting the value to null will remove the clip bounds 18615 * and the view will draw normally, using its full bounds. 18616 * 18617 * @param clipBounds The rectangular area, in the local coordinates of 18618 * this view, to which future drawing operations will be clipped. 18619 */ 18620 public void setClipBounds(Rect clipBounds) { 18621 if (clipBounds == mClipBounds 18622 || (clipBounds != null && clipBounds.equals(mClipBounds))) { 18623 return; 18624 } 18625 if (clipBounds != null) { 18626 if (mClipBounds == null) { 18627 mClipBounds = new Rect(clipBounds); 18628 } else { 18629 mClipBounds.set(clipBounds); 18630 } 18631 } else { 18632 mClipBounds = null; 18633 } 18634 mRenderNode.setClipBounds(mClipBounds); 18635 invalidateViewProperty(false, false); 18636 } 18637 18638 /** 18639 * Returns a copy of the current {@link #setClipBounds(Rect) clipBounds}. 18640 * 18641 * @return A copy of the current clip bounds if clip bounds are set, 18642 * otherwise null. 18643 */ 18644 public Rect getClipBounds() { 18645 return (mClipBounds != null) ? new Rect(mClipBounds) : null; 18646 } 18647 18648 18649 /** 18650 * Populates an output rectangle with the clip bounds of the view, 18651 * returning {@code true} if successful or {@code false} if the view's 18652 * clip bounds are {@code null}. 18653 * 18654 * @param outRect rectangle in which to place the clip bounds of the view 18655 * @return {@code true} if successful or {@code false} if the view's 18656 * clip bounds are {@code null} 18657 */ 18658 public boolean getClipBounds(Rect outRect) { 18659 if (mClipBounds != null) { 18660 outRect.set(mClipBounds); 18661 return true; 18662 } 18663 return false; 18664 } 18665 18666 /** 18667 * Utility function, called by draw(canvas, parent, drawingTime) to handle the less common 18668 * case of an active Animation being run on the view. 18669 */ 18670 private boolean applyLegacyAnimation(ViewGroup parent, long drawingTime, 18671 Animation a, boolean scalingRequired) { 18672 Transformation invalidationTransform; 18673 final int flags = parent.mGroupFlags; 18674 final boolean initialized = a.isInitialized(); 18675 if (!initialized) { 18676 a.initialize(mRight - mLeft, mBottom - mTop, parent.getWidth(), parent.getHeight()); 18677 a.initializeInvalidateRegion(0, 0, mRight - mLeft, mBottom - mTop); 18678 if (mAttachInfo != null) a.setListenerHandler(mAttachInfo.mHandler); 18679 onAnimationStart(); 18680 } 18681 18682 final Transformation t = parent.getChildTransformation(); 18683 boolean more = a.getTransformation(drawingTime, t, 1f); 18684 if (scalingRequired && mAttachInfo.mApplicationScale != 1f) { 18685 if (parent.mInvalidationTransformation == null) { 18686 parent.mInvalidationTransformation = new Transformation(); 18687 } 18688 invalidationTransform = parent.mInvalidationTransformation; 18689 a.getTransformation(drawingTime, invalidationTransform, 1f); 18690 } else { 18691 invalidationTransform = t; 18692 } 18693 18694 if (more) { 18695 if (!a.willChangeBounds()) { 18696 if ((flags & (ViewGroup.FLAG_OPTIMIZE_INVALIDATE | ViewGroup.FLAG_ANIMATION_DONE)) == 18697 ViewGroup.FLAG_OPTIMIZE_INVALIDATE) { 18698 parent.mGroupFlags |= ViewGroup.FLAG_INVALIDATE_REQUIRED; 18699 } else if ((flags & ViewGroup.FLAG_INVALIDATE_REQUIRED) == 0) { 18700 // The child need to draw an animation, potentially offscreen, so 18701 // make sure we do not cancel invalidate requests 18702 parent.mPrivateFlags |= PFLAG_DRAW_ANIMATION; 18703 parent.invalidate(mLeft, mTop, mRight, mBottom); 18704 } 18705 } else { 18706 if (parent.mInvalidateRegion == null) { 18707 parent.mInvalidateRegion = new RectF(); 18708 } 18709 final RectF region = parent.mInvalidateRegion; 18710 a.getInvalidateRegion(0, 0, mRight - mLeft, mBottom - mTop, region, 18711 invalidationTransform); 18712 18713 // The child need to draw an animation, potentially offscreen, so 18714 // make sure we do not cancel invalidate requests 18715 parent.mPrivateFlags |= PFLAG_DRAW_ANIMATION; 18716 18717 final int left = mLeft + (int) region.left; 18718 final int top = mTop + (int) region.top; 18719 parent.invalidate(left, top, left + (int) (region.width() + .5f), 18720 top + (int) (region.height() + .5f)); 18721 } 18722 } 18723 return more; 18724 } 18725 18726 /** 18727 * This method is called by getDisplayList() when a display list is recorded for a View. 18728 * It pushes any properties to the RenderNode that aren't managed by the RenderNode. 18729 */ 18730 void setDisplayListProperties(RenderNode renderNode) { 18731 if (renderNode != null) { 18732 renderNode.setHasOverlappingRendering(getHasOverlappingRendering()); 18733 renderNode.setClipToBounds(mParent instanceof ViewGroup 18734 && ((ViewGroup) mParent).getClipChildren()); 18735 18736 float alpha = 1; 18737 if (mParent instanceof ViewGroup && (((ViewGroup) mParent).mGroupFlags & 18738 ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) != 0) { 18739 ViewGroup parentVG = (ViewGroup) mParent; 18740 final Transformation t = parentVG.getChildTransformation(); 18741 if (parentVG.getChildStaticTransformation(this, t)) { 18742 final int transformType = t.getTransformationType(); 18743 if (transformType != Transformation.TYPE_IDENTITY) { 18744 if ((transformType & Transformation.TYPE_ALPHA) != 0) { 18745 alpha = t.getAlpha(); 18746 } 18747 if ((transformType & Transformation.TYPE_MATRIX) != 0) { 18748 renderNode.setStaticMatrix(t.getMatrix()); 18749 } 18750 } 18751 } 18752 } 18753 if (mTransformationInfo != null) { 18754 alpha *= getFinalAlpha(); 18755 if (alpha < 1) { 18756 final int multipliedAlpha = (int) (255 * alpha); 18757 if (onSetAlpha(multipliedAlpha)) { 18758 alpha = 1; 18759 } 18760 } 18761 renderNode.setAlpha(alpha); 18762 } else if (alpha < 1) { 18763 renderNode.setAlpha(alpha); 18764 } 18765 } 18766 } 18767 18768 /** 18769 * This method is called by ViewGroup.drawChild() to have each child view draw itself. 18770 * 18771 * This is where the View specializes rendering behavior based on layer type, 18772 * and hardware acceleration. 18773 */ 18774 boolean draw(Canvas canvas, ViewGroup parent, long drawingTime) { 18775 final boolean hardwareAcceleratedCanvas = canvas.isHardwareAccelerated(); 18776 /* If an attached view draws to a HW canvas, it may use its RenderNode + DisplayList. 18777 * 18778 * If a view is dettached, its DisplayList shouldn't exist. If the canvas isn't 18779 * HW accelerated, it can't handle drawing RenderNodes. 18780 */ 18781 boolean drawingWithRenderNode = mAttachInfo != null 18782 && mAttachInfo.mHardwareAccelerated 18783 && hardwareAcceleratedCanvas; 18784 18785 boolean more = false; 18786 final boolean childHasIdentityMatrix = hasIdentityMatrix(); 18787 final int parentFlags = parent.mGroupFlags; 18788 18789 if ((parentFlags & ViewGroup.FLAG_CLEAR_TRANSFORMATION) != 0) { 18790 parent.getChildTransformation().clear(); 18791 parent.mGroupFlags &= ~ViewGroup.FLAG_CLEAR_TRANSFORMATION; 18792 } 18793 18794 Transformation transformToApply = null; 18795 boolean concatMatrix = false; 18796 final boolean scalingRequired = mAttachInfo != null && mAttachInfo.mScalingRequired; 18797 final Animation a = getAnimation(); 18798 if (a != null) { 18799 more = applyLegacyAnimation(parent, drawingTime, a, scalingRequired); 18800 concatMatrix = a.willChangeTransformationMatrix(); 18801 if (concatMatrix) { 18802 mPrivateFlags3 |= PFLAG3_VIEW_IS_ANIMATING_TRANSFORM; 18803 } 18804 transformToApply = parent.getChildTransformation(); 18805 } else { 18806 if ((mPrivateFlags3 & PFLAG3_VIEW_IS_ANIMATING_TRANSFORM) != 0) { 18807 // No longer animating: clear out old animation matrix 18808 mRenderNode.setAnimationMatrix(null); 18809 mPrivateFlags3 &= ~PFLAG3_VIEW_IS_ANIMATING_TRANSFORM; 18810 } 18811 if (!drawingWithRenderNode 18812 && (parentFlags & ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) != 0) { 18813 final Transformation t = parent.getChildTransformation(); 18814 final boolean hasTransform = parent.getChildStaticTransformation(this, t); 18815 if (hasTransform) { 18816 final int transformType = t.getTransformationType(); 18817 transformToApply = transformType != Transformation.TYPE_IDENTITY ? t : null; 18818 concatMatrix = (transformType & Transformation.TYPE_MATRIX) != 0; 18819 } 18820 } 18821 } 18822 18823 concatMatrix |= !childHasIdentityMatrix; 18824 18825 // Sets the flag as early as possible to allow draw() implementations 18826 // to call invalidate() successfully when doing animations 18827 mPrivateFlags |= PFLAG_DRAWN; 18828 18829 if (!concatMatrix && 18830 (parentFlags & (ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS | 18831 ViewGroup.FLAG_CLIP_CHILDREN)) == ViewGroup.FLAG_CLIP_CHILDREN && 18832 canvas.quickReject(mLeft, mTop, mRight, mBottom, Canvas.EdgeType.BW) && 18833 (mPrivateFlags & PFLAG_DRAW_ANIMATION) == 0) { 18834 mPrivateFlags2 |= PFLAG2_VIEW_QUICK_REJECTED; 18835 return more; 18836 } 18837 mPrivateFlags2 &= ~PFLAG2_VIEW_QUICK_REJECTED; 18838 18839 if (hardwareAcceleratedCanvas) { 18840 // Clear INVALIDATED flag to allow invalidation to occur during rendering, but 18841 // retain the flag's value temporarily in the mRecreateDisplayList flag 18842 mRecreateDisplayList = (mPrivateFlags & PFLAG_INVALIDATED) != 0; 18843 mPrivateFlags &= ~PFLAG_INVALIDATED; 18844 } 18845 18846 RenderNode renderNode = null; 18847 Bitmap cache = null; 18848 int layerType = getLayerType(); // TODO: signify cache state with just 'cache' local 18849 if (layerType == LAYER_TYPE_SOFTWARE || !drawingWithRenderNode) { 18850 if (layerType != LAYER_TYPE_NONE) { 18851 // If not drawing with RenderNode, treat HW layers as SW 18852 layerType = LAYER_TYPE_SOFTWARE; 18853 buildDrawingCache(true); 18854 } 18855 cache = getDrawingCache(true); 18856 } 18857 18858 if (drawingWithRenderNode) { 18859 // Delay getting the display list until animation-driven alpha values are 18860 // set up and possibly passed on to the view 18861 renderNode = updateDisplayListIfDirty(); 18862 if (!renderNode.isValid()) { 18863 // Uncommon, but possible. If a view is removed from the hierarchy during the call 18864 // to getDisplayList(), the display list will be marked invalid and we should not 18865 // try to use it again. 18866 renderNode = null; 18867 drawingWithRenderNode = false; 18868 } 18869 } 18870 18871 int sx = 0; 18872 int sy = 0; 18873 if (!drawingWithRenderNode) { 18874 computeScroll(); 18875 sx = mScrollX; 18876 sy = mScrollY; 18877 } 18878 18879 final boolean drawingWithDrawingCache = cache != null && !drawingWithRenderNode; 18880 final boolean offsetForScroll = cache == null && !drawingWithRenderNode; 18881 18882 int restoreTo = -1; 18883 if (!drawingWithRenderNode || transformToApply != null) { 18884 restoreTo = canvas.save(); 18885 } 18886 if (offsetForScroll) { 18887 canvas.translate(mLeft - sx, mTop - sy); 18888 } else { 18889 if (!drawingWithRenderNode) { 18890 canvas.translate(mLeft, mTop); 18891 } 18892 if (scalingRequired) { 18893 if (drawingWithRenderNode) { 18894 // TODO: Might not need this if we put everything inside the DL 18895 restoreTo = canvas.save(); 18896 } 18897 // mAttachInfo cannot be null, otherwise scalingRequired == false 18898 final float scale = 1.0f / mAttachInfo.mApplicationScale; 18899 canvas.scale(scale, scale); 18900 } 18901 } 18902 18903 float alpha = drawingWithRenderNode ? 1 : (getAlpha() * getTransitionAlpha()); 18904 if (transformToApply != null 18905 || alpha < 1 18906 || !hasIdentityMatrix() 18907 || (mPrivateFlags3 & PFLAG3_VIEW_IS_ANIMATING_ALPHA) != 0) { 18908 if (transformToApply != null || !childHasIdentityMatrix) { 18909 int transX = 0; 18910 int transY = 0; 18911 18912 if (offsetForScroll) { 18913 transX = -sx; 18914 transY = -sy; 18915 } 18916 18917 if (transformToApply != null) { 18918 if (concatMatrix) { 18919 if (drawingWithRenderNode) { 18920 renderNode.setAnimationMatrix(transformToApply.getMatrix()); 18921 } else { 18922 // Undo the scroll translation, apply the transformation matrix, 18923 // then redo the scroll translate to get the correct result. 18924 canvas.translate(-transX, -transY); 18925 canvas.concat(transformToApply.getMatrix()); 18926 canvas.translate(transX, transY); 18927 } 18928 parent.mGroupFlags |= ViewGroup.FLAG_CLEAR_TRANSFORMATION; 18929 } 18930 18931 float transformAlpha = transformToApply.getAlpha(); 18932 if (transformAlpha < 1) { 18933 alpha *= transformAlpha; 18934 parent.mGroupFlags |= ViewGroup.FLAG_CLEAR_TRANSFORMATION; 18935 } 18936 } 18937 18938 if (!childHasIdentityMatrix && !drawingWithRenderNode) { 18939 canvas.translate(-transX, -transY); 18940 canvas.concat(getMatrix()); 18941 canvas.translate(transX, transY); 18942 } 18943 } 18944 18945 // Deal with alpha if it is or used to be <1 18946 if (alpha < 1 || (mPrivateFlags3 & PFLAG3_VIEW_IS_ANIMATING_ALPHA) != 0) { 18947 if (alpha < 1) { 18948 mPrivateFlags3 |= PFLAG3_VIEW_IS_ANIMATING_ALPHA; 18949 } else { 18950 mPrivateFlags3 &= ~PFLAG3_VIEW_IS_ANIMATING_ALPHA; 18951 } 18952 parent.mGroupFlags |= ViewGroup.FLAG_CLEAR_TRANSFORMATION; 18953 if (!drawingWithDrawingCache) { 18954 final int multipliedAlpha = (int) (255 * alpha); 18955 if (!onSetAlpha(multipliedAlpha)) { 18956 if (drawingWithRenderNode) { 18957 renderNode.setAlpha(alpha * getAlpha() * getTransitionAlpha()); 18958 } else if (layerType == LAYER_TYPE_NONE) { 18959 canvas.saveLayerAlpha(sx, sy, sx + getWidth(), sy + getHeight(), 18960 multipliedAlpha); 18961 } 18962 } else { 18963 // Alpha is handled by the child directly, clobber the layer's alpha 18964 mPrivateFlags |= PFLAG_ALPHA_SET; 18965 } 18966 } 18967 } 18968 } else if ((mPrivateFlags & PFLAG_ALPHA_SET) == PFLAG_ALPHA_SET) { 18969 onSetAlpha(255); 18970 mPrivateFlags &= ~PFLAG_ALPHA_SET; 18971 } 18972 18973 if (!drawingWithRenderNode) { 18974 // apply clips directly, since RenderNode won't do it for this draw 18975 if ((parentFlags & ViewGroup.FLAG_CLIP_CHILDREN) != 0 && cache == null) { 18976 if (offsetForScroll) { 18977 canvas.clipRect(sx, sy, sx + getWidth(), sy + getHeight()); 18978 } else { 18979 if (!scalingRequired || cache == null) { 18980 canvas.clipRect(0, 0, getWidth(), getHeight()); 18981 } else { 18982 canvas.clipRect(0, 0, cache.getWidth(), cache.getHeight()); 18983 } 18984 } 18985 } 18986 18987 if (mClipBounds != null) { 18988 // clip bounds ignore scroll 18989 canvas.clipRect(mClipBounds); 18990 } 18991 } 18992 18993 if (!drawingWithDrawingCache) { 18994 if (drawingWithRenderNode) { 18995 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 18996 ((DisplayListCanvas) canvas).drawRenderNode(renderNode); 18997 } else { 18998 // Fast path for layouts with no backgrounds 18999 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { 19000 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 19001 dispatchDraw(canvas); 19002 } else { 19003 draw(canvas); 19004 } 19005 } 19006 } else if (cache != null) { 19007 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 19008 if (layerType == LAYER_TYPE_NONE || mLayerPaint == null) { 19009 // no layer paint, use temporary paint to draw bitmap 19010 Paint cachePaint = parent.mCachePaint; 19011 if (cachePaint == null) { 19012 cachePaint = new Paint(); 19013 cachePaint.setDither(false); 19014 parent.mCachePaint = cachePaint; 19015 } 19016 cachePaint.setAlpha((int) (alpha * 255)); 19017 canvas.drawBitmap(cache, 0.0f, 0.0f, cachePaint); 19018 } else { 19019 // use layer paint to draw the bitmap, merging the two alphas, but also restore 19020 int layerPaintAlpha = mLayerPaint.getAlpha(); 19021 if (alpha < 1) { 19022 mLayerPaint.setAlpha((int) (alpha * layerPaintAlpha)); 19023 } 19024 canvas.drawBitmap(cache, 0.0f, 0.0f, mLayerPaint); 19025 if (alpha < 1) { 19026 mLayerPaint.setAlpha(layerPaintAlpha); 19027 } 19028 } 19029 } 19030 19031 if (restoreTo >= 0) { 19032 canvas.restoreToCount(restoreTo); 19033 } 19034 19035 if (a != null && !more) { 19036 if (!hardwareAcceleratedCanvas && !a.getFillAfter()) { 19037 onSetAlpha(255); 19038 } 19039 parent.finishAnimatingView(this, a); 19040 } 19041 19042 if (more && hardwareAcceleratedCanvas) { 19043 if (a.hasAlpha() && (mPrivateFlags & PFLAG_ALPHA_SET) == PFLAG_ALPHA_SET) { 19044 // alpha animations should cause the child to recreate its display list 19045 invalidate(true); 19046 } 19047 } 19048 19049 mRecreateDisplayList = false; 19050 19051 return more; 19052 } 19053 19054 static Paint getDebugPaint() { 19055 if (sDebugPaint == null) { 19056 sDebugPaint = new Paint(); 19057 sDebugPaint.setAntiAlias(false); 19058 } 19059 return sDebugPaint; 19060 } 19061 19062 final int dipsToPixels(int dips) { 19063 float scale = getContext().getResources().getDisplayMetrics().density; 19064 return (int) (dips * scale + 0.5f); 19065 } 19066 19067 final private void debugDrawFocus(Canvas canvas) { 19068 if (isFocused()) { 19069 final int cornerSquareSize = dipsToPixels(DEBUG_CORNERS_SIZE_DIP); 19070 final int l = mScrollX; 19071 final int r = l + mRight - mLeft; 19072 final int t = mScrollY; 19073 final int b = t + mBottom - mTop; 19074 19075 final Paint paint = getDebugPaint(); 19076 paint.setColor(DEBUG_CORNERS_COLOR); 19077 19078 // Draw squares in corners. 19079 paint.setStyle(Paint.Style.FILL); 19080 canvas.drawRect(l, t, l + cornerSquareSize, t + cornerSquareSize, paint); 19081 canvas.drawRect(r - cornerSquareSize, t, r, t + cornerSquareSize, paint); 19082 canvas.drawRect(l, b - cornerSquareSize, l + cornerSquareSize, b, paint); 19083 canvas.drawRect(r - cornerSquareSize, b - cornerSquareSize, r, b, paint); 19084 19085 // Draw big X across the view. 19086 paint.setStyle(Paint.Style.STROKE); 19087 canvas.drawLine(l, t, r, b, paint); 19088 canvas.drawLine(l, b, r, t, paint); 19089 } 19090 } 19091 19092 /** 19093 * Manually render this view (and all of its children) to the given Canvas. 19094 * The view must have already done a full layout before this function is 19095 * called. When implementing a view, implement 19096 * {@link #onDraw(android.graphics.Canvas)} instead of overriding this method. 19097 * If you do need to override this method, call the superclass version. 19098 * 19099 * @param canvas The Canvas to which the View is rendered. 19100 */ 19101 @CallSuper 19102 public void draw(Canvas canvas) { 19103 final int privateFlags = mPrivateFlags; 19104 final boolean dirtyOpaque = (privateFlags & PFLAG_DIRTY_MASK) == PFLAG_DIRTY_OPAQUE && 19105 (mAttachInfo == null || !mAttachInfo.mIgnoreDirtyState); 19106 mPrivateFlags = (privateFlags & ~PFLAG_DIRTY_MASK) | PFLAG_DRAWN; 19107 19108 /* 19109 * Draw traversal performs several drawing steps which must be executed 19110 * in the appropriate order: 19111 * 19112 * 1. Draw the background 19113 * 2. If necessary, save the canvas' layers to prepare for fading 19114 * 3. Draw view's content 19115 * 4. Draw children 19116 * 5. If necessary, draw the fading edges and restore layers 19117 * 6. Draw decorations (scrollbars for instance) 19118 */ 19119 19120 // Step 1, draw the background, if needed 19121 int saveCount; 19122 19123 if (!dirtyOpaque) { 19124 drawBackground(canvas); 19125 } 19126 19127 // skip step 2 & 5 if possible (common case) 19128 final int viewFlags = mViewFlags; 19129 boolean horizontalEdges = (viewFlags & FADING_EDGE_HORIZONTAL) != 0; 19130 boolean verticalEdges = (viewFlags & FADING_EDGE_VERTICAL) != 0; 19131 if (!verticalEdges && !horizontalEdges) { 19132 // Step 3, draw the content 19133 if (!dirtyOpaque) onDraw(canvas); 19134 19135 // Step 4, draw the children 19136 dispatchDraw(canvas); 19137 19138 drawAutofilledHighlight(canvas); 19139 19140 // Overlay is part of the content and draws beneath Foreground 19141 if (mOverlay != null && !mOverlay.isEmpty()) { 19142 mOverlay.getOverlayView().dispatchDraw(canvas); 19143 } 19144 19145 // Step 6, draw decorations (foreground, scrollbars) 19146 onDrawForeground(canvas); 19147 19148 // Step 7, draw the default focus highlight 19149 drawDefaultFocusHighlight(canvas); 19150 19151 if (debugDraw()) { 19152 debugDrawFocus(canvas); 19153 } 19154 19155 // we're done... 19156 return; 19157 } 19158 19159 /* 19160 * Here we do the full fledged routine... 19161 * (this is an uncommon case where speed matters less, 19162 * this is why we repeat some of the tests that have been 19163 * done above) 19164 */ 19165 19166 boolean drawTop = false; 19167 boolean drawBottom = false; 19168 boolean drawLeft = false; 19169 boolean drawRight = false; 19170 19171 float topFadeStrength = 0.0f; 19172 float bottomFadeStrength = 0.0f; 19173 float leftFadeStrength = 0.0f; 19174 float rightFadeStrength = 0.0f; 19175 19176 // Step 2, save the canvas' layers 19177 int paddingLeft = mPaddingLeft; 19178 19179 final boolean offsetRequired = isPaddingOffsetRequired(); 19180 if (offsetRequired) { 19181 paddingLeft += getLeftPaddingOffset(); 19182 } 19183 19184 int left = mScrollX + paddingLeft; 19185 int right = left + mRight - mLeft - mPaddingRight - paddingLeft; 19186 int top = mScrollY + getFadeTop(offsetRequired); 19187 int bottom = top + getFadeHeight(offsetRequired); 19188 19189 if (offsetRequired) { 19190 right += getRightPaddingOffset(); 19191 bottom += getBottomPaddingOffset(); 19192 } 19193 19194 final ScrollabilityCache scrollabilityCache = mScrollCache; 19195 final float fadeHeight = scrollabilityCache.fadingEdgeLength; 19196 int length = (int) fadeHeight; 19197 19198 // clip the fade length if top and bottom fades overlap 19199 // overlapping fades produce odd-looking artifacts 19200 if (verticalEdges && (top + length > bottom - length)) { 19201 length = (bottom - top) / 2; 19202 } 19203 19204 // also clip horizontal fades if necessary 19205 if (horizontalEdges && (left + length > right - length)) { 19206 length = (right - left) / 2; 19207 } 19208 19209 if (verticalEdges) { 19210 topFadeStrength = Math.max(0.0f, Math.min(1.0f, getTopFadingEdgeStrength())); 19211 drawTop = topFadeStrength * fadeHeight > 1.0f; 19212 bottomFadeStrength = Math.max(0.0f, Math.min(1.0f, getBottomFadingEdgeStrength())); 19213 drawBottom = bottomFadeStrength * fadeHeight > 1.0f; 19214 } 19215 19216 if (horizontalEdges) { 19217 leftFadeStrength = Math.max(0.0f, Math.min(1.0f, getLeftFadingEdgeStrength())); 19218 drawLeft = leftFadeStrength * fadeHeight > 1.0f; 19219 rightFadeStrength = Math.max(0.0f, Math.min(1.0f, getRightFadingEdgeStrength())); 19220 drawRight = rightFadeStrength * fadeHeight > 1.0f; 19221 } 19222 19223 saveCount = canvas.getSaveCount(); 19224 19225 int solidColor = getSolidColor(); 19226 if (solidColor == 0) { 19227 final int flags = Canvas.HAS_ALPHA_LAYER_SAVE_FLAG; 19228 19229 if (drawTop) { 19230 canvas.saveLayer(left, top, right, top + length, null, flags); 19231 } 19232 19233 if (drawBottom) { 19234 canvas.saveLayer(left, bottom - length, right, bottom, null, flags); 19235 } 19236 19237 if (drawLeft) { 19238 canvas.saveLayer(left, top, left + length, bottom, null, flags); 19239 } 19240 19241 if (drawRight) { 19242 canvas.saveLayer(right - length, top, right, bottom, null, flags); 19243 } 19244 } else { 19245 scrollabilityCache.setFadeColor(solidColor); 19246 } 19247 19248 // Step 3, draw the content 19249 if (!dirtyOpaque) onDraw(canvas); 19250 19251 // Step 4, draw the children 19252 dispatchDraw(canvas); 19253 19254 // Step 5, draw the fade effect and restore layers 19255 final Paint p = scrollabilityCache.paint; 19256 final Matrix matrix = scrollabilityCache.matrix; 19257 final Shader fade = scrollabilityCache.shader; 19258 19259 if (drawTop) { 19260 matrix.setScale(1, fadeHeight * topFadeStrength); 19261 matrix.postTranslate(left, top); 19262 fade.setLocalMatrix(matrix); 19263 p.setShader(fade); 19264 canvas.drawRect(left, top, right, top + length, p); 19265 } 19266 19267 if (drawBottom) { 19268 matrix.setScale(1, fadeHeight * bottomFadeStrength); 19269 matrix.postRotate(180); 19270 matrix.postTranslate(left, bottom); 19271 fade.setLocalMatrix(matrix); 19272 p.setShader(fade); 19273 canvas.drawRect(left, bottom - length, right, bottom, p); 19274 } 19275 19276 if (drawLeft) { 19277 matrix.setScale(1, fadeHeight * leftFadeStrength); 19278 matrix.postRotate(-90); 19279 matrix.postTranslate(left, top); 19280 fade.setLocalMatrix(matrix); 19281 p.setShader(fade); 19282 canvas.drawRect(left, top, left + length, bottom, p); 19283 } 19284 19285 if (drawRight) { 19286 matrix.setScale(1, fadeHeight * rightFadeStrength); 19287 matrix.postRotate(90); 19288 matrix.postTranslate(right, top); 19289 fade.setLocalMatrix(matrix); 19290 p.setShader(fade); 19291 canvas.drawRect(right - length, top, right, bottom, p); 19292 } 19293 19294 canvas.restoreToCount(saveCount); 19295 19296 drawAutofilledHighlight(canvas); 19297 19298 // Overlay is part of the content and draws beneath Foreground 19299 if (mOverlay != null && !mOverlay.isEmpty()) { 19300 mOverlay.getOverlayView().dispatchDraw(canvas); 19301 } 19302 19303 // Step 6, draw decorations (foreground, scrollbars) 19304 onDrawForeground(canvas); 19305 19306 if (debugDraw()) { 19307 debugDrawFocus(canvas); 19308 } 19309 } 19310 19311 /** 19312 * Draws the background onto the specified canvas. 19313 * 19314 * @param canvas Canvas on which to draw the background 19315 */ 19316 private void drawBackground(Canvas canvas) { 19317 final Drawable background = mBackground; 19318 if (background == null) { 19319 return; 19320 } 19321 19322 setBackgroundBounds(); 19323 19324 // Attempt to use a display list if requested. 19325 if (canvas.isHardwareAccelerated() && mAttachInfo != null 19326 && mAttachInfo.mThreadedRenderer != null) { 19327 mBackgroundRenderNode = getDrawableRenderNode(background, mBackgroundRenderNode); 19328 19329 final RenderNode renderNode = mBackgroundRenderNode; 19330 if (renderNode != null && renderNode.isValid()) { 19331 setBackgroundRenderNodeProperties(renderNode); 19332 ((DisplayListCanvas) canvas).drawRenderNode(renderNode); 19333 return; 19334 } 19335 } 19336 19337 final int scrollX = mScrollX; 19338 final int scrollY = mScrollY; 19339 if ((scrollX | scrollY) == 0) { 19340 background.draw(canvas); 19341 } else { 19342 canvas.translate(scrollX, scrollY); 19343 background.draw(canvas); 19344 canvas.translate(-scrollX, -scrollY); 19345 } 19346 } 19347 19348 /** 19349 * Sets the correct background bounds and rebuilds the outline, if needed. 19350 * <p/> 19351 * This is called by LayoutLib. 19352 */ 19353 void setBackgroundBounds() { 19354 if (mBackgroundSizeChanged && mBackground != null) { 19355 mBackground.setBounds(0, 0, mRight - mLeft, mBottom - mTop); 19356 mBackgroundSizeChanged = false; 19357 rebuildOutline(); 19358 } 19359 } 19360 19361 private void setBackgroundRenderNodeProperties(RenderNode renderNode) { 19362 renderNode.setTranslationX(mScrollX); 19363 renderNode.setTranslationY(mScrollY); 19364 } 19365 19366 /** 19367 * Creates a new display list or updates the existing display list for the 19368 * specified Drawable. 19369 * 19370 * @param drawable Drawable for which to create a display list 19371 * @param renderNode Existing RenderNode, or {@code null} 19372 * @return A valid display list for the specified drawable 19373 */ 19374 private RenderNode getDrawableRenderNode(Drawable drawable, RenderNode renderNode) { 19375 if (renderNode == null) { 19376 renderNode = RenderNode.create(drawable.getClass().getName(), this); 19377 } 19378 19379 final Rect bounds = drawable.getBounds(); 19380 final int width = bounds.width(); 19381 final int height = bounds.height(); 19382 final DisplayListCanvas canvas = renderNode.start(width, height); 19383 19384 // Reverse left/top translation done by drawable canvas, which will 19385 // instead be applied by rendernode's LTRB bounds below. This way, the 19386 // drawable's bounds match with its rendernode bounds and its content 19387 // will lie within those bounds in the rendernode tree. 19388 canvas.translate(-bounds.left, -bounds.top); 19389 19390 try { 19391 drawable.draw(canvas); 19392 } finally { 19393 renderNode.end(canvas); 19394 } 19395 19396 // Set up drawable properties that are view-independent. 19397 renderNode.setLeftTopRightBottom(bounds.left, bounds.top, bounds.right, bounds.bottom); 19398 renderNode.setProjectBackwards(drawable.isProjected()); 19399 renderNode.setProjectionReceiver(true); 19400 renderNode.setClipToBounds(false); 19401 return renderNode; 19402 } 19403 19404 /** 19405 * Returns the overlay for this view, creating it if it does not yet exist. 19406 * Adding drawables to the overlay will cause them to be displayed whenever 19407 * the view itself is redrawn. Objects in the overlay should be actively 19408 * managed: remove them when they should not be displayed anymore. The 19409 * overlay will always have the same size as its host view. 19410 * 19411 * <p>Note: Overlays do not currently work correctly with {@link 19412 * SurfaceView} or {@link TextureView}; contents in overlays for these 19413 * types of views may not display correctly.</p> 19414 * 19415 * @return The ViewOverlay object for this view. 19416 * @see ViewOverlay 19417 */ 19418 public ViewOverlay getOverlay() { 19419 if (mOverlay == null) { 19420 mOverlay = new ViewOverlay(mContext, this); 19421 } 19422 return mOverlay; 19423 } 19424 19425 /** 19426 * Override this if your view is known to always be drawn on top of a solid color background, 19427 * and needs to draw fading edges. Returning a non-zero color enables the view system to 19428 * optimize the drawing of the fading edges. If you do return a non-zero color, the alpha 19429 * should be set to 0xFF. 19430 * 19431 * @see #setVerticalFadingEdgeEnabled(boolean) 19432 * @see #setHorizontalFadingEdgeEnabled(boolean) 19433 * 19434 * @return The known solid color background for this view, or 0 if the color may vary 19435 */ 19436 @ViewDebug.ExportedProperty(category = "drawing") 19437 @ColorInt 19438 public int getSolidColor() { 19439 return 0; 19440 } 19441 19442 /** 19443 * Build a human readable string representation of the specified view flags. 19444 * 19445 * @param flags the view flags to convert to a string 19446 * @return a String representing the supplied flags 19447 */ 19448 private static String printFlags(int flags) { 19449 String output = ""; 19450 int numFlags = 0; 19451 if ((flags & FOCUSABLE) == FOCUSABLE) { 19452 output += "TAKES_FOCUS"; 19453 numFlags++; 19454 } 19455 19456 switch (flags & VISIBILITY_MASK) { 19457 case INVISIBLE: 19458 if (numFlags > 0) { 19459 output += " "; 19460 } 19461 output += "INVISIBLE"; 19462 // USELESS HERE numFlags++; 19463 break; 19464 case GONE: 19465 if (numFlags > 0) { 19466 output += " "; 19467 } 19468 output += "GONE"; 19469 // USELESS HERE numFlags++; 19470 break; 19471 default: 19472 break; 19473 } 19474 return output; 19475 } 19476 19477 /** 19478 * Build a human readable string representation of the specified private 19479 * view flags. 19480 * 19481 * @param privateFlags the private view flags to convert to a string 19482 * @return a String representing the supplied flags 19483 */ 19484 private static String printPrivateFlags(int privateFlags) { 19485 String output = ""; 19486 int numFlags = 0; 19487 19488 if ((privateFlags & PFLAG_WANTS_FOCUS) == PFLAG_WANTS_FOCUS) { 19489 output += "WANTS_FOCUS"; 19490 numFlags++; 19491 } 19492 19493 if ((privateFlags & PFLAG_FOCUSED) == PFLAG_FOCUSED) { 19494 if (numFlags > 0) { 19495 output += " "; 19496 } 19497 output += "FOCUSED"; 19498 numFlags++; 19499 } 19500 19501 if ((privateFlags & PFLAG_SELECTED) == PFLAG_SELECTED) { 19502 if (numFlags > 0) { 19503 output += " "; 19504 } 19505 output += "SELECTED"; 19506 numFlags++; 19507 } 19508 19509 if ((privateFlags & PFLAG_IS_ROOT_NAMESPACE) == PFLAG_IS_ROOT_NAMESPACE) { 19510 if (numFlags > 0) { 19511 output += " "; 19512 } 19513 output += "IS_ROOT_NAMESPACE"; 19514 numFlags++; 19515 } 19516 19517 if ((privateFlags & PFLAG_HAS_BOUNDS) == PFLAG_HAS_BOUNDS) { 19518 if (numFlags > 0) { 19519 output += " "; 19520 } 19521 output += "HAS_BOUNDS"; 19522 numFlags++; 19523 } 19524 19525 if ((privateFlags & PFLAG_DRAWN) == PFLAG_DRAWN) { 19526 if (numFlags > 0) { 19527 output += " "; 19528 } 19529 output += "DRAWN"; 19530 // USELESS HERE numFlags++; 19531 } 19532 return output; 19533 } 19534 19535 /** 19536 * <p>Indicates whether or not this view's layout will be requested during 19537 * the next hierarchy layout pass.</p> 19538 * 19539 * @return true if the layout will be forced during next layout pass 19540 */ 19541 public boolean isLayoutRequested() { 19542 return (mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT; 19543 } 19544 19545 /** 19546 * Return true if o is a ViewGroup that is laying out using optical bounds. 19547 * @hide 19548 */ 19549 public static boolean isLayoutModeOptical(Object o) { 19550 return o instanceof ViewGroup && ((ViewGroup) o).isLayoutModeOptical(); 19551 } 19552 19553 private boolean setOpticalFrame(int left, int top, int right, int bottom) { 19554 Insets parentInsets = mParent instanceof View ? 19555 ((View) mParent).getOpticalInsets() : Insets.NONE; 19556 Insets childInsets = getOpticalInsets(); 19557 return setFrame( 19558 left + parentInsets.left - childInsets.left, 19559 top + parentInsets.top - childInsets.top, 19560 right + parentInsets.left + childInsets.right, 19561 bottom + parentInsets.top + childInsets.bottom); 19562 } 19563 19564 /** 19565 * Assign a size and position to a view and all of its 19566 * descendants 19567 * 19568 * <p>This is the second phase of the layout mechanism. 19569 * (The first is measuring). In this phase, each parent calls 19570 * layout on all of its children to position them. 19571 * This is typically done using the child measurements 19572 * that were stored in the measure pass().</p> 19573 * 19574 * <p>Derived classes should not override this method. 19575 * Derived classes with children should override 19576 * onLayout. In that method, they should 19577 * call layout on each of their children.</p> 19578 * 19579 * @param l Left position, relative to parent 19580 * @param t Top position, relative to parent 19581 * @param r Right position, relative to parent 19582 * @param b Bottom position, relative to parent 19583 */ 19584 @SuppressWarnings({"unchecked"}) 19585 public void layout(int l, int t, int r, int b) { 19586 if ((mPrivateFlags3 & PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT) != 0) { 19587 onMeasure(mOldWidthMeasureSpec, mOldHeightMeasureSpec); 19588 mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT; 19589 } 19590 19591 int oldL = mLeft; 19592 int oldT = mTop; 19593 int oldB = mBottom; 19594 int oldR = mRight; 19595 19596 boolean changed = isLayoutModeOptical(mParent) ? 19597 setOpticalFrame(l, t, r, b) : setFrame(l, t, r, b); 19598 19599 if (changed || (mPrivateFlags & PFLAG_LAYOUT_REQUIRED) == PFLAG_LAYOUT_REQUIRED) { 19600 onLayout(changed, l, t, r, b); 19601 19602 if (shouldDrawRoundScrollbar()) { 19603 if(mRoundScrollbarRenderer == null) { 19604 mRoundScrollbarRenderer = new RoundScrollbarRenderer(this); 19605 } 19606 } else { 19607 mRoundScrollbarRenderer = null; 19608 } 19609 19610 mPrivateFlags &= ~PFLAG_LAYOUT_REQUIRED; 19611 19612 ListenerInfo li = mListenerInfo; 19613 if (li != null && li.mOnLayoutChangeListeners != null) { 19614 ArrayList<OnLayoutChangeListener> listenersCopy = 19615 (ArrayList<OnLayoutChangeListener>)li.mOnLayoutChangeListeners.clone(); 19616 int numListeners = listenersCopy.size(); 19617 for (int i = 0; i < numListeners; ++i) { 19618 listenersCopy.get(i).onLayoutChange(this, l, t, r, b, oldL, oldT, oldR, oldB); 19619 } 19620 } 19621 } 19622 19623 mPrivateFlags &= ~PFLAG_FORCE_LAYOUT; 19624 mPrivateFlags3 |= PFLAG3_IS_LAID_OUT; 19625 19626 if ((mPrivateFlags3 & PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT) != 0) { 19627 mPrivateFlags3 &= ~PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT; 19628 notifyEnterOrExitForAutoFillIfNeeded(true); 19629 } 19630 } 19631 19632 /** 19633 * Called from layout when this view should 19634 * assign a size and position to each of its children. 19635 * 19636 * Derived classes with children should override 19637 * this method and call layout on each of 19638 * their children. 19639 * @param changed This is a new size or position for this view 19640 * @param left Left position, relative to parent 19641 * @param top Top position, relative to parent 19642 * @param right Right position, relative to parent 19643 * @param bottom Bottom position, relative to parent 19644 */ 19645 protected void onLayout(boolean changed, int left, int top, int right, int bottom) { 19646 } 19647 19648 /** 19649 * Assign a size and position to this view. 19650 * 19651 * This is called from layout. 19652 * 19653 * @param left Left position, relative to parent 19654 * @param top Top position, relative to parent 19655 * @param right Right position, relative to parent 19656 * @param bottom Bottom position, relative to parent 19657 * @return true if the new size and position are different than the 19658 * previous ones 19659 * {@hide} 19660 */ 19661 protected boolean setFrame(int left, int top, int right, int bottom) { 19662 boolean changed = false; 19663 19664 if (DBG) { 19665 Log.d("View", this + " View.setFrame(" + left + "," + top + "," 19666 + right + "," + bottom + ")"); 19667 } 19668 19669 if (mLeft != left || mRight != right || mTop != top || mBottom != bottom) { 19670 changed = true; 19671 19672 // Remember our drawn bit 19673 int drawn = mPrivateFlags & PFLAG_DRAWN; 19674 19675 int oldWidth = mRight - mLeft; 19676 int oldHeight = mBottom - mTop; 19677 int newWidth = right - left; 19678 int newHeight = bottom - top; 19679 boolean sizeChanged = (newWidth != oldWidth) || (newHeight != oldHeight); 19680 19681 // Invalidate our old position 19682 invalidate(sizeChanged); 19683 19684 mLeft = left; 19685 mTop = top; 19686 mRight = right; 19687 mBottom = bottom; 19688 mRenderNode.setLeftTopRightBottom(mLeft, mTop, mRight, mBottom); 19689 19690 mPrivateFlags |= PFLAG_HAS_BOUNDS; 19691 19692 19693 if (sizeChanged) { 19694 sizeChange(newWidth, newHeight, oldWidth, oldHeight); 19695 } 19696 19697 if ((mViewFlags & VISIBILITY_MASK) == VISIBLE || mGhostView != null) { 19698 // If we are visible, force the DRAWN bit to on so that 19699 // this invalidate will go through (at least to our parent). 19700 // This is because someone may have invalidated this view 19701 // before this call to setFrame came in, thereby clearing 19702 // the DRAWN bit. 19703 mPrivateFlags |= PFLAG_DRAWN; 19704 invalidate(sizeChanged); 19705 // parent display list may need to be recreated based on a change in the bounds 19706 // of any child 19707 invalidateParentCaches(); 19708 } 19709 19710 // Reset drawn bit to original value (invalidate turns it off) 19711 mPrivateFlags |= drawn; 19712 19713 mBackgroundSizeChanged = true; 19714 mDefaultFocusHighlightSizeChanged = true; 19715 if (mForegroundInfo != null) { 19716 mForegroundInfo.mBoundsChanged = true; 19717 } 19718 19719 notifySubtreeAccessibilityStateChangedIfNeeded(); 19720 } 19721 return changed; 19722 } 19723 19724 /** 19725 * Same as setFrame, but public and hidden. For use in {@link android.transition.ChangeBounds}. 19726 * @hide 19727 */ 19728 public void setLeftTopRightBottom(int left, int top, int right, int bottom) { 19729 setFrame(left, top, right, bottom); 19730 } 19731 19732 private void sizeChange(int newWidth, int newHeight, int oldWidth, int oldHeight) { 19733 onSizeChanged(newWidth, newHeight, oldWidth, oldHeight); 19734 if (mOverlay != null) { 19735 mOverlay.getOverlayView().setRight(newWidth); 19736 mOverlay.getOverlayView().setBottom(newHeight); 19737 } 19738 rebuildOutline(); 19739 } 19740 19741 /** 19742 * Finalize inflating a view from XML. This is called as the last phase 19743 * of inflation, after all child views have been added. 19744 * 19745 * <p>Even if the subclass overrides onFinishInflate, they should always be 19746 * sure to call the super method, so that we get called. 19747 */ 19748 @CallSuper 19749 protected void onFinishInflate() { 19750 } 19751 19752 /** 19753 * Returns the resources associated with this view. 19754 * 19755 * @return Resources object. 19756 */ 19757 public Resources getResources() { 19758 return mResources; 19759 } 19760 19761 /** 19762 * Invalidates the specified Drawable. 19763 * 19764 * @param drawable the drawable to invalidate 19765 */ 19766 @Override 19767 public void invalidateDrawable(@NonNull Drawable drawable) { 19768 if (verifyDrawable(drawable)) { 19769 final Rect dirty = drawable.getDirtyBounds(); 19770 final int scrollX = mScrollX; 19771 final int scrollY = mScrollY; 19772 19773 invalidate(dirty.left + scrollX, dirty.top + scrollY, 19774 dirty.right + scrollX, dirty.bottom + scrollY); 19775 rebuildOutline(); 19776 } 19777 } 19778 19779 /** 19780 * Schedules an action on a drawable to occur at a specified time. 19781 * 19782 * @param who the recipient of the action 19783 * @param what the action to run on the drawable 19784 * @param when the time at which the action must occur. Uses the 19785 * {@link SystemClock#uptimeMillis} timebase. 19786 */ 19787 @Override 19788 public void scheduleDrawable(@NonNull Drawable who, @NonNull Runnable what, long when) { 19789 if (verifyDrawable(who) && what != null) { 19790 final long delay = when - SystemClock.uptimeMillis(); 19791 if (mAttachInfo != null) { 19792 mAttachInfo.mViewRootImpl.mChoreographer.postCallbackDelayed( 19793 Choreographer.CALLBACK_ANIMATION, what, who, 19794 Choreographer.subtractFrameDelay(delay)); 19795 } else { 19796 // Postpone the runnable until we know 19797 // on which thread it needs to run. 19798 getRunQueue().postDelayed(what, delay); 19799 } 19800 } 19801 } 19802 19803 /** 19804 * Cancels a scheduled action on a drawable. 19805 * 19806 * @param who the recipient of the action 19807 * @param what the action to cancel 19808 */ 19809 @Override 19810 public void unscheduleDrawable(@NonNull Drawable who, @NonNull Runnable what) { 19811 if (verifyDrawable(who) && what != null) { 19812 if (mAttachInfo != null) { 19813 mAttachInfo.mViewRootImpl.mChoreographer.removeCallbacks( 19814 Choreographer.CALLBACK_ANIMATION, what, who); 19815 } 19816 getRunQueue().removeCallbacks(what); 19817 } 19818 } 19819 19820 /** 19821 * Unschedule any events associated with the given Drawable. This can be 19822 * used when selecting a new Drawable into a view, so that the previous 19823 * one is completely unscheduled. 19824 * 19825 * @param who The Drawable to unschedule. 19826 * 19827 * @see #drawableStateChanged 19828 */ 19829 public void unscheduleDrawable(Drawable who) { 19830 if (mAttachInfo != null && who != null) { 19831 mAttachInfo.mViewRootImpl.mChoreographer.removeCallbacks( 19832 Choreographer.CALLBACK_ANIMATION, null, who); 19833 } 19834 } 19835 19836 /** 19837 * Resolve the Drawables depending on the layout direction. This is implicitly supposing 19838 * that the View directionality can and will be resolved before its Drawables. 19839 * 19840 * Will call {@link View#onResolveDrawables} when resolution is done. 19841 * 19842 * @hide 19843 */ 19844 protected void resolveDrawables() { 19845 // Drawables resolution may need to happen before resolving the layout direction (which is 19846 // done only during the measure() call). 19847 // If the layout direction is not resolved yet, we cannot resolve the Drawables except in 19848 // one case: when the raw layout direction has not been defined as LAYOUT_DIRECTION_INHERIT. 19849 // So, if the raw layout direction is LAYOUT_DIRECTION_LTR or LAYOUT_DIRECTION_RTL or 19850 // LAYOUT_DIRECTION_LOCALE, we can "cheat" and we don't need to wait for the layout 19851 // direction to be resolved as its resolved value will be the same as its raw value. 19852 if (!isLayoutDirectionResolved() && 19853 getRawLayoutDirection() == View.LAYOUT_DIRECTION_INHERIT) { 19854 return; 19855 } 19856 19857 final int layoutDirection = isLayoutDirectionResolved() ? 19858 getLayoutDirection() : getRawLayoutDirection(); 19859 19860 if (mBackground != null) { 19861 mBackground.setLayoutDirection(layoutDirection); 19862 } 19863 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null) { 19864 mForegroundInfo.mDrawable.setLayoutDirection(layoutDirection); 19865 } 19866 if (mDefaultFocusHighlight != null) { 19867 mDefaultFocusHighlight.setLayoutDirection(layoutDirection); 19868 } 19869 mPrivateFlags2 |= PFLAG2_DRAWABLE_RESOLVED; 19870 onResolveDrawables(layoutDirection); 19871 } 19872 19873 boolean areDrawablesResolved() { 19874 return (mPrivateFlags2 & PFLAG2_DRAWABLE_RESOLVED) == PFLAG2_DRAWABLE_RESOLVED; 19875 } 19876 19877 /** 19878 * Called when layout direction has been resolved. 19879 * 19880 * The default implementation does nothing. 19881 * 19882 * @param layoutDirection The resolved layout direction. 19883 * 19884 * @see #LAYOUT_DIRECTION_LTR 19885 * @see #LAYOUT_DIRECTION_RTL 19886 * 19887 * @hide 19888 */ 19889 public void onResolveDrawables(@ResolvedLayoutDir int layoutDirection) { 19890 } 19891 19892 /** 19893 * @hide 19894 */ 19895 protected void resetResolvedDrawables() { 19896 resetResolvedDrawablesInternal(); 19897 } 19898 19899 void resetResolvedDrawablesInternal() { 19900 mPrivateFlags2 &= ~PFLAG2_DRAWABLE_RESOLVED; 19901 } 19902 19903 /** 19904 * If your view subclass is displaying its own Drawable objects, it should 19905 * override this function and return true for any Drawable it is 19906 * displaying. This allows animations for those drawables to be 19907 * scheduled. 19908 * 19909 * <p>Be sure to call through to the super class when overriding this 19910 * function. 19911 * 19912 * @param who The Drawable to verify. Return true if it is one you are 19913 * displaying, else return the result of calling through to the 19914 * super class. 19915 * 19916 * @return boolean If true than the Drawable is being displayed in the 19917 * view; else false and it is not allowed to animate. 19918 * 19919 * @see #unscheduleDrawable(android.graphics.drawable.Drawable) 19920 * @see #drawableStateChanged() 19921 */ 19922 @CallSuper 19923 protected boolean verifyDrawable(@NonNull Drawable who) { 19924 // Avoid verifying the scroll bar drawable so that we don't end up in 19925 // an invalidation loop. This effectively prevents the scroll bar 19926 // drawable from triggering invalidations and scheduling runnables. 19927 return who == mBackground || (mForegroundInfo != null && mForegroundInfo.mDrawable == who) 19928 || (mDefaultFocusHighlight == who); 19929 } 19930 19931 /** 19932 * This function is called whenever the state of the view changes in such 19933 * a way that it impacts the state of drawables being shown. 19934 * <p> 19935 * If the View has a StateListAnimator, it will also be called to run necessary state 19936 * change animations. 19937 * <p> 19938 * Be sure to call through to the superclass when overriding this function. 19939 * 19940 * @see Drawable#setState(int[]) 19941 */ 19942 @CallSuper 19943 protected void drawableStateChanged() { 19944 final int[] state = getDrawableState(); 19945 boolean changed = false; 19946 19947 final Drawable bg = mBackground; 19948 if (bg != null && bg.isStateful()) { 19949 changed |= bg.setState(state); 19950 } 19951 19952 final Drawable hl = mDefaultFocusHighlight; 19953 if (hl != null && hl.isStateful()) { 19954 changed |= hl.setState(state); 19955 } 19956 19957 final Drawable fg = mForegroundInfo != null ? mForegroundInfo.mDrawable : null; 19958 if (fg != null && fg.isStateful()) { 19959 changed |= fg.setState(state); 19960 } 19961 19962 if (mScrollCache != null) { 19963 final Drawable scrollBar = mScrollCache.scrollBar; 19964 if (scrollBar != null && scrollBar.isStateful()) { 19965 changed |= scrollBar.setState(state) 19966 && mScrollCache.state != ScrollabilityCache.OFF; 19967 } 19968 } 19969 19970 if (mStateListAnimator != null) { 19971 mStateListAnimator.setState(state); 19972 } 19973 19974 if (changed) { 19975 invalidate(); 19976 } 19977 } 19978 19979 /** 19980 * This function is called whenever the view hotspot changes and needs to 19981 * be propagated to drawables or child views managed by the view. 19982 * <p> 19983 * Dispatching to child views is handled by 19984 * {@link #dispatchDrawableHotspotChanged(float, float)}. 19985 * <p> 19986 * Be sure to call through to the superclass when overriding this function. 19987 * 19988 * @param x hotspot x coordinate 19989 * @param y hotspot y coordinate 19990 */ 19991 @CallSuper 19992 public void drawableHotspotChanged(float x, float y) { 19993 if (mBackground != null) { 19994 mBackground.setHotspot(x, y); 19995 } 19996 if (mDefaultFocusHighlight != null) { 19997 mDefaultFocusHighlight.setHotspot(x, y); 19998 } 19999 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null) { 20000 mForegroundInfo.mDrawable.setHotspot(x, y); 20001 } 20002 20003 dispatchDrawableHotspotChanged(x, y); 20004 } 20005 20006 /** 20007 * Dispatches drawableHotspotChanged to all of this View's children. 20008 * 20009 * @param x hotspot x coordinate 20010 * @param y hotspot y coordinate 20011 * @see #drawableHotspotChanged(float, float) 20012 */ 20013 public void dispatchDrawableHotspotChanged(float x, float y) { 20014 } 20015 20016 /** 20017 * Call this to force a view to update its drawable state. This will cause 20018 * drawableStateChanged to be called on this view. Views that are interested 20019 * in the new state should call getDrawableState. 20020 * 20021 * @see #drawableStateChanged 20022 * @see #getDrawableState 20023 */ 20024 public void refreshDrawableState() { 20025 mPrivateFlags |= PFLAG_DRAWABLE_STATE_DIRTY; 20026 drawableStateChanged(); 20027 20028 ViewParent parent = mParent; 20029 if (parent != null) { 20030 parent.childDrawableStateChanged(this); 20031 } 20032 } 20033 20034 /** 20035 * Create a default focus highlight if it doesn't exist. 20036 * @return a default focus highlight. 20037 */ 20038 private Drawable getDefaultFocusHighlightDrawable() { 20039 if (mDefaultFocusHighlightCache == null) { 20040 if (mContext != null) { 20041 final int[] attrs = new int[] { android.R.attr.selectableItemBackground }; 20042 final TypedArray ta = mContext.obtainStyledAttributes(attrs); 20043 mDefaultFocusHighlightCache = ta.getDrawable(0); 20044 ta.recycle(); 20045 } 20046 } 20047 return mDefaultFocusHighlightCache; 20048 } 20049 20050 /** 20051 * Set the current default focus highlight. 20052 * @param highlight the highlight drawable, or {@code null} if it's no longer needed. 20053 */ 20054 private void setDefaultFocusHighlight(Drawable highlight) { 20055 mDefaultFocusHighlight = highlight; 20056 mDefaultFocusHighlightSizeChanged = true; 20057 if (highlight != null) { 20058 if ((mPrivateFlags & PFLAG_SKIP_DRAW) != 0) { 20059 mPrivateFlags &= ~PFLAG_SKIP_DRAW; 20060 } 20061 highlight.setLayoutDirection(getLayoutDirection()); 20062 if (highlight.isStateful()) { 20063 highlight.setState(getDrawableState()); 20064 } 20065 if (isAttachedToWindow()) { 20066 highlight.setVisible(getWindowVisibility() == VISIBLE && isShown(), false); 20067 } 20068 // Set callback last, since the view may still be initializing. 20069 highlight.setCallback(this); 20070 } else if ((mViewFlags & WILL_NOT_DRAW) != 0 && mBackground == null 20071 && (mForegroundInfo == null || mForegroundInfo.mDrawable == null)) { 20072 mPrivateFlags |= PFLAG_SKIP_DRAW; 20073 } 20074 invalidate(); 20075 } 20076 20077 /** 20078 * Check whether we need to draw a default focus highlight when this view gets focused, 20079 * which requires: 20080 * <ul> 20081 * <li>In both background and foreground, {@link android.R.attr#state_focused} 20082 * is not defined.</li> 20083 * <li>This view is not in touch mode.</li> 20084 * <li>This view doesn't opt out for a default focus highlight, via 20085 * {@link #setDefaultFocusHighlightEnabled(boolean)}.</li> 20086 * <li>This view is attached to window.</li> 20087 * </ul> 20088 * @return {@code true} if a default focus highlight is needed. 20089 * @hide 20090 */ 20091 @TestApi 20092 public boolean isDefaultFocusHighlightNeeded(Drawable background, Drawable foreground) { 20093 final boolean lackFocusState = (background == null || !background.isStateful() 20094 || !background.hasFocusStateSpecified()) 20095 && (foreground == null || !foreground.isStateful() 20096 || !foreground.hasFocusStateSpecified()); 20097 return !isInTouchMode() && getDefaultFocusHighlightEnabled() && lackFocusState 20098 && isAttachedToWindow() && sUseDefaultFocusHighlight; 20099 } 20100 20101 /** 20102 * When this view is focused, switches on/off the default focused highlight. 20103 * <p> 20104 * This always happens when this view is focused, and only at this moment the default focus 20105 * highlight can be visible. 20106 */ 20107 private void switchDefaultFocusHighlight() { 20108 if (isFocused()) { 20109 final boolean needed = isDefaultFocusHighlightNeeded(mBackground, 20110 mForegroundInfo == null ? null : mForegroundInfo.mDrawable); 20111 final boolean active = mDefaultFocusHighlight != null; 20112 if (needed && !active) { 20113 setDefaultFocusHighlight(getDefaultFocusHighlightDrawable()); 20114 } else if (!needed && active) { 20115 // The highlight is no longer needed, so tear it down. 20116 setDefaultFocusHighlight(null); 20117 } 20118 } 20119 } 20120 20121 /** 20122 * Draw the default focus highlight onto the canvas. 20123 * @param canvas the canvas where we're drawing the highlight. 20124 */ 20125 private void drawDefaultFocusHighlight(Canvas canvas) { 20126 if (mDefaultFocusHighlight != null) { 20127 if (mDefaultFocusHighlightSizeChanged) { 20128 mDefaultFocusHighlightSizeChanged = false; 20129 final int l = mScrollX; 20130 final int r = l + mRight - mLeft; 20131 final int t = mScrollY; 20132 final int b = t + mBottom - mTop; 20133 mDefaultFocusHighlight.setBounds(l, t, r, b); 20134 } 20135 mDefaultFocusHighlight.draw(canvas); 20136 } 20137 } 20138 20139 /** 20140 * Return an array of resource IDs of the drawable states representing the 20141 * current state of the view. 20142 * 20143 * @return The current drawable state 20144 * 20145 * @see Drawable#setState(int[]) 20146 * @see #drawableStateChanged() 20147 * @see #onCreateDrawableState(int) 20148 */ 20149 public final int[] getDrawableState() { 20150 if ((mDrawableState != null) && ((mPrivateFlags & PFLAG_DRAWABLE_STATE_DIRTY) == 0)) { 20151 return mDrawableState; 20152 } else { 20153 mDrawableState = onCreateDrawableState(0); 20154 mPrivateFlags &= ~PFLAG_DRAWABLE_STATE_DIRTY; 20155 return mDrawableState; 20156 } 20157 } 20158 20159 /** 20160 * Generate the new {@link android.graphics.drawable.Drawable} state for 20161 * this view. This is called by the view 20162 * system when the cached Drawable state is determined to be invalid. To 20163 * retrieve the current state, you should use {@link #getDrawableState}. 20164 * 20165 * @param extraSpace if non-zero, this is the number of extra entries you 20166 * would like in the returned array in which you can place your own 20167 * states. 20168 * 20169 * @return Returns an array holding the current {@link Drawable} state of 20170 * the view. 20171 * 20172 * @see #mergeDrawableStates(int[], int[]) 20173 */ 20174 protected int[] onCreateDrawableState(int extraSpace) { 20175 if ((mViewFlags & DUPLICATE_PARENT_STATE) == DUPLICATE_PARENT_STATE && 20176 mParent instanceof View) { 20177 return ((View) mParent).onCreateDrawableState(extraSpace); 20178 } 20179 20180 int[] drawableState; 20181 20182 int privateFlags = mPrivateFlags; 20183 20184 int viewStateIndex = 0; 20185 if ((privateFlags & PFLAG_PRESSED) != 0) viewStateIndex |= StateSet.VIEW_STATE_PRESSED; 20186 if ((mViewFlags & ENABLED_MASK) == ENABLED) viewStateIndex |= StateSet.VIEW_STATE_ENABLED; 20187 if (isFocused()) viewStateIndex |= StateSet.VIEW_STATE_FOCUSED; 20188 if ((privateFlags & PFLAG_SELECTED) != 0) viewStateIndex |= StateSet.VIEW_STATE_SELECTED; 20189 if (hasWindowFocus()) viewStateIndex |= StateSet.VIEW_STATE_WINDOW_FOCUSED; 20190 if ((privateFlags & PFLAG_ACTIVATED) != 0) viewStateIndex |= StateSet.VIEW_STATE_ACTIVATED; 20191 if (mAttachInfo != null && mAttachInfo.mHardwareAccelerationRequested && 20192 ThreadedRenderer.isAvailable()) { 20193 // This is set if HW acceleration is requested, even if the current 20194 // process doesn't allow it. This is just to allow app preview 20195 // windows to better match their app. 20196 viewStateIndex |= StateSet.VIEW_STATE_ACCELERATED; 20197 } 20198 if ((privateFlags & PFLAG_HOVERED) != 0) viewStateIndex |= StateSet.VIEW_STATE_HOVERED; 20199 20200 final int privateFlags2 = mPrivateFlags2; 20201 if ((privateFlags2 & PFLAG2_DRAG_CAN_ACCEPT) != 0) { 20202 viewStateIndex |= StateSet.VIEW_STATE_DRAG_CAN_ACCEPT; 20203 } 20204 if ((privateFlags2 & PFLAG2_DRAG_HOVERED) != 0) { 20205 viewStateIndex |= StateSet.VIEW_STATE_DRAG_HOVERED; 20206 } 20207 20208 drawableState = StateSet.get(viewStateIndex); 20209 20210 //noinspection ConstantIfStatement 20211 if (false) { 20212 Log.i("View", "drawableStateIndex=" + viewStateIndex); 20213 Log.i("View", toString() 20214 + " pressed=" + ((privateFlags & PFLAG_PRESSED) != 0) 20215 + " en=" + ((mViewFlags & ENABLED_MASK) == ENABLED) 20216 + " fo=" + hasFocus() 20217 + " sl=" + ((privateFlags & PFLAG_SELECTED) != 0) 20218 + " wf=" + hasWindowFocus() 20219 + ": " + Arrays.toString(drawableState)); 20220 } 20221 20222 if (extraSpace == 0) { 20223 return drawableState; 20224 } 20225 20226 final int[] fullState; 20227 if (drawableState != null) { 20228 fullState = new int[drawableState.length + extraSpace]; 20229 System.arraycopy(drawableState, 0, fullState, 0, drawableState.length); 20230 } else { 20231 fullState = new int[extraSpace]; 20232 } 20233 20234 return fullState; 20235 } 20236 20237 /** 20238 * Merge your own state values in <var>additionalState</var> into the base 20239 * state values <var>baseState</var> that were returned by 20240 * {@link #onCreateDrawableState(int)}. 20241 * 20242 * @param baseState The base state values returned by 20243 * {@link #onCreateDrawableState(int)}, which will be modified to also hold your 20244 * own additional state values. 20245 * 20246 * @param additionalState The additional state values you would like 20247 * added to <var>baseState</var>; this array is not modified. 20248 * 20249 * @return As a convenience, the <var>baseState</var> array you originally 20250 * passed into the function is returned. 20251 * 20252 * @see #onCreateDrawableState(int) 20253 */ 20254 protected static int[] mergeDrawableStates(int[] baseState, int[] additionalState) { 20255 final int N = baseState.length; 20256 int i = N - 1; 20257 while (i >= 0 && baseState[i] == 0) { 20258 i--; 20259 } 20260 System.arraycopy(additionalState, 0, baseState, i + 1, additionalState.length); 20261 return baseState; 20262 } 20263 20264 /** 20265 * Call {@link Drawable#jumpToCurrentState() Drawable.jumpToCurrentState()} 20266 * on all Drawable objects associated with this view. 20267 * <p> 20268 * Also calls {@link StateListAnimator#jumpToCurrentState()} if there is a StateListAnimator 20269 * attached to this view. 20270 */ 20271 @CallSuper 20272 public void jumpDrawablesToCurrentState() { 20273 if (mBackground != null) { 20274 mBackground.jumpToCurrentState(); 20275 } 20276 if (mStateListAnimator != null) { 20277 mStateListAnimator.jumpToCurrentState(); 20278 } 20279 if (mDefaultFocusHighlight != null) { 20280 mDefaultFocusHighlight.jumpToCurrentState(); 20281 } 20282 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null) { 20283 mForegroundInfo.mDrawable.jumpToCurrentState(); 20284 } 20285 } 20286 20287 /** 20288 * Sets the background color for this view. 20289 * @param color the color of the background 20290 */ 20291 @RemotableViewMethod 20292 public void setBackgroundColor(@ColorInt int color) { 20293 if (mBackground instanceof ColorDrawable) { 20294 ((ColorDrawable) mBackground.mutate()).setColor(color); 20295 computeOpaqueFlags(); 20296 mBackgroundResource = 0; 20297 } else { 20298 setBackground(new ColorDrawable(color)); 20299 } 20300 } 20301 20302 /** 20303 * Set the background to a given resource. The resource should refer to 20304 * a Drawable object or 0 to remove the background. 20305 * @param resid The identifier of the resource. 20306 * 20307 * @attr ref android.R.styleable#View_background 20308 */ 20309 @RemotableViewMethod 20310 public void setBackgroundResource(@DrawableRes int resid) { 20311 if (resid != 0 && resid == mBackgroundResource) { 20312 return; 20313 } 20314 20315 Drawable d = null; 20316 if (resid != 0) { 20317 d = mContext.getDrawable(resid); 20318 } 20319 setBackground(d); 20320 20321 mBackgroundResource = resid; 20322 } 20323 20324 /** 20325 * Set the background to a given Drawable, or remove the background. If the 20326 * background has padding, this View's padding is set to the background's 20327 * padding. However, when a background is removed, this View's padding isn't 20328 * touched. If setting the padding is desired, please use 20329 * {@link #setPadding(int, int, int, int)}. 20330 * 20331 * @param background The Drawable to use as the background, or null to remove the 20332 * background 20333 */ 20334 public void setBackground(Drawable background) { 20335 //noinspection deprecation 20336 setBackgroundDrawable(background); 20337 } 20338 20339 /** 20340 * @deprecated use {@link #setBackground(Drawable)} instead 20341 */ 20342 @Deprecated 20343 public void setBackgroundDrawable(Drawable background) { 20344 computeOpaqueFlags(); 20345 20346 if (background == mBackground) { 20347 return; 20348 } 20349 20350 boolean requestLayout = false; 20351 20352 mBackgroundResource = 0; 20353 20354 /* 20355 * Regardless of whether we're setting a new background or not, we want 20356 * to clear the previous drawable. setVisible first while we still have the callback set. 20357 */ 20358 if (mBackground != null) { 20359 if (isAttachedToWindow()) { 20360 mBackground.setVisible(false, false); 20361 } 20362 mBackground.setCallback(null); 20363 unscheduleDrawable(mBackground); 20364 } 20365 20366 if (background != null) { 20367 Rect padding = sThreadLocal.get(); 20368 if (padding == null) { 20369 padding = new Rect(); 20370 sThreadLocal.set(padding); 20371 } 20372 resetResolvedDrawablesInternal(); 20373 background.setLayoutDirection(getLayoutDirection()); 20374 if (background.getPadding(padding)) { 20375 resetResolvedPaddingInternal(); 20376 switch (background.getLayoutDirection()) { 20377 case LAYOUT_DIRECTION_RTL: 20378 mUserPaddingLeftInitial = padding.right; 20379 mUserPaddingRightInitial = padding.left; 20380 internalSetPadding(padding.right, padding.top, padding.left, padding.bottom); 20381 break; 20382 case LAYOUT_DIRECTION_LTR: 20383 default: 20384 mUserPaddingLeftInitial = padding.left; 20385 mUserPaddingRightInitial = padding.right; 20386 internalSetPadding(padding.left, padding.top, padding.right, padding.bottom); 20387 } 20388 mLeftPaddingDefined = false; 20389 mRightPaddingDefined = false; 20390 } 20391 20392 // Compare the minimum sizes of the old Drawable and the new. If there isn't an old or 20393 // if it has a different minimum size, we should layout again 20394 if (mBackground == null 20395 || mBackground.getMinimumHeight() != background.getMinimumHeight() 20396 || mBackground.getMinimumWidth() != background.getMinimumWidth()) { 20397 requestLayout = true; 20398 } 20399 20400 // Set mBackground before we set this as the callback and start making other 20401 // background drawable state change calls. In particular, the setVisible call below 20402 // can result in drawables attempting to start animations or otherwise invalidate, 20403 // which requires the view set as the callback (us) to recognize the drawable as 20404 // belonging to it as per verifyDrawable. 20405 mBackground = background; 20406 if (background.isStateful()) { 20407 background.setState(getDrawableState()); 20408 } 20409 if (isAttachedToWindow()) { 20410 background.setVisible(getWindowVisibility() == VISIBLE && isShown(), false); 20411 } 20412 20413 applyBackgroundTint(); 20414 20415 // Set callback last, since the view may still be initializing. 20416 background.setCallback(this); 20417 20418 if ((mPrivateFlags & PFLAG_SKIP_DRAW) != 0) { 20419 mPrivateFlags &= ~PFLAG_SKIP_DRAW; 20420 requestLayout = true; 20421 } 20422 } else { 20423 /* Remove the background */ 20424 mBackground = null; 20425 if ((mViewFlags & WILL_NOT_DRAW) != 0 20426 && (mDefaultFocusHighlight == null) 20427 && (mForegroundInfo == null || mForegroundInfo.mDrawable == null)) { 20428 mPrivateFlags |= PFLAG_SKIP_DRAW; 20429 } 20430 20431 /* 20432 * When the background is set, we try to apply its padding to this 20433 * View. When the background is removed, we don't touch this View's 20434 * padding. This is noted in the Javadocs. Hence, we don't need to 20435 * requestLayout(), the invalidate() below is sufficient. 20436 */ 20437 20438 // The old background's minimum size could have affected this 20439 // View's layout, so let's requestLayout 20440 requestLayout = true; 20441 } 20442 20443 computeOpaqueFlags(); 20444 20445 if (requestLayout) { 20446 requestLayout(); 20447 } 20448 20449 mBackgroundSizeChanged = true; 20450 invalidate(true); 20451 invalidateOutline(); 20452 } 20453 20454 /** 20455 * Gets the background drawable 20456 * 20457 * @return The drawable used as the background for this view, if any. 20458 * 20459 * @see #setBackground(Drawable) 20460 * 20461 * @attr ref android.R.styleable#View_background 20462 */ 20463 public Drawable getBackground() { 20464 return mBackground; 20465 } 20466 20467 /** 20468 * Applies a tint to the background drawable. Does not modify the current tint 20469 * mode, which is {@link PorterDuff.Mode#SRC_IN} by default. 20470 * <p> 20471 * Subsequent calls to {@link #setBackground(Drawable)} will automatically 20472 * mutate the drawable and apply the specified tint and tint mode using 20473 * {@link Drawable#setTintList(ColorStateList)}. 20474 * 20475 * @param tint the tint to apply, may be {@code null} to clear tint 20476 * 20477 * @attr ref android.R.styleable#View_backgroundTint 20478 * @see #getBackgroundTintList() 20479 * @see Drawable#setTintList(ColorStateList) 20480 */ 20481 public void setBackgroundTintList(@Nullable ColorStateList tint) { 20482 if (mBackgroundTint == null) { 20483 mBackgroundTint = new TintInfo(); 20484 } 20485 mBackgroundTint.mTintList = tint; 20486 mBackgroundTint.mHasTintList = true; 20487 20488 applyBackgroundTint(); 20489 } 20490 20491 /** 20492 * Return the tint applied to the background drawable, if specified. 20493 * 20494 * @return the tint applied to the background drawable 20495 * @attr ref android.R.styleable#View_backgroundTint 20496 * @see #setBackgroundTintList(ColorStateList) 20497 */ 20498 @Nullable 20499 public ColorStateList getBackgroundTintList() { 20500 return mBackgroundTint != null ? mBackgroundTint.mTintList : null; 20501 } 20502 20503 /** 20504 * Specifies the blending mode used to apply the tint specified by 20505 * {@link #setBackgroundTintList(ColorStateList)}} to the background 20506 * drawable. The default mode is {@link PorterDuff.Mode#SRC_IN}. 20507 * 20508 * @param tintMode the blending mode used to apply the tint, may be 20509 * {@code null} to clear tint 20510 * @attr ref android.R.styleable#View_backgroundTintMode 20511 * @see #getBackgroundTintMode() 20512 * @see Drawable#setTintMode(PorterDuff.Mode) 20513 */ 20514 public void setBackgroundTintMode(@Nullable PorterDuff.Mode tintMode) { 20515 if (mBackgroundTint == null) { 20516 mBackgroundTint = new TintInfo(); 20517 } 20518 mBackgroundTint.mTintMode = tintMode; 20519 mBackgroundTint.mHasTintMode = true; 20520 20521 applyBackgroundTint(); 20522 } 20523 20524 /** 20525 * Return the blending mode used to apply the tint to the background 20526 * drawable, if specified. 20527 * 20528 * @return the blending mode used to apply the tint to the background 20529 * drawable 20530 * @attr ref android.R.styleable#View_backgroundTintMode 20531 * @see #setBackgroundTintMode(PorterDuff.Mode) 20532 */ 20533 @Nullable 20534 public PorterDuff.Mode getBackgroundTintMode() { 20535 return mBackgroundTint != null ? mBackgroundTint.mTintMode : null; 20536 } 20537 20538 private void applyBackgroundTint() { 20539 if (mBackground != null && mBackgroundTint != null) { 20540 final TintInfo tintInfo = mBackgroundTint; 20541 if (tintInfo.mHasTintList || tintInfo.mHasTintMode) { 20542 mBackground = mBackground.mutate(); 20543 20544 if (tintInfo.mHasTintList) { 20545 mBackground.setTintList(tintInfo.mTintList); 20546 } 20547 20548 if (tintInfo.mHasTintMode) { 20549 mBackground.setTintMode(tintInfo.mTintMode); 20550 } 20551 20552 // The drawable (or one of its children) may not have been 20553 // stateful before applying the tint, so let's try again. 20554 if (mBackground.isStateful()) { 20555 mBackground.setState(getDrawableState()); 20556 } 20557 } 20558 } 20559 } 20560 20561 /** 20562 * Returns the drawable used as the foreground of this View. The 20563 * foreground drawable, if non-null, is always drawn on top of the view's content. 20564 * 20565 * @return a Drawable or null if no foreground was set 20566 * 20567 * @see #onDrawForeground(Canvas) 20568 */ 20569 public Drawable getForeground() { 20570 return mForegroundInfo != null ? mForegroundInfo.mDrawable : null; 20571 } 20572 20573 /** 20574 * Supply a Drawable that is to be rendered on top of all of the content in the view. 20575 * 20576 * @param foreground the Drawable to be drawn on top of the children 20577 * 20578 * @attr ref android.R.styleable#View_foreground 20579 */ 20580 public void setForeground(Drawable foreground) { 20581 if (mForegroundInfo == null) { 20582 if (foreground == null) { 20583 // Nothing to do. 20584 return; 20585 } 20586 mForegroundInfo = new ForegroundInfo(); 20587 } 20588 20589 if (foreground == mForegroundInfo.mDrawable) { 20590 // Nothing to do 20591 return; 20592 } 20593 20594 if (mForegroundInfo.mDrawable != null) { 20595 if (isAttachedToWindow()) { 20596 mForegroundInfo.mDrawable.setVisible(false, false); 20597 } 20598 mForegroundInfo.mDrawable.setCallback(null); 20599 unscheduleDrawable(mForegroundInfo.mDrawable); 20600 } 20601 20602 mForegroundInfo.mDrawable = foreground; 20603 mForegroundInfo.mBoundsChanged = true; 20604 if (foreground != null) { 20605 if ((mPrivateFlags & PFLAG_SKIP_DRAW) != 0) { 20606 mPrivateFlags &= ~PFLAG_SKIP_DRAW; 20607 } 20608 foreground.setLayoutDirection(getLayoutDirection()); 20609 if (foreground.isStateful()) { 20610 foreground.setState(getDrawableState()); 20611 } 20612 applyForegroundTint(); 20613 if (isAttachedToWindow()) { 20614 foreground.setVisible(getWindowVisibility() == VISIBLE && isShown(), false); 20615 } 20616 // Set callback last, since the view may still be initializing. 20617 foreground.setCallback(this); 20618 } else if ((mViewFlags & WILL_NOT_DRAW) != 0 && mBackground == null 20619 && (mDefaultFocusHighlight == null)) { 20620 mPrivateFlags |= PFLAG_SKIP_DRAW; 20621 } 20622 requestLayout(); 20623 invalidate(); 20624 } 20625 20626 /** 20627 * Magic bit used to support features of framework-internal window decor implementation details. 20628 * This used to live exclusively in FrameLayout. 20629 * 20630 * @return true if the foreground should draw inside the padding region or false 20631 * if it should draw inset by the view's padding 20632 * @hide internal use only; only used by FrameLayout and internal screen layouts. 20633 */ 20634 public boolean isForegroundInsidePadding() { 20635 return mForegroundInfo != null ? mForegroundInfo.mInsidePadding : true; 20636 } 20637 20638 /** 20639 * Describes how the foreground is positioned. 20640 * 20641 * @return foreground gravity. 20642 * 20643 * @see #setForegroundGravity(int) 20644 * 20645 * @attr ref android.R.styleable#View_foregroundGravity 20646 */ 20647 public int getForegroundGravity() { 20648 return mForegroundInfo != null ? mForegroundInfo.mGravity 20649 : Gravity.START | Gravity.TOP; 20650 } 20651 20652 /** 20653 * Describes how the foreground is positioned. Defaults to START and TOP. 20654 * 20655 * @param gravity see {@link android.view.Gravity} 20656 * 20657 * @see #getForegroundGravity() 20658 * 20659 * @attr ref android.R.styleable#View_foregroundGravity 20660 */ 20661 public void setForegroundGravity(int gravity) { 20662 if (mForegroundInfo == null) { 20663 mForegroundInfo = new ForegroundInfo(); 20664 } 20665 20666 if (mForegroundInfo.mGravity != gravity) { 20667 if ((gravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK) == 0) { 20668 gravity |= Gravity.START; 20669 } 20670 20671 if ((gravity & Gravity.VERTICAL_GRAVITY_MASK) == 0) { 20672 gravity |= Gravity.TOP; 20673 } 20674 20675 mForegroundInfo.mGravity = gravity; 20676 requestLayout(); 20677 } 20678 } 20679 20680 /** 20681 * Applies a tint to the foreground drawable. Does not modify the current tint 20682 * mode, which is {@link PorterDuff.Mode#SRC_IN} by default. 20683 * <p> 20684 * Subsequent calls to {@link #setForeground(Drawable)} will automatically 20685 * mutate the drawable and apply the specified tint and tint mode using 20686 * {@link Drawable#setTintList(ColorStateList)}. 20687 * 20688 * @param tint the tint to apply, may be {@code null} to clear tint 20689 * 20690 * @attr ref android.R.styleable#View_foregroundTint 20691 * @see #getForegroundTintList() 20692 * @see Drawable#setTintList(ColorStateList) 20693 */ 20694 public void setForegroundTintList(@Nullable ColorStateList tint) { 20695 if (mForegroundInfo == null) { 20696 mForegroundInfo = new ForegroundInfo(); 20697 } 20698 if (mForegroundInfo.mTintInfo == null) { 20699 mForegroundInfo.mTintInfo = new TintInfo(); 20700 } 20701 mForegroundInfo.mTintInfo.mTintList = tint; 20702 mForegroundInfo.mTintInfo.mHasTintList = true; 20703 20704 applyForegroundTint(); 20705 } 20706 20707 /** 20708 * Return the tint applied to the foreground drawable, if specified. 20709 * 20710 * @return the tint applied to the foreground drawable 20711 * @attr ref android.R.styleable#View_foregroundTint 20712 * @see #setForegroundTintList(ColorStateList) 20713 */ 20714 @Nullable 20715 public ColorStateList getForegroundTintList() { 20716 return mForegroundInfo != null && mForegroundInfo.mTintInfo != null 20717 ? mForegroundInfo.mTintInfo.mTintList : null; 20718 } 20719 20720 /** 20721 * Specifies the blending mode used to apply the tint specified by 20722 * {@link #setForegroundTintList(ColorStateList)}} to the background 20723 * drawable. The default mode is {@link PorterDuff.Mode#SRC_IN}. 20724 * 20725 * @param tintMode the blending mode used to apply the tint, may be 20726 * {@code null} to clear tint 20727 * @attr ref android.R.styleable#View_foregroundTintMode 20728 * @see #getForegroundTintMode() 20729 * @see Drawable#setTintMode(PorterDuff.Mode) 20730 */ 20731 public void setForegroundTintMode(@Nullable PorterDuff.Mode tintMode) { 20732 if (mForegroundInfo == null) { 20733 mForegroundInfo = new ForegroundInfo(); 20734 } 20735 if (mForegroundInfo.mTintInfo == null) { 20736 mForegroundInfo.mTintInfo = new TintInfo(); 20737 } 20738 mForegroundInfo.mTintInfo.mTintMode = tintMode; 20739 mForegroundInfo.mTintInfo.mHasTintMode = true; 20740 20741 applyForegroundTint(); 20742 } 20743 20744 /** 20745 * Return the blending mode used to apply the tint to the foreground 20746 * drawable, if specified. 20747 * 20748 * @return the blending mode used to apply the tint to the foreground 20749 * drawable 20750 * @attr ref android.R.styleable#View_foregroundTintMode 20751 * @see #setForegroundTintMode(PorterDuff.Mode) 20752 */ 20753 @Nullable 20754 public PorterDuff.Mode getForegroundTintMode() { 20755 return mForegroundInfo != null && mForegroundInfo.mTintInfo != null 20756 ? mForegroundInfo.mTintInfo.mTintMode : null; 20757 } 20758 20759 private void applyForegroundTint() { 20760 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null 20761 && mForegroundInfo.mTintInfo != null) { 20762 final TintInfo tintInfo = mForegroundInfo.mTintInfo; 20763 if (tintInfo.mHasTintList || tintInfo.mHasTintMode) { 20764 mForegroundInfo.mDrawable = mForegroundInfo.mDrawable.mutate(); 20765 20766 if (tintInfo.mHasTintList) { 20767 mForegroundInfo.mDrawable.setTintList(tintInfo.mTintList); 20768 } 20769 20770 if (tintInfo.mHasTintMode) { 20771 mForegroundInfo.mDrawable.setTintMode(tintInfo.mTintMode); 20772 } 20773 20774 // The drawable (or one of its children) may not have been 20775 // stateful before applying the tint, so let's try again. 20776 if (mForegroundInfo.mDrawable.isStateful()) { 20777 mForegroundInfo.mDrawable.setState(getDrawableState()); 20778 } 20779 } 20780 } 20781 } 20782 20783 /** 20784 * Get the drawable to be overlayed when a view is autofilled 20785 * 20786 * @return The drawable 20787 * 20788 * @throws IllegalStateException if the drawable could not be found. 20789 */ 20790 @Nullable private Drawable getAutofilledDrawable() { 20791 if (mAttachInfo == null) { 20792 return null; 20793 } 20794 // Lazily load the isAutofilled drawable. 20795 if (mAttachInfo.mAutofilledDrawable == null) { 20796 Context rootContext = getRootView().getContext(); 20797 TypedArray a = rootContext.getTheme().obtainStyledAttributes(AUTOFILL_HIGHLIGHT_ATTR); 20798 int attributeResourceId = a.getResourceId(0, 0); 20799 mAttachInfo.mAutofilledDrawable = rootContext.getDrawable(attributeResourceId); 20800 a.recycle(); 20801 } 20802 20803 return mAttachInfo.mAutofilledDrawable; 20804 } 20805 20806 /** 20807 * Draw {@link View#isAutofilled()} highlight over view if the view is autofilled. 20808 * 20809 * @param canvas The canvas to draw on 20810 */ 20811 private void drawAutofilledHighlight(@NonNull Canvas canvas) { 20812 if (isAutofilled()) { 20813 Drawable autofilledHighlight = getAutofilledDrawable(); 20814 20815 if (autofilledHighlight != null) { 20816 autofilledHighlight.setBounds(0, 0, getWidth(), getHeight()); 20817 autofilledHighlight.draw(canvas); 20818 } 20819 } 20820 } 20821 20822 /** 20823 * Draw any foreground content for this view. 20824 * 20825 * <p>Foreground content may consist of scroll bars, a {@link #setForeground foreground} 20826 * drawable or other view-specific decorations. The foreground is drawn on top of the 20827 * primary view content.</p> 20828 * 20829 * @param canvas canvas to draw into 20830 */ 20831 public void onDrawForeground(Canvas canvas) { 20832 onDrawScrollIndicators(canvas); 20833 onDrawScrollBars(canvas); 20834 20835 final Drawable foreground = mForegroundInfo != null ? mForegroundInfo.mDrawable : null; 20836 if (foreground != null) { 20837 if (mForegroundInfo.mBoundsChanged) { 20838 mForegroundInfo.mBoundsChanged = false; 20839 final Rect selfBounds = mForegroundInfo.mSelfBounds; 20840 final Rect overlayBounds = mForegroundInfo.mOverlayBounds; 20841 20842 if (mForegroundInfo.mInsidePadding) { 20843 selfBounds.set(0, 0, getWidth(), getHeight()); 20844 } else { 20845 selfBounds.set(getPaddingLeft(), getPaddingTop(), 20846 getWidth() - getPaddingRight(), getHeight() - getPaddingBottom()); 20847 } 20848 20849 final int ld = getLayoutDirection(); 20850 Gravity.apply(mForegroundInfo.mGravity, foreground.getIntrinsicWidth(), 20851 foreground.getIntrinsicHeight(), selfBounds, overlayBounds, ld); 20852 foreground.setBounds(overlayBounds); 20853 } 20854 20855 foreground.draw(canvas); 20856 } 20857 } 20858 20859 /** 20860 * Sets the padding. The view may add on the space required to display 20861 * the scrollbars, depending on the style and visibility of the scrollbars. 20862 * So the values returned from {@link #getPaddingLeft}, {@link #getPaddingTop}, 20863 * {@link #getPaddingRight} and {@link #getPaddingBottom} may be different 20864 * from the values set in this call. 20865 * 20866 * @attr ref android.R.styleable#View_padding 20867 * @attr ref android.R.styleable#View_paddingBottom 20868 * @attr ref android.R.styleable#View_paddingLeft 20869 * @attr ref android.R.styleable#View_paddingRight 20870 * @attr ref android.R.styleable#View_paddingTop 20871 * @param left the left padding in pixels 20872 * @param top the top padding in pixels 20873 * @param right the right padding in pixels 20874 * @param bottom the bottom padding in pixels 20875 */ 20876 public void setPadding(int left, int top, int right, int bottom) { 20877 resetResolvedPaddingInternal(); 20878 20879 mUserPaddingStart = UNDEFINED_PADDING; 20880 mUserPaddingEnd = UNDEFINED_PADDING; 20881 20882 mUserPaddingLeftInitial = left; 20883 mUserPaddingRightInitial = right; 20884 20885 mLeftPaddingDefined = true; 20886 mRightPaddingDefined = true; 20887 20888 internalSetPadding(left, top, right, bottom); 20889 } 20890 20891 /** 20892 * @hide 20893 */ 20894 protected void internalSetPadding(int left, int top, int right, int bottom) { 20895 mUserPaddingLeft = left; 20896 mUserPaddingRight = right; 20897 mUserPaddingBottom = bottom; 20898 20899 final int viewFlags = mViewFlags; 20900 boolean changed = false; 20901 20902 // Common case is there are no scroll bars. 20903 if ((viewFlags & (SCROLLBARS_VERTICAL|SCROLLBARS_HORIZONTAL)) != 0) { 20904 if ((viewFlags & SCROLLBARS_VERTICAL) != 0) { 20905 final int offset = (viewFlags & SCROLLBARS_INSET_MASK) == 0 20906 ? 0 : getVerticalScrollbarWidth(); 20907 switch (mVerticalScrollbarPosition) { 20908 case SCROLLBAR_POSITION_DEFAULT: 20909 if (isLayoutRtl()) { 20910 left += offset; 20911 } else { 20912 right += offset; 20913 } 20914 break; 20915 case SCROLLBAR_POSITION_RIGHT: 20916 right += offset; 20917 break; 20918 case SCROLLBAR_POSITION_LEFT: 20919 left += offset; 20920 break; 20921 } 20922 } 20923 if ((viewFlags & SCROLLBARS_HORIZONTAL) != 0) { 20924 bottom += (viewFlags & SCROLLBARS_INSET_MASK) == 0 20925 ? 0 : getHorizontalScrollbarHeight(); 20926 } 20927 } 20928 20929 if (mPaddingLeft != left) { 20930 changed = true; 20931 mPaddingLeft = left; 20932 } 20933 if (mPaddingTop != top) { 20934 changed = true; 20935 mPaddingTop = top; 20936 } 20937 if (mPaddingRight != right) { 20938 changed = true; 20939 mPaddingRight = right; 20940 } 20941 if (mPaddingBottom != bottom) { 20942 changed = true; 20943 mPaddingBottom = bottom; 20944 } 20945 20946 if (changed) { 20947 requestLayout(); 20948 invalidateOutline(); 20949 } 20950 } 20951 20952 /** 20953 * Sets the relative padding. The view may add on the space required to display 20954 * the scrollbars, depending on the style and visibility of the scrollbars. 20955 * So the values returned from {@link #getPaddingStart}, {@link #getPaddingTop}, 20956 * {@link #getPaddingEnd} and {@link #getPaddingBottom} may be different 20957 * from the values set in this call. 20958 * 20959 * @attr ref android.R.styleable#View_padding 20960 * @attr ref android.R.styleable#View_paddingBottom 20961 * @attr ref android.R.styleable#View_paddingStart 20962 * @attr ref android.R.styleable#View_paddingEnd 20963 * @attr ref android.R.styleable#View_paddingTop 20964 * @param start the start padding in pixels 20965 * @param top the top padding in pixels 20966 * @param end the end padding in pixels 20967 * @param bottom the bottom padding in pixels 20968 */ 20969 public void setPaddingRelative(int start, int top, int end, int bottom) { 20970 resetResolvedPaddingInternal(); 20971 20972 mUserPaddingStart = start; 20973 mUserPaddingEnd = end; 20974 mLeftPaddingDefined = true; 20975 mRightPaddingDefined = true; 20976 20977 switch(getLayoutDirection()) { 20978 case LAYOUT_DIRECTION_RTL: 20979 mUserPaddingLeftInitial = end; 20980 mUserPaddingRightInitial = start; 20981 internalSetPadding(end, top, start, bottom); 20982 break; 20983 case LAYOUT_DIRECTION_LTR: 20984 default: 20985 mUserPaddingLeftInitial = start; 20986 mUserPaddingRightInitial = end; 20987 internalSetPadding(start, top, end, bottom); 20988 } 20989 } 20990 20991 /** 20992 * Returns the top padding of this view. 20993 * 20994 * @return the top padding in pixels 20995 */ 20996 public int getPaddingTop() { 20997 return mPaddingTop; 20998 } 20999 21000 /** 21001 * Returns the bottom padding of this view. If there are inset and enabled 21002 * scrollbars, this value may include the space required to display the 21003 * scrollbars as well. 21004 * 21005 * @return the bottom padding in pixels 21006 */ 21007 public int getPaddingBottom() { 21008 return mPaddingBottom; 21009 } 21010 21011 /** 21012 * Returns the left padding of this view. If there are inset and enabled 21013 * scrollbars, this value may include the space required to display the 21014 * scrollbars as well. 21015 * 21016 * @return the left padding in pixels 21017 */ 21018 public int getPaddingLeft() { 21019 if (!isPaddingResolved()) { 21020 resolvePadding(); 21021 } 21022 return mPaddingLeft; 21023 } 21024 21025 /** 21026 * Returns the start padding of this view depending on its resolved layout direction. 21027 * If there are inset and enabled scrollbars, this value may include the space 21028 * required to display the scrollbars as well. 21029 * 21030 * @return the start padding in pixels 21031 */ 21032 public int getPaddingStart() { 21033 if (!isPaddingResolved()) { 21034 resolvePadding(); 21035 } 21036 return (getLayoutDirection() == LAYOUT_DIRECTION_RTL) ? 21037 mPaddingRight : mPaddingLeft; 21038 } 21039 21040 /** 21041 * Returns the right padding of this view. If there are inset and enabled 21042 * scrollbars, this value may include the space required to display the 21043 * scrollbars as well. 21044 * 21045 * @return the right padding in pixels 21046 */ 21047 public int getPaddingRight() { 21048 if (!isPaddingResolved()) { 21049 resolvePadding(); 21050 } 21051 return mPaddingRight; 21052 } 21053 21054 /** 21055 * Returns the end padding of this view depending on its resolved layout direction. 21056 * If there are inset and enabled scrollbars, this value may include the space 21057 * required to display the scrollbars as well. 21058 * 21059 * @return the end padding in pixels 21060 */ 21061 public int getPaddingEnd() { 21062 if (!isPaddingResolved()) { 21063 resolvePadding(); 21064 } 21065 return (getLayoutDirection() == LAYOUT_DIRECTION_RTL) ? 21066 mPaddingLeft : mPaddingRight; 21067 } 21068 21069 /** 21070 * Return if the padding has been set through relative values 21071 * {@link #setPaddingRelative(int, int, int, int)} or through 21072 * @attr ref android.R.styleable#View_paddingStart or 21073 * @attr ref android.R.styleable#View_paddingEnd 21074 * 21075 * @return true if the padding is relative or false if it is not. 21076 */ 21077 public boolean isPaddingRelative() { 21078 return (mUserPaddingStart != UNDEFINED_PADDING || mUserPaddingEnd != UNDEFINED_PADDING); 21079 } 21080 21081 Insets computeOpticalInsets() { 21082 return (mBackground == null) ? Insets.NONE : mBackground.getOpticalInsets(); 21083 } 21084 21085 /** 21086 * @hide 21087 */ 21088 public void resetPaddingToInitialValues() { 21089 if (isRtlCompatibilityMode()) { 21090 mPaddingLeft = mUserPaddingLeftInitial; 21091 mPaddingRight = mUserPaddingRightInitial; 21092 return; 21093 } 21094 if (isLayoutRtl()) { 21095 mPaddingLeft = (mUserPaddingEnd >= 0) ? mUserPaddingEnd : mUserPaddingLeftInitial; 21096 mPaddingRight = (mUserPaddingStart >= 0) ? mUserPaddingStart : mUserPaddingRightInitial; 21097 } else { 21098 mPaddingLeft = (mUserPaddingStart >= 0) ? mUserPaddingStart : mUserPaddingLeftInitial; 21099 mPaddingRight = (mUserPaddingEnd >= 0) ? mUserPaddingEnd : mUserPaddingRightInitial; 21100 } 21101 } 21102 21103 /** 21104 * @hide 21105 */ 21106 public Insets getOpticalInsets() { 21107 if (mLayoutInsets == null) { 21108 mLayoutInsets = computeOpticalInsets(); 21109 } 21110 return mLayoutInsets; 21111 } 21112 21113 /** 21114 * Set this view's optical insets. 21115 * 21116 * <p>This method should be treated similarly to setMeasuredDimension and not as a general 21117 * property. Views that compute their own optical insets should call it as part of measurement. 21118 * This method does not request layout. If you are setting optical insets outside of 21119 * measure/layout itself you will want to call requestLayout() yourself. 21120 * </p> 21121 * @hide 21122 */ 21123 public void setOpticalInsets(Insets insets) { 21124 mLayoutInsets = insets; 21125 } 21126 21127 /** 21128 * Changes the selection state of this view. A view can be selected or not. 21129 * Note that selection is not the same as focus. Views are typically 21130 * selected in the context of an AdapterView like ListView or GridView; 21131 * the selected view is the view that is highlighted. 21132 * 21133 * @param selected true if the view must be selected, false otherwise 21134 */ 21135 public void setSelected(boolean selected) { 21136 //noinspection DoubleNegation 21137 if (((mPrivateFlags & PFLAG_SELECTED) != 0) != selected) { 21138 mPrivateFlags = (mPrivateFlags & ~PFLAG_SELECTED) | (selected ? PFLAG_SELECTED : 0); 21139 if (!selected) resetPressedState(); 21140 invalidate(true); 21141 refreshDrawableState(); 21142 dispatchSetSelected(selected); 21143 if (selected) { 21144 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED); 21145 } else { 21146 notifyViewAccessibilityStateChangedIfNeeded( 21147 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 21148 } 21149 } 21150 } 21151 21152 /** 21153 * Dispatch setSelected to all of this View's children. 21154 * 21155 * @see #setSelected(boolean) 21156 * 21157 * @param selected The new selected state 21158 */ 21159 protected void dispatchSetSelected(boolean selected) { 21160 } 21161 21162 /** 21163 * Indicates the selection state of this view. 21164 * 21165 * @return true if the view is selected, false otherwise 21166 */ 21167 @ViewDebug.ExportedProperty 21168 public boolean isSelected() { 21169 return (mPrivateFlags & PFLAG_SELECTED) != 0; 21170 } 21171 21172 /** 21173 * Changes the activated state of this view. A view can be activated or not. 21174 * Note that activation is not the same as selection. Selection is 21175 * a transient property, representing the view (hierarchy) the user is 21176 * currently interacting with. Activation is a longer-term state that the 21177 * user can move views in and out of. For example, in a list view with 21178 * single or multiple selection enabled, the views in the current selection 21179 * set are activated. (Um, yeah, we are deeply sorry about the terminology 21180 * here.) The activated state is propagated down to children of the view it 21181 * is set on. 21182 * 21183 * @param activated true if the view must be activated, false otherwise 21184 */ 21185 public void setActivated(boolean activated) { 21186 //noinspection DoubleNegation 21187 if (((mPrivateFlags & PFLAG_ACTIVATED) != 0) != activated) { 21188 mPrivateFlags = (mPrivateFlags & ~PFLAG_ACTIVATED) | (activated ? PFLAG_ACTIVATED : 0); 21189 invalidate(true); 21190 refreshDrawableState(); 21191 dispatchSetActivated(activated); 21192 } 21193 } 21194 21195 /** 21196 * Dispatch setActivated to all of this View's children. 21197 * 21198 * @see #setActivated(boolean) 21199 * 21200 * @param activated The new activated state 21201 */ 21202 protected void dispatchSetActivated(boolean activated) { 21203 } 21204 21205 /** 21206 * Indicates the activation state of this view. 21207 * 21208 * @return true if the view is activated, false otherwise 21209 */ 21210 @ViewDebug.ExportedProperty 21211 public boolean isActivated() { 21212 return (mPrivateFlags & PFLAG_ACTIVATED) != 0; 21213 } 21214 21215 /** 21216 * Returns the ViewTreeObserver for this view's hierarchy. The view tree 21217 * observer can be used to get notifications when global events, like 21218 * layout, happen. 21219 * 21220 * The returned ViewTreeObserver observer is not guaranteed to remain 21221 * valid for the lifetime of this View. If the caller of this method keeps 21222 * a long-lived reference to ViewTreeObserver, it should always check for 21223 * the return value of {@link ViewTreeObserver#isAlive()}. 21224 * 21225 * @return The ViewTreeObserver for this view's hierarchy. 21226 */ 21227 public ViewTreeObserver getViewTreeObserver() { 21228 if (mAttachInfo != null) { 21229 return mAttachInfo.mTreeObserver; 21230 } 21231 if (mFloatingTreeObserver == null) { 21232 mFloatingTreeObserver = new ViewTreeObserver(mContext); 21233 } 21234 return mFloatingTreeObserver; 21235 } 21236 21237 /** 21238 * <p>Finds the topmost view in the current view hierarchy.</p> 21239 * 21240 * @return the topmost view containing this view 21241 */ 21242 public View getRootView() { 21243 if (mAttachInfo != null) { 21244 final View v = mAttachInfo.mRootView; 21245 if (v != null) { 21246 return v; 21247 } 21248 } 21249 21250 View parent = this; 21251 21252 while (parent.mParent != null && parent.mParent instanceof View) { 21253 parent = (View) parent.mParent; 21254 } 21255 21256 return parent; 21257 } 21258 21259 /** 21260 * Transforms a motion event from view-local coordinates to on-screen 21261 * coordinates. 21262 * 21263 * @param ev the view-local motion event 21264 * @return false if the transformation could not be applied 21265 * @hide 21266 */ 21267 public boolean toGlobalMotionEvent(MotionEvent ev) { 21268 final AttachInfo info = mAttachInfo; 21269 if (info == null) { 21270 return false; 21271 } 21272 21273 final Matrix m = info.mTmpMatrix; 21274 m.set(Matrix.IDENTITY_MATRIX); 21275 transformMatrixToGlobal(m); 21276 ev.transform(m); 21277 return true; 21278 } 21279 21280 /** 21281 * Transforms a motion event from on-screen coordinates to view-local 21282 * coordinates. 21283 * 21284 * @param ev the on-screen motion event 21285 * @return false if the transformation could not be applied 21286 * @hide 21287 */ 21288 public boolean toLocalMotionEvent(MotionEvent ev) { 21289 final AttachInfo info = mAttachInfo; 21290 if (info == null) { 21291 return false; 21292 } 21293 21294 final Matrix m = info.mTmpMatrix; 21295 m.set(Matrix.IDENTITY_MATRIX); 21296 transformMatrixToLocal(m); 21297 ev.transform(m); 21298 return true; 21299 } 21300 21301 /** 21302 * Modifies the input matrix such that it maps view-local coordinates to 21303 * on-screen coordinates. 21304 * 21305 * @param m input matrix to modify 21306 * @hide 21307 */ 21308 public void transformMatrixToGlobal(Matrix m) { 21309 final ViewParent parent = mParent; 21310 if (parent instanceof View) { 21311 final View vp = (View) parent; 21312 vp.transformMatrixToGlobal(m); 21313 m.preTranslate(-vp.mScrollX, -vp.mScrollY); 21314 } else if (parent instanceof ViewRootImpl) { 21315 final ViewRootImpl vr = (ViewRootImpl) parent; 21316 vr.transformMatrixToGlobal(m); 21317 m.preTranslate(0, -vr.mCurScrollY); 21318 } 21319 21320 m.preTranslate(mLeft, mTop); 21321 21322 if (!hasIdentityMatrix()) { 21323 m.preConcat(getMatrix()); 21324 } 21325 } 21326 21327 /** 21328 * Modifies the input matrix such that it maps on-screen coordinates to 21329 * view-local coordinates. 21330 * 21331 * @param m input matrix to modify 21332 * @hide 21333 */ 21334 public void transformMatrixToLocal(Matrix m) { 21335 final ViewParent parent = mParent; 21336 if (parent instanceof View) { 21337 final View vp = (View) parent; 21338 vp.transformMatrixToLocal(m); 21339 m.postTranslate(vp.mScrollX, vp.mScrollY); 21340 } else if (parent instanceof ViewRootImpl) { 21341 final ViewRootImpl vr = (ViewRootImpl) parent; 21342 vr.transformMatrixToLocal(m); 21343 m.postTranslate(0, vr.mCurScrollY); 21344 } 21345 21346 m.postTranslate(-mLeft, -mTop); 21347 21348 if (!hasIdentityMatrix()) { 21349 m.postConcat(getInverseMatrix()); 21350 } 21351 } 21352 21353 /** 21354 * @hide 21355 */ 21356 @ViewDebug.ExportedProperty(category = "layout", indexMapping = { 21357 @ViewDebug.IntToString(from = 0, to = "x"), 21358 @ViewDebug.IntToString(from = 1, to = "y") 21359 }) 21360 public int[] getLocationOnScreen() { 21361 int[] location = new int[2]; 21362 getLocationOnScreen(location); 21363 return location; 21364 } 21365 21366 /** 21367 * <p>Computes the coordinates of this view on the screen. The argument 21368 * must be an array of two integers. After the method returns, the array 21369 * contains the x and y location in that order.</p> 21370 * 21371 * @param outLocation an array of two integers in which to hold the coordinates 21372 */ 21373 public void getLocationOnScreen(@Size(2) int[] outLocation) { 21374 getLocationInWindow(outLocation); 21375 21376 final AttachInfo info = mAttachInfo; 21377 if (info != null) { 21378 outLocation[0] += info.mWindowLeft; 21379 outLocation[1] += info.mWindowTop; 21380 } 21381 } 21382 21383 /** 21384 * <p>Computes the coordinates of this view in its window. The argument 21385 * must be an array of two integers. After the method returns, the array 21386 * contains the x and y location in that order.</p> 21387 * 21388 * @param outLocation an array of two integers in which to hold the coordinates 21389 */ 21390 public void getLocationInWindow(@Size(2) int[] outLocation) { 21391 if (outLocation == null || outLocation.length < 2) { 21392 throw new IllegalArgumentException("outLocation must be an array of two integers"); 21393 } 21394 21395 outLocation[0] = 0; 21396 outLocation[1] = 0; 21397 21398 transformFromViewToWindowSpace(outLocation); 21399 } 21400 21401 /** @hide */ 21402 public void transformFromViewToWindowSpace(@Size(2) int[] inOutLocation) { 21403 if (inOutLocation == null || inOutLocation.length < 2) { 21404 throw new IllegalArgumentException("inOutLocation must be an array of two integers"); 21405 } 21406 21407 if (mAttachInfo == null) { 21408 // When the view is not attached to a window, this method does not make sense 21409 inOutLocation[0] = inOutLocation[1] = 0; 21410 return; 21411 } 21412 21413 float position[] = mAttachInfo.mTmpTransformLocation; 21414 position[0] = inOutLocation[0]; 21415 position[1] = inOutLocation[1]; 21416 21417 if (!hasIdentityMatrix()) { 21418 getMatrix().mapPoints(position); 21419 } 21420 21421 position[0] += mLeft; 21422 position[1] += mTop; 21423 21424 ViewParent viewParent = mParent; 21425 while (viewParent instanceof View) { 21426 final View view = (View) viewParent; 21427 21428 position[0] -= view.mScrollX; 21429 position[1] -= view.mScrollY; 21430 21431 if (!view.hasIdentityMatrix()) { 21432 view.getMatrix().mapPoints(position); 21433 } 21434 21435 position[0] += view.mLeft; 21436 position[1] += view.mTop; 21437 21438 viewParent = view.mParent; 21439 } 21440 21441 if (viewParent instanceof ViewRootImpl) { 21442 // *cough* 21443 final ViewRootImpl vr = (ViewRootImpl) viewParent; 21444 position[1] -= vr.mCurScrollY; 21445 } 21446 21447 inOutLocation[0] = Math.round(position[0]); 21448 inOutLocation[1] = Math.round(position[1]); 21449 } 21450 21451 /** 21452 * @param id the id of the view to be found 21453 * @return the view of the specified id, null if cannot be found 21454 * @hide 21455 */ 21456 protected <T extends View> T findViewTraversal(@IdRes int id) { 21457 if (id == mID) { 21458 return (T) this; 21459 } 21460 return null; 21461 } 21462 21463 /** 21464 * @param tag the tag of the view to be found 21465 * @return the view of specified tag, null if cannot be found 21466 * @hide 21467 */ 21468 protected <T extends View> T findViewWithTagTraversal(Object tag) { 21469 if (tag != null && tag.equals(mTag)) { 21470 return (T) this; 21471 } 21472 return null; 21473 } 21474 21475 /** 21476 * @param predicate The predicate to evaluate. 21477 * @param childToSkip If not null, ignores this child during the recursive traversal. 21478 * @return The first view that matches the predicate or null. 21479 * @hide 21480 */ 21481 protected <T extends View> T findViewByPredicateTraversal(Predicate<View> predicate, 21482 View childToSkip) { 21483 if (predicate.test(this)) { 21484 return (T) this; 21485 } 21486 return null; 21487 } 21488 21489 /** 21490 * Finds the first descendant view with the given ID, the view itself if 21491 * the ID matches {@link #getId()}, or {@code null} if the ID is invalid 21492 * (< 0) or there is no matching view in the hierarchy. 21493 * <p> 21494 * <strong>Note:</strong> In most cases -- depending on compiler support -- 21495 * the resulting view is automatically cast to the target class type. If 21496 * the target class type is unconstrained, an explicit cast may be 21497 * necessary. 21498 * 21499 * @param id the ID to search for 21500 * @return a view with given ID if found, or {@code null} otherwise 21501 * @see View#findViewById(int) 21502 */ 21503 @Nullable 21504 public final <T extends View> T findViewById(@IdRes int id) { 21505 if (id == NO_ID) { 21506 return null; 21507 } 21508 return findViewTraversal(id); 21509 } 21510 21511 /** 21512 * Finds a view by its unuque and stable accessibility id. 21513 * 21514 * @param accessibilityId The searched accessibility id. 21515 * @return The found view. 21516 */ 21517 final <T extends View> T findViewByAccessibilityId(int accessibilityId) { 21518 if (accessibilityId < 0) { 21519 return null; 21520 } 21521 T view = findViewByAccessibilityIdTraversal(accessibilityId); 21522 if (view != null) { 21523 return view.includeForAccessibility() ? view : null; 21524 } 21525 return null; 21526 } 21527 21528 /** 21529 * Performs the traversal to find a view by its unique and stable accessibility id. 21530 * 21531 * <strong>Note:</strong>This method does not stop at the root namespace 21532 * boundary since the user can touch the screen at an arbitrary location 21533 * potentially crossing the root namespace boundary which will send an 21534 * accessibility event to accessibility services and they should be able 21535 * to obtain the event source. Also accessibility ids are guaranteed to be 21536 * unique in the window. 21537 * 21538 * @param accessibilityId The accessibility id. 21539 * @return The found view. 21540 * @hide 21541 */ 21542 public <T extends View> T findViewByAccessibilityIdTraversal(int accessibilityId) { 21543 if (getAccessibilityViewId() == accessibilityId) { 21544 return (T) this; 21545 } 21546 return null; 21547 } 21548 21549 /** 21550 * Performs the traversal to find a view by its autofill id. 21551 * 21552 * <strong>Note:</strong>This method does not stop at the root namespace 21553 * boundary. 21554 * 21555 * @param autofillId The autofill id. 21556 * @return The found view. 21557 * @hide 21558 */ 21559 public <T extends View> T findViewByAutofillIdTraversal(int autofillId) { 21560 if (getAutofillViewId() == autofillId) { 21561 return (T) this; 21562 } 21563 return null; 21564 } 21565 21566 /** 21567 * Look for a child view with the given tag. If this view has the given 21568 * tag, return this view. 21569 * 21570 * @param tag The tag to search for, using "tag.equals(getTag())". 21571 * @return The View that has the given tag in the hierarchy or null 21572 */ 21573 public final <T extends View> T findViewWithTag(Object tag) { 21574 if (tag == null) { 21575 return null; 21576 } 21577 return findViewWithTagTraversal(tag); 21578 } 21579 21580 /** 21581 * Look for a child view that matches the specified predicate. 21582 * If this view matches the predicate, return this view. 21583 * 21584 * @param predicate The predicate to evaluate. 21585 * @return The first view that matches the predicate or null. 21586 * @hide 21587 */ 21588 public final <T extends View> T findViewByPredicate(Predicate<View> predicate) { 21589 return findViewByPredicateTraversal(predicate, null); 21590 } 21591 21592 /** 21593 * Look for a child view that matches the specified predicate, 21594 * starting with the specified view and its descendents and then 21595 * recusively searching the ancestors and siblings of that view 21596 * until this view is reached. 21597 * 21598 * This method is useful in cases where the predicate does not match 21599 * a single unique view (perhaps multiple views use the same id) 21600 * and we are trying to find the view that is "closest" in scope to the 21601 * starting view. 21602 * 21603 * @param start The view to start from. 21604 * @param predicate The predicate to evaluate. 21605 * @return The first view that matches the predicate or null. 21606 * @hide 21607 */ 21608 public final <T extends View> T findViewByPredicateInsideOut( 21609 View start, Predicate<View> predicate) { 21610 View childToSkip = null; 21611 for (;;) { 21612 T view = start.findViewByPredicateTraversal(predicate, childToSkip); 21613 if (view != null || start == this) { 21614 return view; 21615 } 21616 21617 ViewParent parent = start.getParent(); 21618 if (parent == null || !(parent instanceof View)) { 21619 return null; 21620 } 21621 21622 childToSkip = start; 21623 start = (View) parent; 21624 } 21625 } 21626 21627 /** 21628 * Sets the identifier for this view. The identifier does not have to be 21629 * unique in this view's hierarchy. The identifier should be a positive 21630 * number. 21631 * 21632 * @see #NO_ID 21633 * @see #getId() 21634 * @see #findViewById(int) 21635 * 21636 * @param id a number used to identify the view 21637 * 21638 * @attr ref android.R.styleable#View_id 21639 */ 21640 public void setId(@IdRes int id) { 21641 mID = id; 21642 if (mID == View.NO_ID && mLabelForId != View.NO_ID) { 21643 mID = generateViewId(); 21644 } 21645 } 21646 21647 /** 21648 * {@hide} 21649 * 21650 * @param isRoot true if the view belongs to the root namespace, false 21651 * otherwise 21652 */ 21653 public void setIsRootNamespace(boolean isRoot) { 21654 if (isRoot) { 21655 mPrivateFlags |= PFLAG_IS_ROOT_NAMESPACE; 21656 } else { 21657 mPrivateFlags &= ~PFLAG_IS_ROOT_NAMESPACE; 21658 } 21659 } 21660 21661 /** 21662 * {@hide} 21663 * 21664 * @return true if the view belongs to the root namespace, false otherwise 21665 */ 21666 public boolean isRootNamespace() { 21667 return (mPrivateFlags&PFLAG_IS_ROOT_NAMESPACE) != 0; 21668 } 21669 21670 /** 21671 * Returns this view's identifier. 21672 * 21673 * @return a positive integer used to identify the view or {@link #NO_ID} 21674 * if the view has no ID 21675 * 21676 * @see #setId(int) 21677 * @see #findViewById(int) 21678 * @attr ref android.R.styleable#View_id 21679 */ 21680 @IdRes 21681 @ViewDebug.CapturedViewProperty 21682 public int getId() { 21683 return mID; 21684 } 21685 21686 /** 21687 * Returns this view's tag. 21688 * 21689 * @return the Object stored in this view as a tag, or {@code null} if not 21690 * set 21691 * 21692 * @see #setTag(Object) 21693 * @see #getTag(int) 21694 */ 21695 @ViewDebug.ExportedProperty 21696 public Object getTag() { 21697 return mTag; 21698 } 21699 21700 /** 21701 * Sets the tag associated with this view. A tag can be used to mark 21702 * a view in its hierarchy and does not have to be unique within the 21703 * hierarchy. Tags can also be used to store data within a view without 21704 * resorting to another data structure. 21705 * 21706 * @param tag an Object to tag the view with 21707 * 21708 * @see #getTag() 21709 * @see #setTag(int, Object) 21710 */ 21711 public void setTag(final Object tag) { 21712 mTag = tag; 21713 } 21714 21715 /** 21716 * Returns the tag associated with this view and the specified key. 21717 * 21718 * @param key The key identifying the tag 21719 * 21720 * @return the Object stored in this view as a tag, or {@code null} if not 21721 * set 21722 * 21723 * @see #setTag(int, Object) 21724 * @see #getTag() 21725 */ 21726 public Object getTag(int key) { 21727 if (mKeyedTags != null) return mKeyedTags.get(key); 21728 return null; 21729 } 21730 21731 /** 21732 * Sets a tag associated with this view and a key. A tag can be used 21733 * to mark a view in its hierarchy and does not have to be unique within 21734 * the hierarchy. Tags can also be used to store data within a view 21735 * without resorting to another data structure. 21736 * 21737 * The specified key should be an id declared in the resources of the 21738 * application to ensure it is unique (see the <a 21739 * href="{@docRoot}guide/topics/resources/more-resources.html#Id">ID resource type</a>). 21740 * Keys identified as belonging to 21741 * the Android framework or not associated with any package will cause 21742 * an {@link IllegalArgumentException} to be thrown. 21743 * 21744 * @param key The key identifying the tag 21745 * @param tag An Object to tag the view with 21746 * 21747 * @throws IllegalArgumentException If they specified key is not valid 21748 * 21749 * @see #setTag(Object) 21750 * @see #getTag(int) 21751 */ 21752 public void setTag(int key, final Object tag) { 21753 // If the package id is 0x00 or 0x01, it's either an undefined package 21754 // or a framework id 21755 if ((key >>> 24) < 2) { 21756 throw new IllegalArgumentException("The key must be an application-specific " 21757 + "resource id."); 21758 } 21759 21760 setKeyedTag(key, tag); 21761 } 21762 21763 /** 21764 * Variation of {@link #setTag(int, Object)} that enforces the key to be a 21765 * framework id. 21766 * 21767 * @hide 21768 */ 21769 public void setTagInternal(int key, Object tag) { 21770 if ((key >>> 24) != 0x1) { 21771 throw new IllegalArgumentException("The key must be a framework-specific " 21772 + "resource id."); 21773 } 21774 21775 setKeyedTag(key, tag); 21776 } 21777 21778 private void setKeyedTag(int key, Object tag) { 21779 if (mKeyedTags == null) { 21780 mKeyedTags = new SparseArray<Object>(2); 21781 } 21782 21783 mKeyedTags.put(key, tag); 21784 } 21785 21786 /** 21787 * Prints information about this view in the log output, with the tag 21788 * {@link #VIEW_LOG_TAG}. 21789 * 21790 * @hide 21791 */ 21792 public void debug() { 21793 debug(0); 21794 } 21795 21796 /** 21797 * Prints information about this view in the log output, with the tag 21798 * {@link #VIEW_LOG_TAG}. Each line in the output is preceded with an 21799 * indentation defined by the <code>depth</code>. 21800 * 21801 * @param depth the indentation level 21802 * 21803 * @hide 21804 */ 21805 protected void debug(int depth) { 21806 String output = debugIndent(depth - 1); 21807 21808 output += "+ " + this; 21809 int id = getId(); 21810 if (id != -1) { 21811 output += " (id=" + id + ")"; 21812 } 21813 Object tag = getTag(); 21814 if (tag != null) { 21815 output += " (tag=" + tag + ")"; 21816 } 21817 Log.d(VIEW_LOG_TAG, output); 21818 21819 if ((mPrivateFlags & PFLAG_FOCUSED) != 0) { 21820 output = debugIndent(depth) + " FOCUSED"; 21821 Log.d(VIEW_LOG_TAG, output); 21822 } 21823 21824 output = debugIndent(depth); 21825 output += "frame={" + mLeft + ", " + mTop + ", " + mRight 21826 + ", " + mBottom + "} scroll={" + mScrollX + ", " + mScrollY 21827 + "} "; 21828 Log.d(VIEW_LOG_TAG, output); 21829 21830 if (mPaddingLeft != 0 || mPaddingTop != 0 || mPaddingRight != 0 21831 || mPaddingBottom != 0) { 21832 output = debugIndent(depth); 21833 output += "padding={" + mPaddingLeft + ", " + mPaddingTop 21834 + ", " + mPaddingRight + ", " + mPaddingBottom + "}"; 21835 Log.d(VIEW_LOG_TAG, output); 21836 } 21837 21838 output = debugIndent(depth); 21839 output += "mMeasureWidth=" + mMeasuredWidth + 21840 " mMeasureHeight=" + mMeasuredHeight; 21841 Log.d(VIEW_LOG_TAG, output); 21842 21843 output = debugIndent(depth); 21844 if (mLayoutParams == null) { 21845 output += "BAD! no layout params"; 21846 } else { 21847 output = mLayoutParams.debug(output); 21848 } 21849 Log.d(VIEW_LOG_TAG, output); 21850 21851 output = debugIndent(depth); 21852 output += "flags={"; 21853 output += View.printFlags(mViewFlags); 21854 output += "}"; 21855 Log.d(VIEW_LOG_TAG, output); 21856 21857 output = debugIndent(depth); 21858 output += "privateFlags={"; 21859 output += View.printPrivateFlags(mPrivateFlags); 21860 output += "}"; 21861 Log.d(VIEW_LOG_TAG, output); 21862 } 21863 21864 /** 21865 * Creates a string of whitespaces used for indentation. 21866 * 21867 * @param depth the indentation level 21868 * @return a String containing (depth * 2 + 3) * 2 white spaces 21869 * 21870 * @hide 21871 */ 21872 protected static String debugIndent(int depth) { 21873 StringBuilder spaces = new StringBuilder((depth * 2 + 3) * 2); 21874 for (int i = 0; i < (depth * 2) + 3; i++) { 21875 spaces.append(' ').append(' '); 21876 } 21877 return spaces.toString(); 21878 } 21879 21880 /** 21881 * <p>Return the offset of the widget's text baseline from the widget's top 21882 * boundary. If this widget does not support baseline alignment, this 21883 * method returns -1. </p> 21884 * 21885 * @return the offset of the baseline within the widget's bounds or -1 21886 * if baseline alignment is not supported 21887 */ 21888 @ViewDebug.ExportedProperty(category = "layout") 21889 public int getBaseline() { 21890 return -1; 21891 } 21892 21893 /** 21894 * Returns whether the view hierarchy is currently undergoing a layout pass. This 21895 * information is useful to avoid situations such as calling {@link #requestLayout()} during 21896 * a layout pass. 21897 * 21898 * @return whether the view hierarchy is currently undergoing a layout pass 21899 */ 21900 public boolean isInLayout() { 21901 ViewRootImpl viewRoot = getViewRootImpl(); 21902 return (viewRoot != null && viewRoot.isInLayout()); 21903 } 21904 21905 /** 21906 * Call this when something has changed which has invalidated the 21907 * layout of this view. This will schedule a layout pass of the view 21908 * tree. This should not be called while the view hierarchy is currently in a layout 21909 * pass ({@link #isInLayout()}. If layout is happening, the request may be honored at the 21910 * end of the current layout pass (and then layout will run again) or after the current 21911 * frame is drawn and the next layout occurs. 21912 * 21913 * <p>Subclasses which override this method should call the superclass method to 21914 * handle possible request-during-layout errors correctly.</p> 21915 */ 21916 @CallSuper 21917 public void requestLayout() { 21918 if (mMeasureCache != null) mMeasureCache.clear(); 21919 21920 if (mAttachInfo != null && mAttachInfo.mViewRequestingLayout == null) { 21921 // Only trigger request-during-layout logic if this is the view requesting it, 21922 // not the views in its parent hierarchy 21923 ViewRootImpl viewRoot = getViewRootImpl(); 21924 if (viewRoot != null && viewRoot.isInLayout()) { 21925 if (!viewRoot.requestLayoutDuringLayout(this)) { 21926 return; 21927 } 21928 } 21929 mAttachInfo.mViewRequestingLayout = this; 21930 } 21931 21932 mPrivateFlags |= PFLAG_FORCE_LAYOUT; 21933 mPrivateFlags |= PFLAG_INVALIDATED; 21934 21935 if (mParent != null && !mParent.isLayoutRequested()) { 21936 mParent.requestLayout(); 21937 } 21938 if (mAttachInfo != null && mAttachInfo.mViewRequestingLayout == this) { 21939 mAttachInfo.mViewRequestingLayout = null; 21940 } 21941 } 21942 21943 /** 21944 * Forces this view to be laid out during the next layout pass. 21945 * This method does not call requestLayout() or forceLayout() 21946 * on the parent. 21947 */ 21948 public void forceLayout() { 21949 if (mMeasureCache != null) mMeasureCache.clear(); 21950 21951 mPrivateFlags |= PFLAG_FORCE_LAYOUT; 21952 mPrivateFlags |= PFLAG_INVALIDATED; 21953 } 21954 21955 /** 21956 * <p> 21957 * This is called to find out how big a view should be. The parent 21958 * supplies constraint information in the width and height parameters. 21959 * </p> 21960 * 21961 * <p> 21962 * The actual measurement work of a view is performed in 21963 * {@link #onMeasure(int, int)}, called by this method. Therefore, only 21964 * {@link #onMeasure(int, int)} can and must be overridden by subclasses. 21965 * </p> 21966 * 21967 * 21968 * @param widthMeasureSpec Horizontal space requirements as imposed by the 21969 * parent 21970 * @param heightMeasureSpec Vertical space requirements as imposed by the 21971 * parent 21972 * 21973 * @see #onMeasure(int, int) 21974 */ 21975 public final void measure(int widthMeasureSpec, int heightMeasureSpec) { 21976 boolean optical = isLayoutModeOptical(this); 21977 if (optical != isLayoutModeOptical(mParent)) { 21978 Insets insets = getOpticalInsets(); 21979 int oWidth = insets.left + insets.right; 21980 int oHeight = insets.top + insets.bottom; 21981 widthMeasureSpec = MeasureSpec.adjust(widthMeasureSpec, optical ? -oWidth : oWidth); 21982 heightMeasureSpec = MeasureSpec.adjust(heightMeasureSpec, optical ? -oHeight : oHeight); 21983 } 21984 21985 // Suppress sign extension for the low bytes 21986 long key = (long) widthMeasureSpec << 32 | (long) heightMeasureSpec & 0xffffffffL; 21987 if (mMeasureCache == null) mMeasureCache = new LongSparseLongArray(2); 21988 21989 final boolean forceLayout = (mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT; 21990 21991 // Optimize layout by avoiding an extra EXACTLY pass when the view is 21992 // already measured as the correct size. In API 23 and below, this 21993 // extra pass is required to make LinearLayout re-distribute weight. 21994 final boolean specChanged = widthMeasureSpec != mOldWidthMeasureSpec 21995 || heightMeasureSpec != mOldHeightMeasureSpec; 21996 final boolean isSpecExactly = MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY 21997 && MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.EXACTLY; 21998 final boolean matchesSpecSize = getMeasuredWidth() == MeasureSpec.getSize(widthMeasureSpec) 21999 && getMeasuredHeight() == MeasureSpec.getSize(heightMeasureSpec); 22000 final boolean needsLayout = specChanged 22001 && (sAlwaysRemeasureExactly || !isSpecExactly || !matchesSpecSize); 22002 22003 if (forceLayout || needsLayout) { 22004 // first clears the measured dimension flag 22005 mPrivateFlags &= ~PFLAG_MEASURED_DIMENSION_SET; 22006 22007 resolveRtlPropertiesIfNeeded(); 22008 22009 int cacheIndex = forceLayout ? -1 : mMeasureCache.indexOfKey(key); 22010 if (cacheIndex < 0 || sIgnoreMeasureCache) { 22011 // measure ourselves, this should set the measured dimension flag back 22012 onMeasure(widthMeasureSpec, heightMeasureSpec); 22013 mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT; 22014 } else { 22015 long value = mMeasureCache.valueAt(cacheIndex); 22016 // Casting a long to int drops the high 32 bits, no mask needed 22017 setMeasuredDimensionRaw((int) (value >> 32), (int) value); 22018 mPrivateFlags3 |= PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT; 22019 } 22020 22021 // flag not set, setMeasuredDimension() was not invoked, we raise 22022 // an exception to warn the developer 22023 if ((mPrivateFlags & PFLAG_MEASURED_DIMENSION_SET) != PFLAG_MEASURED_DIMENSION_SET) { 22024 throw new IllegalStateException("View with id " + getId() + ": " 22025 + getClass().getName() + "#onMeasure() did not set the" 22026 + " measured dimension by calling" 22027 + " setMeasuredDimension()"); 22028 } 22029 22030 mPrivateFlags |= PFLAG_LAYOUT_REQUIRED; 22031 } 22032 22033 mOldWidthMeasureSpec = widthMeasureSpec; 22034 mOldHeightMeasureSpec = heightMeasureSpec; 22035 22036 mMeasureCache.put(key, ((long) mMeasuredWidth) << 32 | 22037 (long) mMeasuredHeight & 0xffffffffL); // suppress sign extension 22038 } 22039 22040 /** 22041 * <p> 22042 * Measure the view and its content to determine the measured width and the 22043 * measured height. This method is invoked by {@link #measure(int, int)} and 22044 * should be overridden by subclasses to provide accurate and efficient 22045 * measurement of their contents. 22046 * </p> 22047 * 22048 * <p> 22049 * <strong>CONTRACT:</strong> When overriding this method, you 22050 * <em>must</em> call {@link #setMeasuredDimension(int, int)} to store the 22051 * measured width and height of this view. Failure to do so will trigger an 22052 * <code>IllegalStateException</code>, thrown by 22053 * {@link #measure(int, int)}. Calling the superclass' 22054 * {@link #onMeasure(int, int)} is a valid use. 22055 * </p> 22056 * 22057 * <p> 22058 * The base class implementation of measure defaults to the background size, 22059 * unless a larger size is allowed by the MeasureSpec. Subclasses should 22060 * override {@link #onMeasure(int, int)} to provide better measurements of 22061 * their content. 22062 * </p> 22063 * 22064 * <p> 22065 * If this method is overridden, it is the subclass's responsibility to make 22066 * sure the measured height and width are at least the view's minimum height 22067 * and width ({@link #getSuggestedMinimumHeight()} and 22068 * {@link #getSuggestedMinimumWidth()}). 22069 * </p> 22070 * 22071 * @param widthMeasureSpec horizontal space requirements as imposed by the parent. 22072 * The requirements are encoded with 22073 * {@link android.view.View.MeasureSpec}. 22074 * @param heightMeasureSpec vertical space requirements as imposed by the parent. 22075 * The requirements are encoded with 22076 * {@link android.view.View.MeasureSpec}. 22077 * 22078 * @see #getMeasuredWidth() 22079 * @see #getMeasuredHeight() 22080 * @see #setMeasuredDimension(int, int) 22081 * @see #getSuggestedMinimumHeight() 22082 * @see #getSuggestedMinimumWidth() 22083 * @see android.view.View.MeasureSpec#getMode(int) 22084 * @see android.view.View.MeasureSpec#getSize(int) 22085 */ 22086 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 22087 setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec), 22088 getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec)); 22089 } 22090 22091 /** 22092 * <p>This method must be called by {@link #onMeasure(int, int)} to store the 22093 * measured width and measured height. Failing to do so will trigger an 22094 * exception at measurement time.</p> 22095 * 22096 * @param measuredWidth The measured width of this view. May be a complex 22097 * bit mask as defined by {@link #MEASURED_SIZE_MASK} and 22098 * {@link #MEASURED_STATE_TOO_SMALL}. 22099 * @param measuredHeight The measured height of this view. May be a complex 22100 * bit mask as defined by {@link #MEASURED_SIZE_MASK} and 22101 * {@link #MEASURED_STATE_TOO_SMALL}. 22102 */ 22103 protected final void setMeasuredDimension(int measuredWidth, int measuredHeight) { 22104 boolean optical = isLayoutModeOptical(this); 22105 if (optical != isLayoutModeOptical(mParent)) { 22106 Insets insets = getOpticalInsets(); 22107 int opticalWidth = insets.left + insets.right; 22108 int opticalHeight = insets.top + insets.bottom; 22109 22110 measuredWidth += optical ? opticalWidth : -opticalWidth; 22111 measuredHeight += optical ? opticalHeight : -opticalHeight; 22112 } 22113 setMeasuredDimensionRaw(measuredWidth, measuredHeight); 22114 } 22115 22116 /** 22117 * Sets the measured dimension without extra processing for things like optical bounds. 22118 * Useful for reapplying consistent values that have already been cooked with adjustments 22119 * for optical bounds, etc. such as those from the measurement cache. 22120 * 22121 * @param measuredWidth The measured width of this view. May be a complex 22122 * bit mask as defined by {@link #MEASURED_SIZE_MASK} and 22123 * {@link #MEASURED_STATE_TOO_SMALL}. 22124 * @param measuredHeight The measured height of this view. May be a complex 22125 * bit mask as defined by {@link #MEASURED_SIZE_MASK} and 22126 * {@link #MEASURED_STATE_TOO_SMALL}. 22127 */ 22128 private void setMeasuredDimensionRaw(int measuredWidth, int measuredHeight) { 22129 mMeasuredWidth = measuredWidth; 22130 mMeasuredHeight = measuredHeight; 22131 22132 mPrivateFlags |= PFLAG_MEASURED_DIMENSION_SET; 22133 } 22134 22135 /** 22136 * Merge two states as returned by {@link #getMeasuredState()}. 22137 * @param curState The current state as returned from a view or the result 22138 * of combining multiple views. 22139 * @param newState The new view state to combine. 22140 * @return Returns a new integer reflecting the combination of the two 22141 * states. 22142 */ 22143 public static int combineMeasuredStates(int curState, int newState) { 22144 return curState | newState; 22145 } 22146 22147 /** 22148 * Version of {@link #resolveSizeAndState(int, int, int)} 22149 * returning only the {@link #MEASURED_SIZE_MASK} bits of the result. 22150 */ 22151 public static int resolveSize(int size, int measureSpec) { 22152 return resolveSizeAndState(size, measureSpec, 0) & MEASURED_SIZE_MASK; 22153 } 22154 22155 /** 22156 * Utility to reconcile a desired size and state, with constraints imposed 22157 * by a MeasureSpec. Will take the desired size, unless a different size 22158 * is imposed by the constraints. The returned value is a compound integer, 22159 * with the resolved size in the {@link #MEASURED_SIZE_MASK} bits and 22160 * optionally the bit {@link #MEASURED_STATE_TOO_SMALL} set if the 22161 * resulting size is smaller than the size the view wants to be. 22162 * 22163 * @param size How big the view wants to be. 22164 * @param measureSpec Constraints imposed by the parent. 22165 * @param childMeasuredState Size information bit mask for the view's 22166 * children. 22167 * @return Size information bit mask as defined by 22168 * {@link #MEASURED_SIZE_MASK} and 22169 * {@link #MEASURED_STATE_TOO_SMALL}. 22170 */ 22171 public static int resolveSizeAndState(int size, int measureSpec, int childMeasuredState) { 22172 final int specMode = MeasureSpec.getMode(measureSpec); 22173 final int specSize = MeasureSpec.getSize(measureSpec); 22174 final int result; 22175 switch (specMode) { 22176 case MeasureSpec.AT_MOST: 22177 if (specSize < size) { 22178 result = specSize | MEASURED_STATE_TOO_SMALL; 22179 } else { 22180 result = size; 22181 } 22182 break; 22183 case MeasureSpec.EXACTLY: 22184 result = specSize; 22185 break; 22186 case MeasureSpec.UNSPECIFIED: 22187 default: 22188 result = size; 22189 } 22190 return result | (childMeasuredState & MEASURED_STATE_MASK); 22191 } 22192 22193 /** 22194 * Utility to return a default size. Uses the supplied size if the 22195 * MeasureSpec imposed no constraints. Will get larger if allowed 22196 * by the MeasureSpec. 22197 * 22198 * @param size Default size for this view 22199 * @param measureSpec Constraints imposed by the parent 22200 * @return The size this view should be. 22201 */ 22202 public static int getDefaultSize(int size, int measureSpec) { 22203 int result = size; 22204 int specMode = MeasureSpec.getMode(measureSpec); 22205 int specSize = MeasureSpec.getSize(measureSpec); 22206 22207 switch (specMode) { 22208 case MeasureSpec.UNSPECIFIED: 22209 result = size; 22210 break; 22211 case MeasureSpec.AT_MOST: 22212 case MeasureSpec.EXACTLY: 22213 result = specSize; 22214 break; 22215 } 22216 return result; 22217 } 22218 22219 /** 22220 * Returns the suggested minimum height that the view should use. This 22221 * returns the maximum of the view's minimum height 22222 * and the background's minimum height 22223 * ({@link android.graphics.drawable.Drawable#getMinimumHeight()}). 22224 * <p> 22225 * When being used in {@link #onMeasure(int, int)}, the caller should still 22226 * ensure the returned height is within the requirements of the parent. 22227 * 22228 * @return The suggested minimum height of the view. 22229 */ 22230 protected int getSuggestedMinimumHeight() { 22231 return (mBackground == null) ? mMinHeight : max(mMinHeight, mBackground.getMinimumHeight()); 22232 22233 } 22234 22235 /** 22236 * Returns the suggested minimum width that the view should use. This 22237 * returns the maximum of the view's minimum width 22238 * and the background's minimum width 22239 * ({@link android.graphics.drawable.Drawable#getMinimumWidth()}). 22240 * <p> 22241 * When being used in {@link #onMeasure(int, int)}, the caller should still 22242 * ensure the returned width is within the requirements of the parent. 22243 * 22244 * @return The suggested minimum width of the view. 22245 */ 22246 protected int getSuggestedMinimumWidth() { 22247 return (mBackground == null) ? mMinWidth : max(mMinWidth, mBackground.getMinimumWidth()); 22248 } 22249 22250 /** 22251 * Returns the minimum height of the view. 22252 * 22253 * @return the minimum height the view will try to be, in pixels 22254 * 22255 * @see #setMinimumHeight(int) 22256 * 22257 * @attr ref android.R.styleable#View_minHeight 22258 */ 22259 public int getMinimumHeight() { 22260 return mMinHeight; 22261 } 22262 22263 /** 22264 * Sets the minimum height of the view. It is not guaranteed the view will 22265 * be able to achieve this minimum height (for example, if its parent layout 22266 * constrains it with less available height). 22267 * 22268 * @param minHeight The minimum height the view will try to be, in pixels 22269 * 22270 * @see #getMinimumHeight() 22271 * 22272 * @attr ref android.R.styleable#View_minHeight 22273 */ 22274 @RemotableViewMethod 22275 public void setMinimumHeight(int minHeight) { 22276 mMinHeight = minHeight; 22277 requestLayout(); 22278 } 22279 22280 /** 22281 * Returns the minimum width of the view. 22282 * 22283 * @return the minimum width the view will try to be, in pixels 22284 * 22285 * @see #setMinimumWidth(int) 22286 * 22287 * @attr ref android.R.styleable#View_minWidth 22288 */ 22289 public int getMinimumWidth() { 22290 return mMinWidth; 22291 } 22292 22293 /** 22294 * Sets the minimum width of the view. It is not guaranteed the view will 22295 * be able to achieve this minimum width (for example, if its parent layout 22296 * constrains it with less available width). 22297 * 22298 * @param minWidth The minimum width the view will try to be, in pixels 22299 * 22300 * @see #getMinimumWidth() 22301 * 22302 * @attr ref android.R.styleable#View_minWidth 22303 */ 22304 public void setMinimumWidth(int minWidth) { 22305 mMinWidth = minWidth; 22306 requestLayout(); 22307 22308 } 22309 22310 /** 22311 * Get the animation currently associated with this view. 22312 * 22313 * @return The animation that is currently playing or 22314 * scheduled to play for this view. 22315 */ 22316 public Animation getAnimation() { 22317 return mCurrentAnimation; 22318 } 22319 22320 /** 22321 * Start the specified animation now. 22322 * 22323 * @param animation the animation to start now 22324 */ 22325 public void startAnimation(Animation animation) { 22326 animation.setStartTime(Animation.START_ON_FIRST_FRAME); 22327 setAnimation(animation); 22328 invalidateParentCaches(); 22329 invalidate(true); 22330 } 22331 22332 /** 22333 * Cancels any animations for this view. 22334 */ 22335 public void clearAnimation() { 22336 if (mCurrentAnimation != null) { 22337 mCurrentAnimation.detach(); 22338 } 22339 mCurrentAnimation = null; 22340 invalidateParentIfNeeded(); 22341 } 22342 22343 /** 22344 * Sets the next animation to play for this view. 22345 * If you want the animation to play immediately, use 22346 * {@link #startAnimation(android.view.animation.Animation)} instead. 22347 * This method provides allows fine-grained 22348 * control over the start time and invalidation, but you 22349 * must make sure that 1) the animation has a start time set, and 22350 * 2) the view's parent (which controls animations on its children) 22351 * will be invalidated when the animation is supposed to 22352 * start. 22353 * 22354 * @param animation The next animation, or null. 22355 */ 22356 public void setAnimation(Animation animation) { 22357 mCurrentAnimation = animation; 22358 22359 if (animation != null) { 22360 // If the screen is off assume the animation start time is now instead of 22361 // the next frame we draw. Keeping the START_ON_FIRST_FRAME start time 22362 // would cause the animation to start when the screen turns back on 22363 if (mAttachInfo != null && mAttachInfo.mDisplayState == Display.STATE_OFF 22364 && animation.getStartTime() == Animation.START_ON_FIRST_FRAME) { 22365 animation.setStartTime(AnimationUtils.currentAnimationTimeMillis()); 22366 } 22367 animation.reset(); 22368 } 22369 } 22370 22371 /** 22372 * Invoked by a parent ViewGroup to notify the start of the animation 22373 * currently associated with this view. If you override this method, 22374 * always call super.onAnimationStart(); 22375 * 22376 * @see #setAnimation(android.view.animation.Animation) 22377 * @see #getAnimation() 22378 */ 22379 @CallSuper 22380 protected void onAnimationStart() { 22381 mPrivateFlags |= PFLAG_ANIMATION_STARTED; 22382 } 22383 22384 /** 22385 * Invoked by a parent ViewGroup to notify the end of the animation 22386 * currently associated with this view. If you override this method, 22387 * always call super.onAnimationEnd(); 22388 * 22389 * @see #setAnimation(android.view.animation.Animation) 22390 * @see #getAnimation() 22391 */ 22392 @CallSuper 22393 protected void onAnimationEnd() { 22394 mPrivateFlags &= ~PFLAG_ANIMATION_STARTED; 22395 } 22396 22397 /** 22398 * Invoked if there is a Transform that involves alpha. Subclass that can 22399 * draw themselves with the specified alpha should return true, and then 22400 * respect that alpha when their onDraw() is called. If this returns false 22401 * then the view may be redirected to draw into an offscreen buffer to 22402 * fulfill the request, which will look fine, but may be slower than if the 22403 * subclass handles it internally. The default implementation returns false. 22404 * 22405 * @param alpha The alpha (0..255) to apply to the view's drawing 22406 * @return true if the view can draw with the specified alpha. 22407 */ 22408 protected boolean onSetAlpha(int alpha) { 22409 return false; 22410 } 22411 22412 /** 22413 * This is used by the RootView to perform an optimization when 22414 * the view hierarchy contains one or several SurfaceView. 22415 * SurfaceView is always considered transparent, but its children are not, 22416 * therefore all View objects remove themselves from the global transparent 22417 * region (passed as a parameter to this function). 22418 * 22419 * @param region The transparent region for this ViewAncestor (window). 22420 * 22421 * @return Returns true if the effective visibility of the view at this 22422 * point is opaque, regardless of the transparent region; returns false 22423 * if it is possible for underlying windows to be seen behind the view. 22424 * 22425 * {@hide} 22426 */ 22427 public boolean gatherTransparentRegion(Region region) { 22428 final AttachInfo attachInfo = mAttachInfo; 22429 if (region != null && attachInfo != null) { 22430 final int pflags = mPrivateFlags; 22431 if ((pflags & PFLAG_SKIP_DRAW) == 0) { 22432 // The SKIP_DRAW flag IS NOT set, so this view draws. We need to 22433 // remove it from the transparent region. 22434 final int[] location = attachInfo.mTransparentLocation; 22435 getLocationInWindow(location); 22436 // When a view has Z value, then it will be better to leave some area below the view 22437 // for drawing shadow. The shadow outset is proportional to the Z value. Note that 22438 // the bottom part needs more offset than the left, top and right parts due to the 22439 // spot light effects. 22440 int shadowOffset = getZ() > 0 ? (int) getZ() : 0; 22441 region.op(location[0] - shadowOffset, location[1] - shadowOffset, 22442 location[0] + mRight - mLeft + shadowOffset, 22443 location[1] + mBottom - mTop + (shadowOffset * 3), Region.Op.DIFFERENCE); 22444 } else { 22445 if (mBackground != null && mBackground.getOpacity() != PixelFormat.TRANSPARENT) { 22446 // The SKIP_DRAW flag IS set and the background drawable exists, we remove 22447 // the background drawable's non-transparent parts from this transparent region. 22448 applyDrawableToTransparentRegion(mBackground, region); 22449 } 22450 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null 22451 && mForegroundInfo.mDrawable.getOpacity() != PixelFormat.TRANSPARENT) { 22452 // Similarly, we remove the foreground drawable's non-transparent parts. 22453 applyDrawableToTransparentRegion(mForegroundInfo.mDrawable, region); 22454 } 22455 if (mDefaultFocusHighlight != null 22456 && mDefaultFocusHighlight.getOpacity() != PixelFormat.TRANSPARENT) { 22457 // Similarly, we remove the default focus highlight's non-transparent parts. 22458 applyDrawableToTransparentRegion(mDefaultFocusHighlight, region); 22459 } 22460 } 22461 } 22462 return true; 22463 } 22464 22465 /** 22466 * Play a sound effect for this view. 22467 * 22468 * <p>The framework will play sound effects for some built in actions, such as 22469 * clicking, but you may wish to play these effects in your widget, 22470 * for instance, for internal navigation. 22471 * 22472 * <p>The sound effect will only be played if sound effects are enabled by the user, and 22473 * {@link #isSoundEffectsEnabled()} is true. 22474 * 22475 * @param soundConstant One of the constants defined in {@link SoundEffectConstants} 22476 */ 22477 public void playSoundEffect(int soundConstant) { 22478 if (mAttachInfo == null || mAttachInfo.mRootCallbacks == null || !isSoundEffectsEnabled()) { 22479 return; 22480 } 22481 mAttachInfo.mRootCallbacks.playSoundEffect(soundConstant); 22482 } 22483 22484 /** 22485 * BZZZTT!!1! 22486 * 22487 * <p>Provide haptic feedback to the user for this view. 22488 * 22489 * <p>The framework will provide haptic feedback for some built in actions, 22490 * such as long presses, but you may wish to provide feedback for your 22491 * own widget. 22492 * 22493 * <p>The feedback will only be performed if 22494 * {@link #isHapticFeedbackEnabled()} is true. 22495 * 22496 * @param feedbackConstant One of the constants defined in 22497 * {@link HapticFeedbackConstants} 22498 */ 22499 public boolean performHapticFeedback(int feedbackConstant) { 22500 return performHapticFeedback(feedbackConstant, 0); 22501 } 22502 22503 /** 22504 * BZZZTT!!1! 22505 * 22506 * <p>Like {@link #performHapticFeedback(int)}, with additional options. 22507 * 22508 * @param feedbackConstant One of the constants defined in 22509 * {@link HapticFeedbackConstants} 22510 * @param flags Additional flags as per {@link HapticFeedbackConstants}. 22511 */ 22512 public boolean performHapticFeedback(int feedbackConstant, int flags) { 22513 if (mAttachInfo == null) { 22514 return false; 22515 } 22516 //noinspection SimplifiableIfStatement 22517 if ((flags & HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING) == 0 22518 && !isHapticFeedbackEnabled()) { 22519 return false; 22520 } 22521 return mAttachInfo.mRootCallbacks.performHapticFeedback(feedbackConstant, 22522 (flags & HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING) != 0); 22523 } 22524 22525 /** 22526 * Request that the visibility of the status bar or other screen/window 22527 * decorations be changed. 22528 * 22529 * <p>This method is used to put the over device UI into temporary modes 22530 * where the user's attention is focused more on the application content, 22531 * by dimming or hiding surrounding system affordances. This is typically 22532 * used in conjunction with {@link Window#FEATURE_ACTION_BAR_OVERLAY 22533 * Window.FEATURE_ACTION_BAR_OVERLAY}, allowing the applications content 22534 * to be placed behind the action bar (and with these flags other system 22535 * affordances) so that smooth transitions between hiding and showing them 22536 * can be done. 22537 * 22538 * <p>Two representative examples of the use of system UI visibility is 22539 * implementing a content browsing application (like a magazine reader) 22540 * and a video playing application. 22541 * 22542 * <p>The first code shows a typical implementation of a View in a content 22543 * browsing application. In this implementation, the application goes 22544 * into a content-oriented mode by hiding the status bar and action bar, 22545 * and putting the navigation elements into lights out mode. The user can 22546 * then interact with content while in this mode. Such an application should 22547 * provide an easy way for the user to toggle out of the mode (such as to 22548 * check information in the status bar or access notifications). In the 22549 * implementation here, this is done simply by tapping on the content. 22550 * 22551 * {@sample development/samples/ApiDemos/src/com/example/android/apis/view/ContentBrowserActivity.java 22552 * content} 22553 * 22554 * <p>This second code sample shows a typical implementation of a View 22555 * in a video playing application. In this situation, while the video is 22556 * playing the application would like to go into a complete full-screen mode, 22557 * to use as much of the display as possible for the video. When in this state 22558 * the user can not interact with the application; the system intercepts 22559 * touching on the screen to pop the UI out of full screen mode. See 22560 * {@link #fitSystemWindows(Rect)} for a sample layout that goes with this code. 22561 * 22562 * {@sample development/samples/ApiDemos/src/com/example/android/apis/view/VideoPlayerActivity.java 22563 * content} 22564 * 22565 * @param visibility Bitwise-or of flags {@link #SYSTEM_UI_FLAG_LOW_PROFILE}, 22566 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, {@link #SYSTEM_UI_FLAG_FULLSCREEN}, 22567 * {@link #SYSTEM_UI_FLAG_LAYOUT_STABLE}, {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION}, 22568 * {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN}, {@link #SYSTEM_UI_FLAG_IMMERSIVE}, 22569 * and {@link #SYSTEM_UI_FLAG_IMMERSIVE_STICKY}. 22570 */ 22571 public void setSystemUiVisibility(int visibility) { 22572 if (visibility != mSystemUiVisibility) { 22573 mSystemUiVisibility = visibility; 22574 if (mParent != null && mAttachInfo != null && !mAttachInfo.mRecomputeGlobalAttributes) { 22575 mParent.recomputeViewAttributes(this); 22576 } 22577 } 22578 } 22579 22580 /** 22581 * Returns the last {@link #setSystemUiVisibility(int)} that this view has requested. 22582 * @return Bitwise-or of flags {@link #SYSTEM_UI_FLAG_LOW_PROFILE}, 22583 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, {@link #SYSTEM_UI_FLAG_FULLSCREEN}, 22584 * {@link #SYSTEM_UI_FLAG_LAYOUT_STABLE}, {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION}, 22585 * {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN}, {@link #SYSTEM_UI_FLAG_IMMERSIVE}, 22586 * and {@link #SYSTEM_UI_FLAG_IMMERSIVE_STICKY}. 22587 */ 22588 public int getSystemUiVisibility() { 22589 return mSystemUiVisibility; 22590 } 22591 22592 /** 22593 * Returns the current system UI visibility that is currently set for 22594 * the entire window. This is the combination of the 22595 * {@link #setSystemUiVisibility(int)} values supplied by all of the 22596 * views in the window. 22597 */ 22598 public int getWindowSystemUiVisibility() { 22599 return mAttachInfo != null ? mAttachInfo.mSystemUiVisibility : 0; 22600 } 22601 22602 /** 22603 * Override to find out when the window's requested system UI visibility 22604 * has changed, that is the value returned by {@link #getWindowSystemUiVisibility()}. 22605 * This is different from the callbacks received through 22606 * {@link #setOnSystemUiVisibilityChangeListener(OnSystemUiVisibilityChangeListener)} 22607 * in that this is only telling you about the local request of the window, 22608 * not the actual values applied by the system. 22609 */ 22610 public void onWindowSystemUiVisibilityChanged(int visible) { 22611 } 22612 22613 /** 22614 * Dispatch callbacks to {@link #onWindowSystemUiVisibilityChanged(int)} down 22615 * the view hierarchy. 22616 */ 22617 public void dispatchWindowSystemUiVisiblityChanged(int visible) { 22618 onWindowSystemUiVisibilityChanged(visible); 22619 } 22620 22621 /** 22622 * Set a listener to receive callbacks when the visibility of the system bar changes. 22623 * @param l The {@link OnSystemUiVisibilityChangeListener} to receive callbacks. 22624 */ 22625 public void setOnSystemUiVisibilityChangeListener(OnSystemUiVisibilityChangeListener l) { 22626 getListenerInfo().mOnSystemUiVisibilityChangeListener = l; 22627 if (mParent != null && mAttachInfo != null && !mAttachInfo.mRecomputeGlobalAttributes) { 22628 mParent.recomputeViewAttributes(this); 22629 } 22630 } 22631 22632 /** 22633 * Dispatch callbacks to {@link #setOnSystemUiVisibilityChangeListener} down 22634 * the view hierarchy. 22635 */ 22636 public void dispatchSystemUiVisibilityChanged(int visibility) { 22637 ListenerInfo li = mListenerInfo; 22638 if (li != null && li.mOnSystemUiVisibilityChangeListener != null) { 22639 li.mOnSystemUiVisibilityChangeListener.onSystemUiVisibilityChange( 22640 visibility & PUBLIC_STATUS_BAR_VISIBILITY_MASK); 22641 } 22642 } 22643 22644 boolean updateLocalSystemUiVisibility(int localValue, int localChanges) { 22645 int val = (mSystemUiVisibility&~localChanges) | (localValue&localChanges); 22646 if (val != mSystemUiVisibility) { 22647 setSystemUiVisibility(val); 22648 return true; 22649 } 22650 return false; 22651 } 22652 22653 /** @hide */ 22654 public void setDisabledSystemUiVisibility(int flags) { 22655 if (mAttachInfo != null) { 22656 if (mAttachInfo.mDisabledSystemUiVisibility != flags) { 22657 mAttachInfo.mDisabledSystemUiVisibility = flags; 22658 if (mParent != null) { 22659 mParent.recomputeViewAttributes(this); 22660 } 22661 } 22662 } 22663 } 22664 22665 /** 22666 * Creates an image that the system displays during the drag and drop 22667 * operation. This is called a "drag shadow". The default implementation 22668 * for a DragShadowBuilder based on a View returns an image that has exactly the same 22669 * appearance as the given View. The default also positions the center of the drag shadow 22670 * directly under the touch point. If no View is provided (the constructor with no parameters 22671 * is used), and {@link #onProvideShadowMetrics(Point,Point) onProvideShadowMetrics()} and 22672 * {@link #onDrawShadow(Canvas) onDrawShadow()} are not overridden, then the 22673 * default is an invisible drag shadow. 22674 * <p> 22675 * You are not required to use the View you provide to the constructor as the basis of the 22676 * drag shadow. The {@link #onDrawShadow(Canvas) onDrawShadow()} method allows you to draw 22677 * anything you want as the drag shadow. 22678 * </p> 22679 * <p> 22680 * You pass a DragShadowBuilder object to the system when you start the drag. The system 22681 * calls {@link #onProvideShadowMetrics(Point,Point) onProvideShadowMetrics()} to get the 22682 * size and position of the drag shadow. It uses this data to construct a 22683 * {@link android.graphics.Canvas} object, then it calls {@link #onDrawShadow(Canvas) onDrawShadow()} 22684 * so that your application can draw the shadow image in the Canvas. 22685 * </p> 22686 * 22687 * <div class="special reference"> 22688 * <h3>Developer Guides</h3> 22689 * <p>For a guide to implementing drag and drop features, read the 22690 * <a href="{@docRoot}guide/topics/ui/drag-drop.html">Drag and Drop</a> developer guide.</p> 22691 * </div> 22692 */ 22693 public static class DragShadowBuilder { 22694 private final WeakReference<View> mView; 22695 22696 /** 22697 * Constructs a shadow image builder based on a View. By default, the resulting drag 22698 * shadow will have the same appearance and dimensions as the View, with the touch point 22699 * over the center of the View. 22700 * @param view A View. Any View in scope can be used. 22701 */ 22702 public DragShadowBuilder(View view) { 22703 mView = new WeakReference<View>(view); 22704 } 22705 22706 /** 22707 * Construct a shadow builder object with no associated View. This 22708 * constructor variant is only useful when the {@link #onProvideShadowMetrics(Point, Point)} 22709 * and {@link #onDrawShadow(Canvas)} methods are also overridden in order 22710 * to supply the drag shadow's dimensions and appearance without 22711 * reference to any View object. If they are not overridden, then the result is an 22712 * invisible drag shadow. 22713 */ 22714 public DragShadowBuilder() { 22715 mView = new WeakReference<View>(null); 22716 } 22717 22718 /** 22719 * Returns the View object that had been passed to the 22720 * {@link #View.DragShadowBuilder(View)} 22721 * constructor. If that View parameter was {@code null} or if the 22722 * {@link #View.DragShadowBuilder()} 22723 * constructor was used to instantiate the builder object, this method will return 22724 * null. 22725 * 22726 * @return The View object associate with this builder object. 22727 */ 22728 @SuppressWarnings({"JavadocReference"}) 22729 final public View getView() { 22730 return mView.get(); 22731 } 22732 22733 /** 22734 * Provides the metrics for the shadow image. These include the dimensions of 22735 * the shadow image, and the point within that shadow that should 22736 * be centered under the touch location while dragging. 22737 * <p> 22738 * The default implementation sets the dimensions of the shadow to be the 22739 * same as the dimensions of the View itself and centers the shadow under 22740 * the touch point. 22741 * </p> 22742 * 22743 * @param outShadowSize A {@link android.graphics.Point} containing the width and height 22744 * of the shadow image. Your application must set {@link android.graphics.Point#x} to the 22745 * desired width and must set {@link android.graphics.Point#y} to the desired height of the 22746 * image. 22747 * 22748 * @param outShadowTouchPoint A {@link android.graphics.Point} for the position within the 22749 * shadow image that should be underneath the touch point during the drag and drop 22750 * operation. Your application must set {@link android.graphics.Point#x} to the 22751 * X coordinate and {@link android.graphics.Point#y} to the Y coordinate of this position. 22752 */ 22753 public void onProvideShadowMetrics(Point outShadowSize, Point outShadowTouchPoint) { 22754 final View view = mView.get(); 22755 if (view != null) { 22756 outShadowSize.set(view.getWidth(), view.getHeight()); 22757 outShadowTouchPoint.set(outShadowSize.x / 2, outShadowSize.y / 2); 22758 } else { 22759 Log.e(View.VIEW_LOG_TAG, "Asked for drag thumb metrics but no view"); 22760 } 22761 } 22762 22763 /** 22764 * Draws the shadow image. The system creates the {@link android.graphics.Canvas} object 22765 * based on the dimensions it received from the 22766 * {@link #onProvideShadowMetrics(Point, Point)} callback. 22767 * 22768 * @param canvas A {@link android.graphics.Canvas} object in which to draw the shadow image. 22769 */ 22770 public void onDrawShadow(Canvas canvas) { 22771 final View view = mView.get(); 22772 if (view != null) { 22773 view.draw(canvas); 22774 } else { 22775 Log.e(View.VIEW_LOG_TAG, "Asked to draw drag shadow but no view"); 22776 } 22777 } 22778 } 22779 22780 /** 22781 * @deprecated Use {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, int) 22782 * startDragAndDrop()} for newer platform versions. 22783 */ 22784 @Deprecated 22785 public final boolean startDrag(ClipData data, DragShadowBuilder shadowBuilder, 22786 Object myLocalState, int flags) { 22787 return startDragAndDrop(data, shadowBuilder, myLocalState, flags); 22788 } 22789 22790 /** 22791 * Starts a drag and drop operation. When your application calls this method, it passes a 22792 * {@link android.view.View.DragShadowBuilder} object to the system. The 22793 * system calls this object's {@link DragShadowBuilder#onProvideShadowMetrics(Point, Point)} 22794 * to get metrics for the drag shadow, and then calls the object's 22795 * {@link DragShadowBuilder#onDrawShadow(Canvas)} to draw the drag shadow itself. 22796 * <p> 22797 * Once the system has the drag shadow, it begins the drag and drop operation by sending 22798 * drag events to all the View objects in your application that are currently visible. It does 22799 * this either by calling the View object's drag listener (an implementation of 22800 * {@link android.view.View.OnDragListener#onDrag(View,DragEvent) onDrag()} or by calling the 22801 * View object's {@link android.view.View#onDragEvent(DragEvent) onDragEvent()} method. 22802 * Both are passed a {@link android.view.DragEvent} object that has a 22803 * {@link android.view.DragEvent#getAction()} value of 22804 * {@link android.view.DragEvent#ACTION_DRAG_STARTED}. 22805 * </p> 22806 * <p> 22807 * Your application can invoke {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, 22808 * int) startDragAndDrop()} on any attached View object. The View object does not need to be 22809 * the one used in {@link android.view.View.DragShadowBuilder}, nor does it need to be related 22810 * to the View the user selected for dragging. 22811 * </p> 22812 * @param data A {@link android.content.ClipData} object pointing to the data to be 22813 * transferred by the drag and drop operation. 22814 * @param shadowBuilder A {@link android.view.View.DragShadowBuilder} object for building the 22815 * drag shadow. 22816 * @param myLocalState An {@link java.lang.Object} containing local data about the drag and 22817 * drop operation. When dispatching drag events to views in the same activity this object 22818 * will be available through {@link android.view.DragEvent#getLocalState()}. Views in other 22819 * activities will not have access to this data ({@link android.view.DragEvent#getLocalState()} 22820 * will return null). 22821 * <p> 22822 * myLocalState is a lightweight mechanism for the sending information from the dragged View 22823 * to the target Views. For example, it can contain flags that differentiate between a 22824 * a copy operation and a move operation. 22825 * </p> 22826 * @param flags Flags that control the drag and drop operation. This can be set to 0 for no 22827 * flags, or any combination of the following: 22828 * <ul> 22829 * <li>{@link #DRAG_FLAG_GLOBAL}</li> 22830 * <li>{@link #DRAG_FLAG_GLOBAL_PERSISTABLE_URI_PERMISSION}</li> 22831 * <li>{@link #DRAG_FLAG_GLOBAL_PREFIX_URI_PERMISSION}</li> 22832 * <li>{@link #DRAG_FLAG_GLOBAL_URI_READ}</li> 22833 * <li>{@link #DRAG_FLAG_GLOBAL_URI_WRITE}</li> 22834 * <li>{@link #DRAG_FLAG_OPAQUE}</li> 22835 * </ul> 22836 * @return {@code true} if the method completes successfully, or 22837 * {@code false} if it fails anywhere. Returning {@code false} means the system was unable to 22838 * do a drag, and so no drag operation is in progress. 22839 */ 22840 public final boolean startDragAndDrop(ClipData data, DragShadowBuilder shadowBuilder, 22841 Object myLocalState, int flags) { 22842 if (ViewDebug.DEBUG_DRAG) { 22843 Log.d(VIEW_LOG_TAG, "startDragAndDrop: data=" + data + " flags=" + flags); 22844 } 22845 if (mAttachInfo == null) { 22846 Log.w(VIEW_LOG_TAG, "startDragAndDrop called on a detached view."); 22847 return false; 22848 } 22849 22850 if (data != null) { 22851 data.prepareToLeaveProcess((flags & View.DRAG_FLAG_GLOBAL) != 0); 22852 } 22853 22854 boolean okay = false; 22855 22856 Point shadowSize = new Point(); 22857 Point shadowTouchPoint = new Point(); 22858 shadowBuilder.onProvideShadowMetrics(shadowSize, shadowTouchPoint); 22859 22860 if ((shadowSize.x < 0) || (shadowSize.y < 0) || 22861 (shadowTouchPoint.x < 0) || (shadowTouchPoint.y < 0)) { 22862 throw new IllegalStateException("Drag shadow dimensions must not be negative"); 22863 } 22864 22865 if (ViewDebug.DEBUG_DRAG) { 22866 Log.d(VIEW_LOG_TAG, "drag shadow: width=" + shadowSize.x + " height=" + shadowSize.y 22867 + " shadowX=" + shadowTouchPoint.x + " shadowY=" + shadowTouchPoint.y); 22868 } 22869 if (mAttachInfo.mDragSurface != null) { 22870 mAttachInfo.mDragSurface.release(); 22871 } 22872 mAttachInfo.mDragSurface = new Surface(); 22873 try { 22874 mAttachInfo.mDragToken = mAttachInfo.mSession.prepareDrag(mAttachInfo.mWindow, 22875 flags, shadowSize.x, shadowSize.y, mAttachInfo.mDragSurface); 22876 if (ViewDebug.DEBUG_DRAG) Log.d(VIEW_LOG_TAG, "prepareDrag returned token=" 22877 + mAttachInfo.mDragToken + " surface=" + mAttachInfo.mDragSurface); 22878 if (mAttachInfo.mDragToken != null) { 22879 Canvas canvas = mAttachInfo.mDragSurface.lockCanvas(null); 22880 try { 22881 canvas.drawColor(0, PorterDuff.Mode.CLEAR); 22882 shadowBuilder.onDrawShadow(canvas); 22883 } finally { 22884 mAttachInfo.mDragSurface.unlockCanvasAndPost(canvas); 22885 } 22886 22887 final ViewRootImpl root = getViewRootImpl(); 22888 22889 // Cache the local state object for delivery with DragEvents 22890 root.setLocalDragState(myLocalState); 22891 22892 // repurpose 'shadowSize' for the last touch point 22893 root.getLastTouchPoint(shadowSize); 22894 22895 okay = mAttachInfo.mSession.performDrag(mAttachInfo.mWindow, mAttachInfo.mDragToken, 22896 root.getLastTouchSource(), shadowSize.x, shadowSize.y, 22897 shadowTouchPoint.x, shadowTouchPoint.y, data); 22898 if (ViewDebug.DEBUG_DRAG) Log.d(VIEW_LOG_TAG, "performDrag returned " + okay); 22899 } 22900 } catch (Exception e) { 22901 Log.e(VIEW_LOG_TAG, "Unable to initiate drag", e); 22902 mAttachInfo.mDragSurface.destroy(); 22903 mAttachInfo.mDragSurface = null; 22904 } 22905 22906 return okay; 22907 } 22908 22909 /** 22910 * Cancels an ongoing drag and drop operation. 22911 * <p> 22912 * A {@link android.view.DragEvent} object with 22913 * {@link android.view.DragEvent#getAction()} value of 22914 * {@link android.view.DragEvent#ACTION_DRAG_ENDED} and 22915 * {@link android.view.DragEvent#getResult()} value of {@code false} 22916 * will be sent to every 22917 * View that received {@link android.view.DragEvent#ACTION_DRAG_STARTED} 22918 * even if they are not currently visible. 22919 * </p> 22920 * <p> 22921 * This method can be called on any View in the same window as the View on which 22922 * {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, int) startDragAndDrop} 22923 * was called. 22924 * </p> 22925 */ 22926 public final void cancelDragAndDrop() { 22927 if (ViewDebug.DEBUG_DRAG) { 22928 Log.d(VIEW_LOG_TAG, "cancelDragAndDrop"); 22929 } 22930 if (mAttachInfo == null) { 22931 Log.w(VIEW_LOG_TAG, "cancelDragAndDrop called on a detached view."); 22932 return; 22933 } 22934 if (mAttachInfo.mDragToken != null) { 22935 try { 22936 mAttachInfo.mSession.cancelDragAndDrop(mAttachInfo.mDragToken); 22937 } catch (Exception e) { 22938 Log.e(VIEW_LOG_TAG, "Unable to cancel drag", e); 22939 } 22940 mAttachInfo.mDragToken = null; 22941 } else { 22942 Log.e(VIEW_LOG_TAG, "No active drag to cancel"); 22943 } 22944 } 22945 22946 /** 22947 * Updates the drag shadow for the ongoing drag and drop operation. 22948 * 22949 * @param shadowBuilder A {@link android.view.View.DragShadowBuilder} object for building the 22950 * new drag shadow. 22951 */ 22952 public final void updateDragShadow(DragShadowBuilder shadowBuilder) { 22953 if (ViewDebug.DEBUG_DRAG) { 22954 Log.d(VIEW_LOG_TAG, "updateDragShadow"); 22955 } 22956 if (mAttachInfo == null) { 22957 Log.w(VIEW_LOG_TAG, "updateDragShadow called on a detached view."); 22958 return; 22959 } 22960 if (mAttachInfo.mDragToken != null) { 22961 try { 22962 Canvas canvas = mAttachInfo.mDragSurface.lockCanvas(null); 22963 try { 22964 canvas.drawColor(0, PorterDuff.Mode.CLEAR); 22965 shadowBuilder.onDrawShadow(canvas); 22966 } finally { 22967 mAttachInfo.mDragSurface.unlockCanvasAndPost(canvas); 22968 } 22969 } catch (Exception e) { 22970 Log.e(VIEW_LOG_TAG, "Unable to update drag shadow", e); 22971 } 22972 } else { 22973 Log.e(VIEW_LOG_TAG, "No active drag"); 22974 } 22975 } 22976 22977 /** 22978 * Starts a move from {startX, startY}, the amount of the movement will be the offset 22979 * between {startX, startY} and the new cursor positon. 22980 * @param startX horizontal coordinate where the move started. 22981 * @param startY vertical coordinate where the move started. 22982 * @return whether moving was started successfully. 22983 * @hide 22984 */ 22985 public final boolean startMovingTask(float startX, float startY) { 22986 if (ViewDebug.DEBUG_POSITIONING) { 22987 Log.d(VIEW_LOG_TAG, "startMovingTask: {" + startX + "," + startY + "}"); 22988 } 22989 try { 22990 return mAttachInfo.mSession.startMovingTask(mAttachInfo.mWindow, startX, startY); 22991 } catch (RemoteException e) { 22992 Log.e(VIEW_LOG_TAG, "Unable to start moving", e); 22993 } 22994 return false; 22995 } 22996 22997 /** 22998 * Handles drag events sent by the system following a call to 22999 * {@link android.view.View#startDragAndDrop(ClipData,DragShadowBuilder,Object,int) 23000 * startDragAndDrop()}. 23001 *<p> 23002 * When the system calls this method, it passes a 23003 * {@link android.view.DragEvent} object. A call to 23004 * {@link android.view.DragEvent#getAction()} returns one of the action type constants defined 23005 * in DragEvent. The method uses these to determine what is happening in the drag and drop 23006 * operation. 23007 * @param event The {@link android.view.DragEvent} sent by the system. 23008 * The {@link android.view.DragEvent#getAction()} method returns an action type constant defined 23009 * in DragEvent, indicating the type of drag event represented by this object. 23010 * @return {@code true} if the method was successful, otherwise {@code false}. 23011 * <p> 23012 * The method should return {@code true} in response to an action type of 23013 * {@link android.view.DragEvent#ACTION_DRAG_STARTED} to receive drag events for the current 23014 * operation. 23015 * </p> 23016 * <p> 23017 * The method should also return {@code true} in response to an action type of 23018 * {@link android.view.DragEvent#ACTION_DROP} if it consumed the drop, or 23019 * {@code false} if it didn't. 23020 * </p> 23021 * <p> 23022 * For all other events, the return value is ignored. 23023 * </p> 23024 */ 23025 public boolean onDragEvent(DragEvent event) { 23026 return false; 23027 } 23028 23029 // Dispatches ACTION_DRAG_ENTERED and ACTION_DRAG_EXITED events for pre-Nougat apps. 23030 boolean dispatchDragEnterExitInPreN(DragEvent event) { 23031 return callDragEventHandler(event); 23032 } 23033 23034 /** 23035 * Detects if this View is enabled and has a drag event listener. 23036 * If both are true, then it calls the drag event listener with the 23037 * {@link android.view.DragEvent} it received. If the drag event listener returns 23038 * {@code true}, then dispatchDragEvent() returns {@code true}. 23039 * <p> 23040 * For all other cases, the method calls the 23041 * {@link android.view.View#onDragEvent(DragEvent) onDragEvent()} drag event handler 23042 * method and returns its result. 23043 * </p> 23044 * <p> 23045 * This ensures that a drag event is always consumed, even if the View does not have a drag 23046 * event listener. However, if the View has a listener and the listener returns true, then 23047 * onDragEvent() is not called. 23048 * </p> 23049 */ 23050 public boolean dispatchDragEvent(DragEvent event) { 23051 event.mEventHandlerWasCalled = true; 23052 if (event.mAction == DragEvent.ACTION_DRAG_LOCATION || 23053 event.mAction == DragEvent.ACTION_DROP) { 23054 // About to deliver an event with coordinates to this view. Notify that now this view 23055 // has drag focus. This will send exit/enter events as needed. 23056 getViewRootImpl().setDragFocus(this, event); 23057 } 23058 return callDragEventHandler(event); 23059 } 23060 23061 final boolean callDragEventHandler(DragEvent event) { 23062 final boolean result; 23063 23064 ListenerInfo li = mListenerInfo; 23065 //noinspection SimplifiableIfStatement 23066 if (li != null && li.mOnDragListener != null && (mViewFlags & ENABLED_MASK) == ENABLED 23067 && li.mOnDragListener.onDrag(this, event)) { 23068 result = true; 23069 } else { 23070 result = onDragEvent(event); 23071 } 23072 23073 switch (event.mAction) { 23074 case DragEvent.ACTION_DRAG_ENTERED: { 23075 mPrivateFlags2 |= View.PFLAG2_DRAG_HOVERED; 23076 refreshDrawableState(); 23077 } break; 23078 case DragEvent.ACTION_DRAG_EXITED: { 23079 mPrivateFlags2 &= ~View.PFLAG2_DRAG_HOVERED; 23080 refreshDrawableState(); 23081 } break; 23082 case DragEvent.ACTION_DRAG_ENDED: { 23083 mPrivateFlags2 &= ~View.DRAG_MASK; 23084 refreshDrawableState(); 23085 } break; 23086 } 23087 23088 return result; 23089 } 23090 23091 boolean canAcceptDrag() { 23092 return (mPrivateFlags2 & PFLAG2_DRAG_CAN_ACCEPT) != 0; 23093 } 23094 23095 /** 23096 * This needs to be a better API (NOT ON VIEW) before it is exposed. If 23097 * it is ever exposed at all. 23098 * @hide 23099 */ 23100 public void onCloseSystemDialogs(String reason) { 23101 } 23102 23103 /** 23104 * Given a Drawable whose bounds have been set to draw into this view, 23105 * update a Region being computed for 23106 * {@link #gatherTransparentRegion(android.graphics.Region)} so 23107 * that any non-transparent parts of the Drawable are removed from the 23108 * given transparent region. 23109 * 23110 * @param dr The Drawable whose transparency is to be applied to the region. 23111 * @param region A Region holding the current transparency information, 23112 * where any parts of the region that are set are considered to be 23113 * transparent. On return, this region will be modified to have the 23114 * transparency information reduced by the corresponding parts of the 23115 * Drawable that are not transparent. 23116 * {@hide} 23117 */ 23118 public void applyDrawableToTransparentRegion(Drawable dr, Region region) { 23119 if (DBG) { 23120 Log.i("View", "Getting transparent region for: " + this); 23121 } 23122 final Region r = dr.getTransparentRegion(); 23123 final Rect db = dr.getBounds(); 23124 final AttachInfo attachInfo = mAttachInfo; 23125 if (r != null && attachInfo != null) { 23126 final int w = getRight()-getLeft(); 23127 final int h = getBottom()-getTop(); 23128 if (db.left > 0) { 23129 //Log.i("VIEW", "Drawable left " + db.left + " > view 0"); 23130 r.op(0, 0, db.left, h, Region.Op.UNION); 23131 } 23132 if (db.right < w) { 23133 //Log.i("VIEW", "Drawable right " + db.right + " < view " + w); 23134 r.op(db.right, 0, w, h, Region.Op.UNION); 23135 } 23136 if (db.top > 0) { 23137 //Log.i("VIEW", "Drawable top " + db.top + " > view 0"); 23138 r.op(0, 0, w, db.top, Region.Op.UNION); 23139 } 23140 if (db.bottom < h) { 23141 //Log.i("VIEW", "Drawable bottom " + db.bottom + " < view " + h); 23142 r.op(0, db.bottom, w, h, Region.Op.UNION); 23143 } 23144 final int[] location = attachInfo.mTransparentLocation; 23145 getLocationInWindow(location); 23146 r.translate(location[0], location[1]); 23147 region.op(r, Region.Op.INTERSECT); 23148 } else { 23149 region.op(db, Region.Op.DIFFERENCE); 23150 } 23151 } 23152 23153 private void checkForLongClick(int delayOffset, float x, float y) { 23154 if ((mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE || (mViewFlags & TOOLTIP) == TOOLTIP) { 23155 mHasPerformedLongPress = false; 23156 23157 if (mPendingCheckForLongPress == null) { 23158 mPendingCheckForLongPress = new CheckForLongPress(); 23159 } 23160 mPendingCheckForLongPress.setAnchor(x, y); 23161 mPendingCheckForLongPress.rememberWindowAttachCount(); 23162 mPendingCheckForLongPress.rememberPressedState(); 23163 postDelayed(mPendingCheckForLongPress, 23164 ViewConfiguration.getLongPressTimeout() - delayOffset); 23165 } 23166 } 23167 23168 /** 23169 * Inflate a view from an XML resource. This convenience method wraps the {@link 23170 * LayoutInflater} class, which provides a full range of options for view inflation. 23171 * 23172 * @param context The Context object for your activity or application. 23173 * @param resource The resource ID to inflate 23174 * @param root A view group that will be the parent. Used to properly inflate the 23175 * layout_* parameters. 23176 * @see LayoutInflater 23177 */ 23178 public static View inflate(Context context, @LayoutRes int resource, ViewGroup root) { 23179 LayoutInflater factory = LayoutInflater.from(context); 23180 return factory.inflate(resource, root); 23181 } 23182 23183 /** 23184 * Scroll the view with standard behavior for scrolling beyond the normal 23185 * content boundaries. Views that call this method should override 23186 * {@link #onOverScrolled(int, int, boolean, boolean)} to respond to the 23187 * results of an over-scroll operation. 23188 * 23189 * Views can use this method to handle any touch or fling-based scrolling. 23190 * 23191 * @param deltaX Change in X in pixels 23192 * @param deltaY Change in Y in pixels 23193 * @param scrollX Current X scroll value in pixels before applying deltaX 23194 * @param scrollY Current Y scroll value in pixels before applying deltaY 23195 * @param scrollRangeX Maximum content scroll range along the X axis 23196 * @param scrollRangeY Maximum content scroll range along the Y axis 23197 * @param maxOverScrollX Number of pixels to overscroll by in either direction 23198 * along the X axis. 23199 * @param maxOverScrollY Number of pixels to overscroll by in either direction 23200 * along the Y axis. 23201 * @param isTouchEvent true if this scroll operation is the result of a touch event. 23202 * @return true if scrolling was clamped to an over-scroll boundary along either 23203 * axis, false otherwise. 23204 */ 23205 @SuppressWarnings({"UnusedParameters"}) 23206 protected boolean overScrollBy(int deltaX, int deltaY, 23207 int scrollX, int scrollY, 23208 int scrollRangeX, int scrollRangeY, 23209 int maxOverScrollX, int maxOverScrollY, 23210 boolean isTouchEvent) { 23211 final int overScrollMode = mOverScrollMode; 23212 final boolean canScrollHorizontal = 23213 computeHorizontalScrollRange() > computeHorizontalScrollExtent(); 23214 final boolean canScrollVertical = 23215 computeVerticalScrollRange() > computeVerticalScrollExtent(); 23216 final boolean overScrollHorizontal = overScrollMode == OVER_SCROLL_ALWAYS || 23217 (overScrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && canScrollHorizontal); 23218 final boolean overScrollVertical = overScrollMode == OVER_SCROLL_ALWAYS || 23219 (overScrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && canScrollVertical); 23220 23221 int newScrollX = scrollX + deltaX; 23222 if (!overScrollHorizontal) { 23223 maxOverScrollX = 0; 23224 } 23225 23226 int newScrollY = scrollY + deltaY; 23227 if (!overScrollVertical) { 23228 maxOverScrollY = 0; 23229 } 23230 23231 // Clamp values if at the limits and record 23232 final int left = -maxOverScrollX; 23233 final int right = maxOverScrollX + scrollRangeX; 23234 final int top = -maxOverScrollY; 23235 final int bottom = maxOverScrollY + scrollRangeY; 23236 23237 boolean clampedX = false; 23238 if (newScrollX > right) { 23239 newScrollX = right; 23240 clampedX = true; 23241 } else if (newScrollX < left) { 23242 newScrollX = left; 23243 clampedX = true; 23244 } 23245 23246 boolean clampedY = false; 23247 if (newScrollY > bottom) { 23248 newScrollY = bottom; 23249 clampedY = true; 23250 } else if (newScrollY < top) { 23251 newScrollY = top; 23252 clampedY = true; 23253 } 23254 23255 onOverScrolled(newScrollX, newScrollY, clampedX, clampedY); 23256 23257 return clampedX || clampedY; 23258 } 23259 23260 /** 23261 * Called by {@link #overScrollBy(int, int, int, int, int, int, int, int, boolean)} to 23262 * respond to the results of an over-scroll operation. 23263 * 23264 * @param scrollX New X scroll value in pixels 23265 * @param scrollY New Y scroll value in pixels 23266 * @param clampedX True if scrollX was clamped to an over-scroll boundary 23267 * @param clampedY True if scrollY was clamped to an over-scroll boundary 23268 */ 23269 protected void onOverScrolled(int scrollX, int scrollY, 23270 boolean clampedX, boolean clampedY) { 23271 // Intentionally empty. 23272 } 23273 23274 /** 23275 * Returns the over-scroll mode for this view. The result will be 23276 * one of {@link #OVER_SCROLL_ALWAYS} (default), {@link #OVER_SCROLL_IF_CONTENT_SCROLLS} 23277 * (allow over-scrolling only if the view content is larger than the container), 23278 * or {@link #OVER_SCROLL_NEVER}. 23279 * 23280 * @return This view's over-scroll mode. 23281 */ 23282 public int getOverScrollMode() { 23283 return mOverScrollMode; 23284 } 23285 23286 /** 23287 * Set the over-scroll mode for this view. Valid over-scroll modes are 23288 * {@link #OVER_SCROLL_ALWAYS} (default), {@link #OVER_SCROLL_IF_CONTENT_SCROLLS} 23289 * (allow over-scrolling only if the view content is larger than the container), 23290 * or {@link #OVER_SCROLL_NEVER}. 23291 * 23292 * Setting the over-scroll mode of a view will have an effect only if the 23293 * view is capable of scrolling. 23294 * 23295 * @param overScrollMode The new over-scroll mode for this view. 23296 */ 23297 public void setOverScrollMode(int overScrollMode) { 23298 if (overScrollMode != OVER_SCROLL_ALWAYS && 23299 overScrollMode != OVER_SCROLL_IF_CONTENT_SCROLLS && 23300 overScrollMode != OVER_SCROLL_NEVER) { 23301 throw new IllegalArgumentException("Invalid overscroll mode " + overScrollMode); 23302 } 23303 mOverScrollMode = overScrollMode; 23304 } 23305 23306 /** 23307 * Enable or disable nested scrolling for this view. 23308 * 23309 * <p>If this property is set to true the view will be permitted to initiate nested 23310 * scrolling operations with a compatible parent view in the current hierarchy. If this 23311 * view does not implement nested scrolling this will have no effect. Disabling nested scrolling 23312 * while a nested scroll is in progress has the effect of {@link #stopNestedScroll() stopping} 23313 * the nested scroll.</p> 23314 * 23315 * @param enabled true to enable nested scrolling, false to disable 23316 * 23317 * @see #isNestedScrollingEnabled() 23318 */ 23319 public void setNestedScrollingEnabled(boolean enabled) { 23320 if (enabled) { 23321 mPrivateFlags3 |= PFLAG3_NESTED_SCROLLING_ENABLED; 23322 } else { 23323 stopNestedScroll(); 23324 mPrivateFlags3 &= ~PFLAG3_NESTED_SCROLLING_ENABLED; 23325 } 23326 } 23327 23328 /** 23329 * Returns true if nested scrolling is enabled for this view. 23330 * 23331 * <p>If nested scrolling is enabled and this View class implementation supports it, 23332 * this view will act as a nested scrolling child view when applicable, forwarding data 23333 * about the scroll operation in progress to a compatible and cooperating nested scrolling 23334 * parent.</p> 23335 * 23336 * @return true if nested scrolling is enabled 23337 * 23338 * @see #setNestedScrollingEnabled(boolean) 23339 */ 23340 public boolean isNestedScrollingEnabled() { 23341 return (mPrivateFlags3 & PFLAG3_NESTED_SCROLLING_ENABLED) == 23342 PFLAG3_NESTED_SCROLLING_ENABLED; 23343 } 23344 23345 /** 23346 * Begin a nestable scroll operation along the given axes. 23347 * 23348 * <p>A view starting a nested scroll promises to abide by the following contract:</p> 23349 * 23350 * <p>The view will call startNestedScroll upon initiating a scroll operation. In the case 23351 * of a touch scroll this corresponds to the initial {@link MotionEvent#ACTION_DOWN}. 23352 * In the case of touch scrolling the nested scroll will be terminated automatically in 23353 * the same manner as {@link ViewParent#requestDisallowInterceptTouchEvent(boolean)}. 23354 * In the event of programmatic scrolling the caller must explicitly call 23355 * {@link #stopNestedScroll()} to indicate the end of the nested scroll.</p> 23356 * 23357 * <p>If <code>startNestedScroll</code> returns true, a cooperative parent was found. 23358 * If it returns false the caller may ignore the rest of this contract until the next scroll. 23359 * Calling startNestedScroll while a nested scroll is already in progress will return true.</p> 23360 * 23361 * <p>At each incremental step of the scroll the caller should invoke 23362 * {@link #dispatchNestedPreScroll(int, int, int[], int[]) dispatchNestedPreScroll} 23363 * once it has calculated the requested scrolling delta. If it returns true the nested scrolling 23364 * parent at least partially consumed the scroll and the caller should adjust the amount it 23365 * scrolls by.</p> 23366 * 23367 * <p>After applying the remainder of the scroll delta the caller should invoke 23368 * {@link #dispatchNestedScroll(int, int, int, int, int[]) dispatchNestedScroll}, passing 23369 * both the delta consumed and the delta unconsumed. A nested scrolling parent may treat 23370 * these values differently. See {@link ViewParent#onNestedScroll(View, int, int, int, int)}. 23371 * </p> 23372 * 23373 * @param axes Flags consisting of a combination of {@link #SCROLL_AXIS_HORIZONTAL} and/or 23374 * {@link #SCROLL_AXIS_VERTICAL}. 23375 * @return true if a cooperative parent was found and nested scrolling has been enabled for 23376 * the current gesture. 23377 * 23378 * @see #stopNestedScroll() 23379 * @see #dispatchNestedPreScroll(int, int, int[], int[]) 23380 * @see #dispatchNestedScroll(int, int, int, int, int[]) 23381 */ 23382 public boolean startNestedScroll(int axes) { 23383 if (hasNestedScrollingParent()) { 23384 // Already in progress 23385 return true; 23386 } 23387 if (isNestedScrollingEnabled()) { 23388 ViewParent p = getParent(); 23389 View child = this; 23390 while (p != null) { 23391 try { 23392 if (p.onStartNestedScroll(child, this, axes)) { 23393 mNestedScrollingParent = p; 23394 p.onNestedScrollAccepted(child, this, axes); 23395 return true; 23396 } 23397 } catch (AbstractMethodError e) { 23398 Log.e(VIEW_LOG_TAG, "ViewParent " + p + " does not implement interface " + 23399 "method onStartNestedScroll", e); 23400 // Allow the search upward to continue 23401 } 23402 if (p instanceof View) { 23403 child = (View) p; 23404 } 23405 p = p.getParent(); 23406 } 23407 } 23408 return false; 23409 } 23410 23411 /** 23412 * Stop a nested scroll in progress. 23413 * 23414 * <p>Calling this method when a nested scroll is not currently in progress is harmless.</p> 23415 * 23416 * @see #startNestedScroll(int) 23417 */ 23418 public void stopNestedScroll() { 23419 if (mNestedScrollingParent != null) { 23420 mNestedScrollingParent.onStopNestedScroll(this); 23421 mNestedScrollingParent = null; 23422 } 23423 } 23424 23425 /** 23426 * Returns true if this view has a nested scrolling parent. 23427 * 23428 * <p>The presence of a nested scrolling parent indicates that this view has initiated 23429 * a nested scroll and it was accepted by an ancestor view further up the view hierarchy.</p> 23430 * 23431 * @return whether this view has a nested scrolling parent 23432 */ 23433 public boolean hasNestedScrollingParent() { 23434 return mNestedScrollingParent != null; 23435 } 23436 23437 /** 23438 * Dispatch one step of a nested scroll in progress. 23439 * 23440 * <p>Implementations of views that support nested scrolling should call this to report 23441 * info about a scroll in progress to the current nested scrolling parent. If a nested scroll 23442 * is not currently in progress or nested scrolling is not 23443 * {@link #isNestedScrollingEnabled() enabled} for this view this method does nothing.</p> 23444 * 23445 * <p>Compatible View implementations should also call 23446 * {@link #dispatchNestedPreScroll(int, int, int[], int[]) dispatchNestedPreScroll} before 23447 * consuming a component of the scroll event themselves.</p> 23448 * 23449 * @param dxConsumed Horizontal distance in pixels consumed by this view during this scroll step 23450 * @param dyConsumed Vertical distance in pixels consumed by this view during this scroll step 23451 * @param dxUnconsumed Horizontal scroll distance in pixels not consumed by this view 23452 * @param dyUnconsumed Horizontal scroll distance in pixels not consumed by this view 23453 * @param offsetInWindow Optional. If not null, on return this will contain the offset 23454 * in local view coordinates of this view from before this operation 23455 * to after it completes. View implementations may use this to adjust 23456 * expected input coordinate tracking. 23457 * @return true if the event was dispatched, false if it could not be dispatched. 23458 * @see #dispatchNestedPreScroll(int, int, int[], int[]) 23459 */ 23460 public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed, 23461 int dxUnconsumed, int dyUnconsumed, @Nullable @Size(2) int[] offsetInWindow) { 23462 if (isNestedScrollingEnabled() && mNestedScrollingParent != null) { 23463 if (dxConsumed != 0 || dyConsumed != 0 || dxUnconsumed != 0 || dyUnconsumed != 0) { 23464 int startX = 0; 23465 int startY = 0; 23466 if (offsetInWindow != null) { 23467 getLocationInWindow(offsetInWindow); 23468 startX = offsetInWindow[0]; 23469 startY = offsetInWindow[1]; 23470 } 23471 23472 mNestedScrollingParent.onNestedScroll(this, dxConsumed, dyConsumed, 23473 dxUnconsumed, dyUnconsumed); 23474 23475 if (offsetInWindow != null) { 23476 getLocationInWindow(offsetInWindow); 23477 offsetInWindow[0] -= startX; 23478 offsetInWindow[1] -= startY; 23479 } 23480 return true; 23481 } else if (offsetInWindow != null) { 23482 // No motion, no dispatch. Keep offsetInWindow up to date. 23483 offsetInWindow[0] = 0; 23484 offsetInWindow[1] = 0; 23485 } 23486 } 23487 return false; 23488 } 23489 23490 /** 23491 * Dispatch one step of a nested scroll in progress before this view consumes any portion of it. 23492 * 23493 * <p>Nested pre-scroll events are to nested scroll events what touch intercept is to touch. 23494 * <code>dispatchNestedPreScroll</code> offers an opportunity for the parent view in a nested 23495 * scrolling operation to consume some or all of the scroll operation before the child view 23496 * consumes it.</p> 23497 * 23498 * @param dx Horizontal scroll distance in pixels 23499 * @param dy Vertical scroll distance in pixels 23500 * @param consumed Output. If not null, consumed[0] will contain the consumed component of dx 23501 * and consumed[1] the consumed dy. 23502 * @param offsetInWindow Optional. If not null, on return this will contain the offset 23503 * in local view coordinates of this view from before this operation 23504 * to after it completes. View implementations may use this to adjust 23505 * expected input coordinate tracking. 23506 * @return true if the parent consumed some or all of the scroll delta 23507 * @see #dispatchNestedScroll(int, int, int, int, int[]) 23508 */ 23509 public boolean dispatchNestedPreScroll(int dx, int dy, 23510 @Nullable @Size(2) int[] consumed, @Nullable @Size(2) int[] offsetInWindow) { 23511 if (isNestedScrollingEnabled() && mNestedScrollingParent != null) { 23512 if (dx != 0 || dy != 0) { 23513 int startX = 0; 23514 int startY = 0; 23515 if (offsetInWindow != null) { 23516 getLocationInWindow(offsetInWindow); 23517 startX = offsetInWindow[0]; 23518 startY = offsetInWindow[1]; 23519 } 23520 23521 if (consumed == null) { 23522 if (mTempNestedScrollConsumed == null) { 23523 mTempNestedScrollConsumed = new int[2]; 23524 } 23525 consumed = mTempNestedScrollConsumed; 23526 } 23527 consumed[0] = 0; 23528 consumed[1] = 0; 23529 mNestedScrollingParent.onNestedPreScroll(this, dx, dy, consumed); 23530 23531 if (offsetInWindow != null) { 23532 getLocationInWindow(offsetInWindow); 23533 offsetInWindow[0] -= startX; 23534 offsetInWindow[1] -= startY; 23535 } 23536 return consumed[0] != 0 || consumed[1] != 0; 23537 } else if (offsetInWindow != null) { 23538 offsetInWindow[0] = 0; 23539 offsetInWindow[1] = 0; 23540 } 23541 } 23542 return false; 23543 } 23544 23545 /** 23546 * Dispatch a fling to a nested scrolling parent. 23547 * 23548 * <p>This method should be used to indicate that a nested scrolling child has detected 23549 * suitable conditions for a fling. Generally this means that a touch scroll has ended with a 23550 * {@link VelocityTracker velocity} in the direction of scrolling that meets or exceeds 23551 * the {@link ViewConfiguration#getScaledMinimumFlingVelocity() minimum fling velocity} 23552 * along a scrollable axis.</p> 23553 * 23554 * <p>If a nested scrolling child view would normally fling but it is at the edge of 23555 * its own content, it can use this method to delegate the fling to its nested scrolling 23556 * parent instead. The parent may optionally consume the fling or observe a child fling.</p> 23557 * 23558 * @param velocityX Horizontal fling velocity in pixels per second 23559 * @param velocityY Vertical fling velocity in pixels per second 23560 * @param consumed true if the child consumed the fling, false otherwise 23561 * @return true if the nested scrolling parent consumed or otherwise reacted to the fling 23562 */ 23563 public boolean dispatchNestedFling(float velocityX, float velocityY, boolean consumed) { 23564 if (isNestedScrollingEnabled() && mNestedScrollingParent != null) { 23565 return mNestedScrollingParent.onNestedFling(this, velocityX, velocityY, consumed); 23566 } 23567 return false; 23568 } 23569 23570 /** 23571 * Dispatch a fling to a nested scrolling parent before it is processed by this view. 23572 * 23573 * <p>Nested pre-fling events are to nested fling events what touch intercept is to touch 23574 * and what nested pre-scroll is to nested scroll. <code>dispatchNestedPreFling</code> 23575 * offsets an opportunity for the parent view in a nested fling to fully consume the fling 23576 * before the child view consumes it. If this method returns <code>true</code>, a nested 23577 * parent view consumed the fling and this view should not scroll as a result.</p> 23578 * 23579 * <p>For a better user experience, only one view in a nested scrolling chain should consume 23580 * the fling at a time. If a parent view consumed the fling this method will return false. 23581 * Custom view implementations should account for this in two ways:</p> 23582 * 23583 * <ul> 23584 * <li>If a custom view is paged and needs to settle to a fixed page-point, do not 23585 * call <code>dispatchNestedPreFling</code>; consume the fling and settle to a valid 23586 * position regardless.</li> 23587 * <li>If a nested parent does consume the fling, this view should not scroll at all, 23588 * even to settle back to a valid idle position.</li> 23589 * </ul> 23590 * 23591 * <p>Views should also not offer fling velocities to nested parent views along an axis 23592 * where scrolling is not currently supported; a {@link android.widget.ScrollView ScrollView} 23593 * should not offer a horizontal fling velocity to its parents since scrolling along that 23594 * axis is not permitted and carrying velocity along that motion does not make sense.</p> 23595 * 23596 * @param velocityX Horizontal fling velocity in pixels per second 23597 * @param velocityY Vertical fling velocity in pixels per second 23598 * @return true if a nested scrolling parent consumed the fling 23599 */ 23600 public boolean dispatchNestedPreFling(float velocityX, float velocityY) { 23601 if (isNestedScrollingEnabled() && mNestedScrollingParent != null) { 23602 return mNestedScrollingParent.onNestedPreFling(this, velocityX, velocityY); 23603 } 23604 return false; 23605 } 23606 23607 /** 23608 * Gets a scale factor that determines the distance the view should scroll 23609 * vertically in response to {@link MotionEvent#ACTION_SCROLL}. 23610 * @return The vertical scroll scale factor. 23611 * @hide 23612 */ 23613 protected float getVerticalScrollFactor() { 23614 if (mVerticalScrollFactor == 0) { 23615 TypedValue outValue = new TypedValue(); 23616 if (!mContext.getTheme().resolveAttribute( 23617 com.android.internal.R.attr.listPreferredItemHeight, outValue, true)) { 23618 throw new IllegalStateException( 23619 "Expected theme to define listPreferredItemHeight."); 23620 } 23621 mVerticalScrollFactor = outValue.getDimension( 23622 mContext.getResources().getDisplayMetrics()); 23623 } 23624 return mVerticalScrollFactor; 23625 } 23626 23627 /** 23628 * Gets a scale factor that determines the distance the view should scroll 23629 * horizontally in response to {@link MotionEvent#ACTION_SCROLL}. 23630 * @return The horizontal scroll scale factor. 23631 * @hide 23632 */ 23633 protected float getHorizontalScrollFactor() { 23634 // TODO: Should use something else. 23635 return getVerticalScrollFactor(); 23636 } 23637 23638 /** 23639 * Return the value specifying the text direction or policy that was set with 23640 * {@link #setTextDirection(int)}. 23641 * 23642 * @return the defined text direction. It can be one of: 23643 * 23644 * {@link #TEXT_DIRECTION_INHERIT}, 23645 * {@link #TEXT_DIRECTION_FIRST_STRONG}, 23646 * {@link #TEXT_DIRECTION_ANY_RTL}, 23647 * {@link #TEXT_DIRECTION_LTR}, 23648 * {@link #TEXT_DIRECTION_RTL}, 23649 * {@link #TEXT_DIRECTION_LOCALE}, 23650 * {@link #TEXT_DIRECTION_FIRST_STRONG_LTR}, 23651 * {@link #TEXT_DIRECTION_FIRST_STRONG_RTL} 23652 * 23653 * @attr ref android.R.styleable#View_textDirection 23654 * 23655 * @hide 23656 */ 23657 @ViewDebug.ExportedProperty(category = "text", mapping = { 23658 @ViewDebug.IntToString(from = TEXT_DIRECTION_INHERIT, to = "INHERIT"), 23659 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG, to = "FIRST_STRONG"), 23660 @ViewDebug.IntToString(from = TEXT_DIRECTION_ANY_RTL, to = "ANY_RTL"), 23661 @ViewDebug.IntToString(from = TEXT_DIRECTION_LTR, to = "LTR"), 23662 @ViewDebug.IntToString(from = TEXT_DIRECTION_RTL, to = "RTL"), 23663 @ViewDebug.IntToString(from = TEXT_DIRECTION_LOCALE, to = "LOCALE"), 23664 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_LTR, to = "FIRST_STRONG_LTR"), 23665 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_RTL, to = "FIRST_STRONG_RTL") 23666 }) 23667 public int getRawTextDirection() { 23668 return (mPrivateFlags2 & PFLAG2_TEXT_DIRECTION_MASK) >> PFLAG2_TEXT_DIRECTION_MASK_SHIFT; 23669 } 23670 23671 /** 23672 * Set the text direction. 23673 * 23674 * @param textDirection the direction to set. Should be one of: 23675 * 23676 * {@link #TEXT_DIRECTION_INHERIT}, 23677 * {@link #TEXT_DIRECTION_FIRST_STRONG}, 23678 * {@link #TEXT_DIRECTION_ANY_RTL}, 23679 * {@link #TEXT_DIRECTION_LTR}, 23680 * {@link #TEXT_DIRECTION_RTL}, 23681 * {@link #TEXT_DIRECTION_LOCALE} 23682 * {@link #TEXT_DIRECTION_FIRST_STRONG_LTR}, 23683 * {@link #TEXT_DIRECTION_FIRST_STRONG_RTL}, 23684 * 23685 * Resolution will be done if the value is set to TEXT_DIRECTION_INHERIT. The resolution 23686 * proceeds up the parent chain of the view to get the value. If there is no parent, then it will 23687 * return the default {@link #TEXT_DIRECTION_FIRST_STRONG}. 23688 * 23689 * @attr ref android.R.styleable#View_textDirection 23690 */ 23691 public void setTextDirection(int textDirection) { 23692 if (getRawTextDirection() != textDirection) { 23693 // Reset the current text direction and the resolved one 23694 mPrivateFlags2 &= ~PFLAG2_TEXT_DIRECTION_MASK; 23695 resetResolvedTextDirection(); 23696 // Set the new text direction 23697 mPrivateFlags2 |= ((textDirection << PFLAG2_TEXT_DIRECTION_MASK_SHIFT) & PFLAG2_TEXT_DIRECTION_MASK); 23698 // Do resolution 23699 resolveTextDirection(); 23700 // Notify change 23701 onRtlPropertiesChanged(getLayoutDirection()); 23702 // Refresh 23703 requestLayout(); 23704 invalidate(true); 23705 } 23706 } 23707 23708 /** 23709 * Return the resolved text direction. 23710 * 23711 * @return the resolved text direction. Returns one of: 23712 * 23713 * {@link #TEXT_DIRECTION_FIRST_STRONG}, 23714 * {@link #TEXT_DIRECTION_ANY_RTL}, 23715 * {@link #TEXT_DIRECTION_LTR}, 23716 * {@link #TEXT_DIRECTION_RTL}, 23717 * {@link #TEXT_DIRECTION_LOCALE}, 23718 * {@link #TEXT_DIRECTION_FIRST_STRONG_LTR}, 23719 * {@link #TEXT_DIRECTION_FIRST_STRONG_RTL} 23720 * 23721 * @attr ref android.R.styleable#View_textDirection 23722 */ 23723 @ViewDebug.ExportedProperty(category = "text", mapping = { 23724 @ViewDebug.IntToString(from = TEXT_DIRECTION_INHERIT, to = "INHERIT"), 23725 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG, to = "FIRST_STRONG"), 23726 @ViewDebug.IntToString(from = TEXT_DIRECTION_ANY_RTL, to = "ANY_RTL"), 23727 @ViewDebug.IntToString(from = TEXT_DIRECTION_LTR, to = "LTR"), 23728 @ViewDebug.IntToString(from = TEXT_DIRECTION_RTL, to = "RTL"), 23729 @ViewDebug.IntToString(from = TEXT_DIRECTION_LOCALE, to = "LOCALE"), 23730 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_LTR, to = "FIRST_STRONG_LTR"), 23731 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_RTL, to = "FIRST_STRONG_RTL") 23732 }) 23733 public int getTextDirection() { 23734 return (mPrivateFlags2 & PFLAG2_TEXT_DIRECTION_RESOLVED_MASK) >> PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT; 23735 } 23736 23737 /** 23738 * Resolve the text direction. 23739 * 23740 * @return true if resolution has been done, false otherwise. 23741 * 23742 * @hide 23743 */ 23744 public boolean resolveTextDirection() { 23745 // Reset any previous text direction resolution 23746 mPrivateFlags2 &= ~(PFLAG2_TEXT_DIRECTION_RESOLVED | PFLAG2_TEXT_DIRECTION_RESOLVED_MASK); 23747 23748 if (hasRtlSupport()) { 23749 // Set resolved text direction flag depending on text direction flag 23750 final int textDirection = getRawTextDirection(); 23751 switch(textDirection) { 23752 case TEXT_DIRECTION_INHERIT: 23753 if (!canResolveTextDirection()) { 23754 // We cannot do the resolution if there is no parent, so use the default one 23755 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 23756 // Resolution will need to happen again later 23757 return false; 23758 } 23759 23760 // Parent has not yet resolved, so we still return the default 23761 try { 23762 if (!mParent.isTextDirectionResolved()) { 23763 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 23764 // Resolution will need to happen again later 23765 return false; 23766 } 23767 } catch (AbstractMethodError e) { 23768 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 23769 " does not fully implement ViewParent", e); 23770 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED | 23771 PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 23772 return true; 23773 } 23774 23775 // Set current resolved direction to the same value as the parent's one 23776 int parentResolvedDirection; 23777 try { 23778 parentResolvedDirection = mParent.getTextDirection(); 23779 } catch (AbstractMethodError e) { 23780 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 23781 " does not fully implement ViewParent", e); 23782 parentResolvedDirection = TEXT_DIRECTION_LTR; 23783 } 23784 switch (parentResolvedDirection) { 23785 case TEXT_DIRECTION_FIRST_STRONG: 23786 case TEXT_DIRECTION_ANY_RTL: 23787 case TEXT_DIRECTION_LTR: 23788 case TEXT_DIRECTION_RTL: 23789 case TEXT_DIRECTION_LOCALE: 23790 case TEXT_DIRECTION_FIRST_STRONG_LTR: 23791 case TEXT_DIRECTION_FIRST_STRONG_RTL: 23792 mPrivateFlags2 |= 23793 (parentResolvedDirection << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT); 23794 break; 23795 default: 23796 // Default resolved direction is "first strong" heuristic 23797 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 23798 } 23799 break; 23800 case TEXT_DIRECTION_FIRST_STRONG: 23801 case TEXT_DIRECTION_ANY_RTL: 23802 case TEXT_DIRECTION_LTR: 23803 case TEXT_DIRECTION_RTL: 23804 case TEXT_DIRECTION_LOCALE: 23805 case TEXT_DIRECTION_FIRST_STRONG_LTR: 23806 case TEXT_DIRECTION_FIRST_STRONG_RTL: 23807 // Resolved direction is the same as text direction 23808 mPrivateFlags2 |= (textDirection << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT); 23809 break; 23810 default: 23811 // Default resolved direction is "first strong" heuristic 23812 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 23813 } 23814 } else { 23815 // Default resolved direction is "first strong" heuristic 23816 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 23817 } 23818 23819 // Set to resolved 23820 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED; 23821 return true; 23822 } 23823 23824 /** 23825 * Check if text direction resolution can be done. 23826 * 23827 * @return true if text direction resolution can be done otherwise return false. 23828 */ 23829 public boolean canResolveTextDirection() { 23830 switch (getRawTextDirection()) { 23831 case TEXT_DIRECTION_INHERIT: 23832 if (mParent != null) { 23833 try { 23834 return mParent.canResolveTextDirection(); 23835 } catch (AbstractMethodError e) { 23836 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 23837 " does not fully implement ViewParent", e); 23838 } 23839 } 23840 return false; 23841 23842 default: 23843 return true; 23844 } 23845 } 23846 23847 /** 23848 * Reset resolved text direction. Text direction will be resolved during a call to 23849 * {@link #onMeasure(int, int)}. 23850 * 23851 * @hide 23852 */ 23853 public void resetResolvedTextDirection() { 23854 // Reset any previous text direction resolution 23855 mPrivateFlags2 &= ~(PFLAG2_TEXT_DIRECTION_RESOLVED | PFLAG2_TEXT_DIRECTION_RESOLVED_MASK); 23856 // Set to default value 23857 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 23858 } 23859 23860 /** 23861 * @return true if text direction is inherited. 23862 * 23863 * @hide 23864 */ 23865 public boolean isTextDirectionInherited() { 23866 return (getRawTextDirection() == TEXT_DIRECTION_INHERIT); 23867 } 23868 23869 /** 23870 * @return true if text direction is resolved. 23871 */ 23872 public boolean isTextDirectionResolved() { 23873 return (mPrivateFlags2 & PFLAG2_TEXT_DIRECTION_RESOLVED) == PFLAG2_TEXT_DIRECTION_RESOLVED; 23874 } 23875 23876 /** 23877 * Return the value specifying the text alignment or policy that was set with 23878 * {@link #setTextAlignment(int)}. 23879 * 23880 * @return the defined text alignment. It can be one of: 23881 * 23882 * {@link #TEXT_ALIGNMENT_INHERIT}, 23883 * {@link #TEXT_ALIGNMENT_GRAVITY}, 23884 * {@link #TEXT_ALIGNMENT_CENTER}, 23885 * {@link #TEXT_ALIGNMENT_TEXT_START}, 23886 * {@link #TEXT_ALIGNMENT_TEXT_END}, 23887 * {@link #TEXT_ALIGNMENT_VIEW_START}, 23888 * {@link #TEXT_ALIGNMENT_VIEW_END} 23889 * 23890 * @attr ref android.R.styleable#View_textAlignment 23891 * 23892 * @hide 23893 */ 23894 @ViewDebug.ExportedProperty(category = "text", mapping = { 23895 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_INHERIT, to = "INHERIT"), 23896 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_GRAVITY, to = "GRAVITY"), 23897 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_TEXT_START, to = "TEXT_START"), 23898 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_TEXT_END, to = "TEXT_END"), 23899 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_CENTER, to = "CENTER"), 23900 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_START, to = "VIEW_START"), 23901 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_END, to = "VIEW_END") 23902 }) 23903 @TextAlignment 23904 public int getRawTextAlignment() { 23905 return (mPrivateFlags2 & PFLAG2_TEXT_ALIGNMENT_MASK) >> PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT; 23906 } 23907 23908 /** 23909 * Set the text alignment. 23910 * 23911 * @param textAlignment The text alignment to set. Should be one of 23912 * 23913 * {@link #TEXT_ALIGNMENT_INHERIT}, 23914 * {@link #TEXT_ALIGNMENT_GRAVITY}, 23915 * {@link #TEXT_ALIGNMENT_CENTER}, 23916 * {@link #TEXT_ALIGNMENT_TEXT_START}, 23917 * {@link #TEXT_ALIGNMENT_TEXT_END}, 23918 * {@link #TEXT_ALIGNMENT_VIEW_START}, 23919 * {@link #TEXT_ALIGNMENT_VIEW_END} 23920 * 23921 * Resolution will be done if the value is set to TEXT_ALIGNMENT_INHERIT. The resolution 23922 * proceeds up the parent chain of the view to get the value. If there is no parent, then it 23923 * will return the default {@link #TEXT_ALIGNMENT_GRAVITY}. 23924 * 23925 * @attr ref android.R.styleable#View_textAlignment 23926 */ 23927 public void setTextAlignment(@TextAlignment int textAlignment) { 23928 if (textAlignment != getRawTextAlignment()) { 23929 // Reset the current and resolved text alignment 23930 mPrivateFlags2 &= ~PFLAG2_TEXT_ALIGNMENT_MASK; 23931 resetResolvedTextAlignment(); 23932 // Set the new text alignment 23933 mPrivateFlags2 |= 23934 ((textAlignment << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT) & PFLAG2_TEXT_ALIGNMENT_MASK); 23935 // Do resolution 23936 resolveTextAlignment(); 23937 // Notify change 23938 onRtlPropertiesChanged(getLayoutDirection()); 23939 // Refresh 23940 requestLayout(); 23941 invalidate(true); 23942 } 23943 } 23944 23945 /** 23946 * Return the resolved text alignment. 23947 * 23948 * @return the resolved text alignment. Returns one of: 23949 * 23950 * {@link #TEXT_ALIGNMENT_GRAVITY}, 23951 * {@link #TEXT_ALIGNMENT_CENTER}, 23952 * {@link #TEXT_ALIGNMENT_TEXT_START}, 23953 * {@link #TEXT_ALIGNMENT_TEXT_END}, 23954 * {@link #TEXT_ALIGNMENT_VIEW_START}, 23955 * {@link #TEXT_ALIGNMENT_VIEW_END} 23956 * 23957 * @attr ref android.R.styleable#View_textAlignment 23958 */ 23959 @ViewDebug.ExportedProperty(category = "text", mapping = { 23960 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_INHERIT, to = "INHERIT"), 23961 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_GRAVITY, to = "GRAVITY"), 23962 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_TEXT_START, to = "TEXT_START"), 23963 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_TEXT_END, to = "TEXT_END"), 23964 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_CENTER, to = "CENTER"), 23965 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_START, to = "VIEW_START"), 23966 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_END, to = "VIEW_END") 23967 }) 23968 @TextAlignment 23969 public int getTextAlignment() { 23970 return (mPrivateFlags2 & PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK) >> 23971 PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT; 23972 } 23973 23974 /** 23975 * Resolve the text alignment. 23976 * 23977 * @return true if resolution has been done, false otherwise. 23978 * 23979 * @hide 23980 */ 23981 public boolean resolveTextAlignment() { 23982 // Reset any previous text alignment resolution 23983 mPrivateFlags2 &= ~(PFLAG2_TEXT_ALIGNMENT_RESOLVED | PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK); 23984 23985 if (hasRtlSupport()) { 23986 // Set resolved text alignment flag depending on text alignment flag 23987 final int textAlignment = getRawTextAlignment(); 23988 switch (textAlignment) { 23989 case TEXT_ALIGNMENT_INHERIT: 23990 // Check if we can resolve the text alignment 23991 if (!canResolveTextAlignment()) { 23992 // We cannot do the resolution if there is no parent so use the default 23993 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 23994 // Resolution will need to happen again later 23995 return false; 23996 } 23997 23998 // Parent has not yet resolved, so we still return the default 23999 try { 24000 if (!mParent.isTextAlignmentResolved()) { 24001 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 24002 // Resolution will need to happen again later 24003 return false; 24004 } 24005 } catch (AbstractMethodError e) { 24006 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 24007 " does not fully implement ViewParent", e); 24008 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED | 24009 PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 24010 return true; 24011 } 24012 24013 int parentResolvedTextAlignment; 24014 try { 24015 parentResolvedTextAlignment = mParent.getTextAlignment(); 24016 } catch (AbstractMethodError e) { 24017 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 24018 " does not fully implement ViewParent", e); 24019 parentResolvedTextAlignment = TEXT_ALIGNMENT_GRAVITY; 24020 } 24021 switch (parentResolvedTextAlignment) { 24022 case TEXT_ALIGNMENT_GRAVITY: 24023 case TEXT_ALIGNMENT_TEXT_START: 24024 case TEXT_ALIGNMENT_TEXT_END: 24025 case TEXT_ALIGNMENT_CENTER: 24026 case TEXT_ALIGNMENT_VIEW_START: 24027 case TEXT_ALIGNMENT_VIEW_END: 24028 // Resolved text alignment is the same as the parent resolved 24029 // text alignment 24030 mPrivateFlags2 |= 24031 (parentResolvedTextAlignment << PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT); 24032 break; 24033 default: 24034 // Use default resolved text alignment 24035 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 24036 } 24037 break; 24038 case TEXT_ALIGNMENT_GRAVITY: 24039 case TEXT_ALIGNMENT_TEXT_START: 24040 case TEXT_ALIGNMENT_TEXT_END: 24041 case TEXT_ALIGNMENT_CENTER: 24042 case TEXT_ALIGNMENT_VIEW_START: 24043 case TEXT_ALIGNMENT_VIEW_END: 24044 // Resolved text alignment is the same as text alignment 24045 mPrivateFlags2 |= (textAlignment << PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT); 24046 break; 24047 default: 24048 // Use default resolved text alignment 24049 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 24050 } 24051 } else { 24052 // Use default resolved text alignment 24053 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 24054 } 24055 24056 // Set the resolved 24057 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED; 24058 return true; 24059 } 24060 24061 /** 24062 * Check if text alignment resolution can be done. 24063 * 24064 * @return true if text alignment resolution can be done otherwise return false. 24065 */ 24066 public boolean canResolveTextAlignment() { 24067 switch (getRawTextAlignment()) { 24068 case TEXT_DIRECTION_INHERIT: 24069 if (mParent != null) { 24070 try { 24071 return mParent.canResolveTextAlignment(); 24072 } catch (AbstractMethodError e) { 24073 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 24074 " does not fully implement ViewParent", e); 24075 } 24076 } 24077 return false; 24078 24079 default: 24080 return true; 24081 } 24082 } 24083 24084 /** 24085 * Reset resolved text alignment. Text alignment will be resolved during a call to 24086 * {@link #onMeasure(int, int)}. 24087 * 24088 * @hide 24089 */ 24090 public void resetResolvedTextAlignment() { 24091 // Reset any previous text alignment resolution 24092 mPrivateFlags2 &= ~(PFLAG2_TEXT_ALIGNMENT_RESOLVED | PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK); 24093 // Set to default 24094 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 24095 } 24096 24097 /** 24098 * @return true if text alignment is inherited. 24099 * 24100 * @hide 24101 */ 24102 public boolean isTextAlignmentInherited() { 24103 return (getRawTextAlignment() == TEXT_ALIGNMENT_INHERIT); 24104 } 24105 24106 /** 24107 * @return true if text alignment is resolved. 24108 */ 24109 public boolean isTextAlignmentResolved() { 24110 return (mPrivateFlags2 & PFLAG2_TEXT_ALIGNMENT_RESOLVED) == PFLAG2_TEXT_ALIGNMENT_RESOLVED; 24111 } 24112 24113 /** 24114 * Generate a value suitable for use in {@link #setId(int)}. 24115 * This value will not collide with ID values generated at build time by aapt for R.id. 24116 * 24117 * @return a generated ID value 24118 */ 24119 public static int generateViewId() { 24120 for (;;) { 24121 final int result = sNextGeneratedId.get(); 24122 // aapt-generated IDs have the high byte nonzero; clamp to the range under that. 24123 int newValue = result + 1; 24124 if (newValue > 0x00FFFFFF) newValue = 1; // Roll over to 1, not 0. 24125 if (sNextGeneratedId.compareAndSet(result, newValue)) { 24126 return result; 24127 } 24128 } 24129 } 24130 24131 private static boolean isViewIdGenerated(int id) { 24132 return (id & 0xFF000000) == 0 && (id & 0x00FFFFFF) != 0; 24133 } 24134 24135 /** 24136 * Gets the Views in the hierarchy affected by entering and exiting Activity Scene transitions. 24137 * @param transitioningViews This View will be added to transitioningViews if it is VISIBLE and 24138 * a normal View or a ViewGroup with 24139 * {@link android.view.ViewGroup#isTransitionGroup()} true. 24140 * @hide 24141 */ 24142 public void captureTransitioningViews(List<View> transitioningViews) { 24143 if (getVisibility() == View.VISIBLE) { 24144 transitioningViews.add(this); 24145 } 24146 } 24147 24148 /** 24149 * Adds all Views that have {@link #getTransitionName()} non-null to namedElements. 24150 * @param namedElements Will contain all Views in the hierarchy having a transitionName. 24151 * @hide 24152 */ 24153 public void findNamedViews(Map<String, View> namedElements) { 24154 if (getVisibility() == VISIBLE || mGhostView != null) { 24155 String transitionName = getTransitionName(); 24156 if (transitionName != null) { 24157 namedElements.put(transitionName, this); 24158 } 24159 } 24160 } 24161 24162 /** 24163 * Returns the pointer icon for the motion event, or null if it doesn't specify the icon. 24164 * The default implementation does not care the location or event types, but some subclasses 24165 * may use it (such as WebViews). 24166 * @param event The MotionEvent from a mouse 24167 * @param pointerIndex The index of the pointer for which to retrieve the {@link PointerIcon}. 24168 * This will be between 0 and {@link MotionEvent#getPointerCount()}. 24169 * @see PointerIcon 24170 */ 24171 public PointerIcon onResolvePointerIcon(MotionEvent event, int pointerIndex) { 24172 final float x = event.getX(pointerIndex); 24173 final float y = event.getY(pointerIndex); 24174 if (isDraggingScrollBar() || isOnScrollbarThumb(x, y)) { 24175 return PointerIcon.getSystemIcon(mContext, PointerIcon.TYPE_ARROW); 24176 } 24177 return mPointerIcon; 24178 } 24179 24180 /** 24181 * Set the pointer icon for the current view. 24182 * Passing {@code null} will restore the pointer icon to its default value. 24183 * @param pointerIcon A PointerIcon instance which will be shown when the mouse hovers. 24184 */ 24185 public void setPointerIcon(PointerIcon pointerIcon) { 24186 mPointerIcon = pointerIcon; 24187 if (mAttachInfo == null || mAttachInfo.mHandlingPointerEvent) { 24188 return; 24189 } 24190 try { 24191 mAttachInfo.mSession.updatePointerIcon(mAttachInfo.mWindow); 24192 } catch (RemoteException e) { 24193 } 24194 } 24195 24196 /** 24197 * Gets the pointer icon for the current view. 24198 */ 24199 public PointerIcon getPointerIcon() { 24200 return mPointerIcon; 24201 } 24202 24203 /** 24204 * Checks pointer capture status. 24205 * 24206 * @return true if the view has pointer capture. 24207 * @see #requestPointerCapture() 24208 * @see #hasPointerCapture() 24209 */ 24210 public boolean hasPointerCapture() { 24211 final ViewRootImpl viewRootImpl = getViewRootImpl(); 24212 if (viewRootImpl == null) { 24213 return false; 24214 } 24215 return viewRootImpl.hasPointerCapture(); 24216 } 24217 24218 /** 24219 * Requests pointer capture mode. 24220 * <p> 24221 * When the window has pointer capture, the mouse pointer icon will disappear and will not 24222 * change its position. Further mouse will be dispatched with the source 24223 * {@link InputDevice#SOURCE_MOUSE_RELATIVE}, and relative position changes will be available 24224 * through {@link MotionEvent#getX} and {@link MotionEvent#getY}. Non-mouse events 24225 * (touchscreens, or stylus) will not be affected. 24226 * <p> 24227 * If the window already has pointer capture, this call does nothing. 24228 * <p> 24229 * The capture may be released through {@link #releasePointerCapture()}, or will be lost 24230 * automatically when the window loses focus. 24231 * 24232 * @see #releasePointerCapture() 24233 * @see #hasPointerCapture() 24234 */ 24235 public void requestPointerCapture() { 24236 final ViewRootImpl viewRootImpl = getViewRootImpl(); 24237 if (viewRootImpl != null) { 24238 viewRootImpl.requestPointerCapture(true); 24239 } 24240 } 24241 24242 24243 /** 24244 * Releases the pointer capture. 24245 * <p> 24246 * If the window does not have pointer capture, this call will do nothing. 24247 * @see #requestPointerCapture() 24248 * @see #hasPointerCapture() 24249 */ 24250 public void releasePointerCapture() { 24251 final ViewRootImpl viewRootImpl = getViewRootImpl(); 24252 if (viewRootImpl != null) { 24253 viewRootImpl.requestPointerCapture(false); 24254 } 24255 } 24256 24257 /** 24258 * Called when the window has just acquired or lost pointer capture. 24259 * 24260 * @param hasCapture True if the view now has pointerCapture, false otherwise. 24261 */ 24262 @CallSuper 24263 public void onPointerCaptureChange(boolean hasCapture) { 24264 } 24265 24266 /** 24267 * @see #onPointerCaptureChange 24268 */ 24269 public void dispatchPointerCaptureChanged(boolean hasCapture) { 24270 onPointerCaptureChange(hasCapture); 24271 } 24272 24273 /** 24274 * Implement this method to handle captured pointer events 24275 * 24276 * @param event The captured pointer event. 24277 * @return True if the event was handled, false otherwise. 24278 * @see #requestPointerCapture() 24279 */ 24280 public boolean onCapturedPointerEvent(MotionEvent event) { 24281 return false; 24282 } 24283 24284 /** 24285 * Interface definition for a callback to be invoked when a captured pointer event 24286 * is being dispatched this view. The callback will be invoked before the event is 24287 * given to the view. 24288 */ 24289 public interface OnCapturedPointerListener { 24290 /** 24291 * Called when a captured pointer event is dispatched to a view. 24292 * @param view The view this event has been dispatched to. 24293 * @param event The captured event. 24294 * @return True if the listener has consumed the event, false otherwise. 24295 */ 24296 boolean onCapturedPointer(View view, MotionEvent event); 24297 } 24298 24299 /** 24300 * Set a listener to receive callbacks when the pointer capture state of a view changes. 24301 * @param l The {@link OnCapturedPointerListener} to receive callbacks. 24302 */ 24303 public void setOnCapturedPointerListener(OnCapturedPointerListener l) { 24304 getListenerInfo().mOnCapturedPointerListener = l; 24305 } 24306 24307 // Properties 24308 // 24309 /** 24310 * A Property wrapper around the <code>alpha</code> functionality handled by the 24311 * {@link View#setAlpha(float)} and {@link View#getAlpha()} methods. 24312 */ 24313 public static final Property<View, Float> ALPHA = new FloatProperty<View>("alpha") { 24314 @Override 24315 public void setValue(View object, float value) { 24316 object.setAlpha(value); 24317 } 24318 24319 @Override 24320 public Float get(View object) { 24321 return object.getAlpha(); 24322 } 24323 }; 24324 24325 /** 24326 * A Property wrapper around the <code>translationX</code> functionality handled by the 24327 * {@link View#setTranslationX(float)} and {@link View#getTranslationX()} methods. 24328 */ 24329 public static final Property<View, Float> TRANSLATION_X = new FloatProperty<View>("translationX") { 24330 @Override 24331 public void setValue(View object, float value) { 24332 object.setTranslationX(value); 24333 } 24334 24335 @Override 24336 public Float get(View object) { 24337 return object.getTranslationX(); 24338 } 24339 }; 24340 24341 /** 24342 * A Property wrapper around the <code>translationY</code> functionality handled by the 24343 * {@link View#setTranslationY(float)} and {@link View#getTranslationY()} methods. 24344 */ 24345 public static final Property<View, Float> TRANSLATION_Y = new FloatProperty<View>("translationY") { 24346 @Override 24347 public void setValue(View object, float value) { 24348 object.setTranslationY(value); 24349 } 24350 24351 @Override 24352 public Float get(View object) { 24353 return object.getTranslationY(); 24354 } 24355 }; 24356 24357 /** 24358 * A Property wrapper around the <code>translationZ</code> functionality handled by the 24359 * {@link View#setTranslationZ(float)} and {@link View#getTranslationZ()} methods. 24360 */ 24361 public static final Property<View, Float> TRANSLATION_Z = new FloatProperty<View>("translationZ") { 24362 @Override 24363 public void setValue(View object, float value) { 24364 object.setTranslationZ(value); 24365 } 24366 24367 @Override 24368 public Float get(View object) { 24369 return object.getTranslationZ(); 24370 } 24371 }; 24372 24373 /** 24374 * A Property wrapper around the <code>x</code> functionality handled by the 24375 * {@link View#setX(float)} and {@link View#getX()} methods. 24376 */ 24377 public static final Property<View, Float> X = new FloatProperty<View>("x") { 24378 @Override 24379 public void setValue(View object, float value) { 24380 object.setX(value); 24381 } 24382 24383 @Override 24384 public Float get(View object) { 24385 return object.getX(); 24386 } 24387 }; 24388 24389 /** 24390 * A Property wrapper around the <code>y</code> functionality handled by the 24391 * {@link View#setY(float)} and {@link View#getY()} methods. 24392 */ 24393 public static final Property<View, Float> Y = new FloatProperty<View>("y") { 24394 @Override 24395 public void setValue(View object, float value) { 24396 object.setY(value); 24397 } 24398 24399 @Override 24400 public Float get(View object) { 24401 return object.getY(); 24402 } 24403 }; 24404 24405 /** 24406 * A Property wrapper around the <code>z</code> functionality handled by the 24407 * {@link View#setZ(float)} and {@link View#getZ()} methods. 24408 */ 24409 public static final Property<View, Float> Z = new FloatProperty<View>("z") { 24410 @Override 24411 public void setValue(View object, float value) { 24412 object.setZ(value); 24413 } 24414 24415 @Override 24416 public Float get(View object) { 24417 return object.getZ(); 24418 } 24419 }; 24420 24421 /** 24422 * A Property wrapper around the <code>rotation</code> functionality handled by the 24423 * {@link View#setRotation(float)} and {@link View#getRotation()} methods. 24424 */ 24425 public static final Property<View, Float> ROTATION = new FloatProperty<View>("rotation") { 24426 @Override 24427 public void setValue(View object, float value) { 24428 object.setRotation(value); 24429 } 24430 24431 @Override 24432 public Float get(View object) { 24433 return object.getRotation(); 24434 } 24435 }; 24436 24437 /** 24438 * A Property wrapper around the <code>rotationX</code> functionality handled by the 24439 * {@link View#setRotationX(float)} and {@link View#getRotationX()} methods. 24440 */ 24441 public static final Property<View, Float> ROTATION_X = new FloatProperty<View>("rotationX") { 24442 @Override 24443 public void setValue(View object, float value) { 24444 object.setRotationX(value); 24445 } 24446 24447 @Override 24448 public Float get(View object) { 24449 return object.getRotationX(); 24450 } 24451 }; 24452 24453 /** 24454 * A Property wrapper around the <code>rotationY</code> functionality handled by the 24455 * {@link View#setRotationY(float)} and {@link View#getRotationY()} methods. 24456 */ 24457 public static final Property<View, Float> ROTATION_Y = new FloatProperty<View>("rotationY") { 24458 @Override 24459 public void setValue(View object, float value) { 24460 object.setRotationY(value); 24461 } 24462 24463 @Override 24464 public Float get(View object) { 24465 return object.getRotationY(); 24466 } 24467 }; 24468 24469 /** 24470 * A Property wrapper around the <code>scaleX</code> functionality handled by the 24471 * {@link View#setScaleX(float)} and {@link View#getScaleX()} methods. 24472 */ 24473 public static final Property<View, Float> SCALE_X = new FloatProperty<View>("scaleX") { 24474 @Override 24475 public void setValue(View object, float value) { 24476 object.setScaleX(value); 24477 } 24478 24479 @Override 24480 public Float get(View object) { 24481 return object.getScaleX(); 24482 } 24483 }; 24484 24485 /** 24486 * A Property wrapper around the <code>scaleY</code> functionality handled by the 24487 * {@link View#setScaleY(float)} and {@link View#getScaleY()} methods. 24488 */ 24489 public static final Property<View, Float> SCALE_Y = new FloatProperty<View>("scaleY") { 24490 @Override 24491 public void setValue(View object, float value) { 24492 object.setScaleY(value); 24493 } 24494 24495 @Override 24496 public Float get(View object) { 24497 return object.getScaleY(); 24498 } 24499 }; 24500 24501 /** 24502 * A MeasureSpec encapsulates the layout requirements passed from parent to child. 24503 * Each MeasureSpec represents a requirement for either the width or the height. 24504 * A MeasureSpec is comprised of a size and a mode. There are three possible 24505 * modes: 24506 * <dl> 24507 * <dt>UNSPECIFIED</dt> 24508 * <dd> 24509 * The parent has not imposed any constraint on the child. It can be whatever size 24510 * it wants. 24511 * </dd> 24512 * 24513 * <dt>EXACTLY</dt> 24514 * <dd> 24515 * The parent has determined an exact size for the child. The child is going to be 24516 * given those bounds regardless of how big it wants to be. 24517 * </dd> 24518 * 24519 * <dt>AT_MOST</dt> 24520 * <dd> 24521 * The child can be as large as it wants up to the specified size. 24522 * </dd> 24523 * </dl> 24524 * 24525 * MeasureSpecs are implemented as ints to reduce object allocation. This class 24526 * is provided to pack and unpack the <size, mode> tuple into the int. 24527 */ 24528 public static class MeasureSpec { 24529 private static final int MODE_SHIFT = 30; 24530 private static final int MODE_MASK = 0x3 << MODE_SHIFT; 24531 24532 /** @hide */ 24533 @IntDef({UNSPECIFIED, EXACTLY, AT_MOST}) 24534 @Retention(RetentionPolicy.SOURCE) 24535 public @interface MeasureSpecMode {} 24536 24537 /** 24538 * Measure specification mode: The parent has not imposed any constraint 24539 * on the child. It can be whatever size it wants. 24540 */ 24541 public static final int UNSPECIFIED = 0 << MODE_SHIFT; 24542 24543 /** 24544 * Measure specification mode: The parent has determined an exact size 24545 * for the child. The child is going to be given those bounds regardless 24546 * of how big it wants to be. 24547 */ 24548 public static final int EXACTLY = 1 << MODE_SHIFT; 24549 24550 /** 24551 * Measure specification mode: The child can be as large as it wants up 24552 * to the specified size. 24553 */ 24554 public static final int AT_MOST = 2 << MODE_SHIFT; 24555 24556 /** 24557 * Creates a measure specification based on the supplied size and mode. 24558 * 24559 * The mode must always be one of the following: 24560 * <ul> 24561 * <li>{@link android.view.View.MeasureSpec#UNSPECIFIED}</li> 24562 * <li>{@link android.view.View.MeasureSpec#EXACTLY}</li> 24563 * <li>{@link android.view.View.MeasureSpec#AT_MOST}</li> 24564 * </ul> 24565 * 24566 * <p><strong>Note:</strong> On API level 17 and lower, makeMeasureSpec's 24567 * implementation was such that the order of arguments did not matter 24568 * and overflow in either value could impact the resulting MeasureSpec. 24569 * {@link android.widget.RelativeLayout} was affected by this bug. 24570 * Apps targeting API levels greater than 17 will get the fixed, more strict 24571 * behavior.</p> 24572 * 24573 * @param size the size of the measure specification 24574 * @param mode the mode of the measure specification 24575 * @return the measure specification based on size and mode 24576 */ 24577 public static int makeMeasureSpec(@IntRange(from = 0, to = (1 << MeasureSpec.MODE_SHIFT) - 1) int size, 24578 @MeasureSpecMode int mode) { 24579 if (sUseBrokenMakeMeasureSpec) { 24580 return size + mode; 24581 } else { 24582 return (size & ~MODE_MASK) | (mode & MODE_MASK); 24583 } 24584 } 24585 24586 /** 24587 * Like {@link #makeMeasureSpec(int, int)}, but any spec with a mode of UNSPECIFIED 24588 * will automatically get a size of 0. Older apps expect this. 24589 * 24590 * @hide internal use only for compatibility with system widgets and older apps 24591 */ 24592 public static int makeSafeMeasureSpec(int size, int mode) { 24593 if (sUseZeroUnspecifiedMeasureSpec && mode == UNSPECIFIED) { 24594 return 0; 24595 } 24596 return makeMeasureSpec(size, mode); 24597 } 24598 24599 /** 24600 * Extracts the mode from the supplied measure specification. 24601 * 24602 * @param measureSpec the measure specification to extract the mode from 24603 * @return {@link android.view.View.MeasureSpec#UNSPECIFIED}, 24604 * {@link android.view.View.MeasureSpec#AT_MOST} or 24605 * {@link android.view.View.MeasureSpec#EXACTLY} 24606 */ 24607 @MeasureSpecMode 24608 public static int getMode(int measureSpec) { 24609 //noinspection ResourceType 24610 return (measureSpec & MODE_MASK); 24611 } 24612 24613 /** 24614 * Extracts the size from the supplied measure specification. 24615 * 24616 * @param measureSpec the measure specification to extract the size from 24617 * @return the size in pixels defined in the supplied measure specification 24618 */ 24619 public static int getSize(int measureSpec) { 24620 return (measureSpec & ~MODE_MASK); 24621 } 24622 24623 static int adjust(int measureSpec, int delta) { 24624 final int mode = getMode(measureSpec); 24625 int size = getSize(measureSpec); 24626 if (mode == UNSPECIFIED) { 24627 // No need to adjust size for UNSPECIFIED mode. 24628 return makeMeasureSpec(size, UNSPECIFIED); 24629 } 24630 size += delta; 24631 if (size < 0) { 24632 Log.e(VIEW_LOG_TAG, "MeasureSpec.adjust: new size would be negative! (" + size + 24633 ") spec: " + toString(measureSpec) + " delta: " + delta); 24634 size = 0; 24635 } 24636 return makeMeasureSpec(size, mode); 24637 } 24638 24639 /** 24640 * Returns a String representation of the specified measure 24641 * specification. 24642 * 24643 * @param measureSpec the measure specification to convert to a String 24644 * @return a String with the following format: "MeasureSpec: MODE SIZE" 24645 */ 24646 public static String toString(int measureSpec) { 24647 int mode = getMode(measureSpec); 24648 int size = getSize(measureSpec); 24649 24650 StringBuilder sb = new StringBuilder("MeasureSpec: "); 24651 24652 if (mode == UNSPECIFIED) 24653 sb.append("UNSPECIFIED "); 24654 else if (mode == EXACTLY) 24655 sb.append("EXACTLY "); 24656 else if (mode == AT_MOST) 24657 sb.append("AT_MOST "); 24658 else 24659 sb.append(mode).append(" "); 24660 24661 sb.append(size); 24662 return sb.toString(); 24663 } 24664 } 24665 24666 private final class CheckForLongPress implements Runnable { 24667 private int mOriginalWindowAttachCount; 24668 private float mX; 24669 private float mY; 24670 private boolean mOriginalPressedState; 24671 24672 @Override 24673 public void run() { 24674 if ((mOriginalPressedState == isPressed()) && (mParent != null) 24675 && mOriginalWindowAttachCount == mWindowAttachCount) { 24676 if (performLongClick(mX, mY)) { 24677 mHasPerformedLongPress = true; 24678 } 24679 } 24680 } 24681 24682 public void setAnchor(float x, float y) { 24683 mX = x; 24684 mY = y; 24685 } 24686 24687 public void rememberWindowAttachCount() { 24688 mOriginalWindowAttachCount = mWindowAttachCount; 24689 } 24690 24691 public void rememberPressedState() { 24692 mOriginalPressedState = isPressed(); 24693 } 24694 } 24695 24696 private final class CheckForTap implements Runnable { 24697 public float x; 24698 public float y; 24699 24700 @Override 24701 public void run() { 24702 mPrivateFlags &= ~PFLAG_PREPRESSED; 24703 setPressed(true, x, y); 24704 checkForLongClick(ViewConfiguration.getTapTimeout(), x, y); 24705 } 24706 } 24707 24708 private final class PerformClick implements Runnable { 24709 @Override 24710 public void run() { 24711 performClick(); 24712 } 24713 } 24714 24715 /** 24716 * This method returns a ViewPropertyAnimator object, which can be used to animate 24717 * specific properties on this View. 24718 * 24719 * @return ViewPropertyAnimator The ViewPropertyAnimator associated with this View. 24720 */ 24721 public ViewPropertyAnimator animate() { 24722 if (mAnimator == null) { 24723 mAnimator = new ViewPropertyAnimator(this); 24724 } 24725 return mAnimator; 24726 } 24727 24728 /** 24729 * Sets the name of the View to be used to identify Views in Transitions. 24730 * Names should be unique in the View hierarchy. 24731 * 24732 * @param transitionName The name of the View to uniquely identify it for Transitions. 24733 */ 24734 public final void setTransitionName(String transitionName) { 24735 mTransitionName = transitionName; 24736 } 24737 24738 /** 24739 * Returns the name of the View to be used to identify Views in Transitions. 24740 * Names should be unique in the View hierarchy. 24741 * 24742 * <p>This returns null if the View has not been given a name.</p> 24743 * 24744 * @return The name used of the View to be used to identify Views in Transitions or null 24745 * if no name has been given. 24746 */ 24747 @ViewDebug.ExportedProperty 24748 public String getTransitionName() { 24749 return mTransitionName; 24750 } 24751 24752 /** 24753 * @hide 24754 */ 24755 public void requestKeyboardShortcuts(List<KeyboardShortcutGroup> data, int deviceId) { 24756 // Do nothing. 24757 } 24758 24759 /** 24760 * Interface definition for a callback to be invoked when a hardware key event is 24761 * dispatched to this view. The callback will be invoked before the key event is 24762 * given to the view. This is only useful for hardware keyboards; a software input 24763 * method has no obligation to trigger this listener. 24764 */ 24765 public interface OnKeyListener { 24766 /** 24767 * Called when a hardware key is dispatched to a view. This allows listeners to 24768 * get a chance to respond before the target view. 24769 * <p>Key presses in software keyboards will generally NOT trigger this method, 24770 * although some may elect to do so in some situations. Do not assume a 24771 * software input method has to be key-based; even if it is, it may use key presses 24772 * in a different way than you expect, so there is no way to reliably catch soft 24773 * input key presses. 24774 * 24775 * @param v The view the key has been dispatched to. 24776 * @param keyCode The code for the physical key that was pressed 24777 * @param event The KeyEvent object containing full information about 24778 * the event. 24779 * @return True if the listener has consumed the event, false otherwise. 24780 */ 24781 boolean onKey(View v, int keyCode, KeyEvent event); 24782 } 24783 24784 /** 24785 * Interface definition for a callback to be invoked when a touch event is 24786 * dispatched to this view. The callback will be invoked before the touch 24787 * event is given to the view. 24788 */ 24789 public interface OnTouchListener { 24790 /** 24791 * Called when a touch event is dispatched to a view. This allows listeners to 24792 * get a chance to respond before the target view. 24793 * 24794 * @param v The view the touch event has been dispatched to. 24795 * @param event The MotionEvent object containing full information about 24796 * the event. 24797 * @return True if the listener has consumed the event, false otherwise. 24798 */ 24799 boolean onTouch(View v, MotionEvent event); 24800 } 24801 24802 /** 24803 * Interface definition for a callback to be invoked when a hover event is 24804 * dispatched to this view. The callback will be invoked before the hover 24805 * event is given to the view. 24806 */ 24807 public interface OnHoverListener { 24808 /** 24809 * Called when a hover event is dispatched to a view. This allows listeners to 24810 * get a chance to respond before the target view. 24811 * 24812 * @param v The view the hover event has been dispatched to. 24813 * @param event The MotionEvent object containing full information about 24814 * the event. 24815 * @return True if the listener has consumed the event, false otherwise. 24816 */ 24817 boolean onHover(View v, MotionEvent event); 24818 } 24819 24820 /** 24821 * Interface definition for a callback to be invoked when a generic motion event is 24822 * dispatched to this view. The callback will be invoked before the generic motion 24823 * event is given to the view. 24824 */ 24825 public interface OnGenericMotionListener { 24826 /** 24827 * Called when a generic motion event is dispatched to a view. This allows listeners to 24828 * get a chance to respond before the target view. 24829 * 24830 * @param v The view the generic motion event has been dispatched to. 24831 * @param event The MotionEvent object containing full information about 24832 * the event. 24833 * @return True if the listener has consumed the event, false otherwise. 24834 */ 24835 boolean onGenericMotion(View v, MotionEvent event); 24836 } 24837 24838 /** 24839 * Interface definition for a callback to be invoked when a view has been clicked and held. 24840 */ 24841 public interface OnLongClickListener { 24842 /** 24843 * Called when a view has been clicked and held. 24844 * 24845 * @param v The view that was clicked and held. 24846 * 24847 * @return true if the callback consumed the long click, false otherwise. 24848 */ 24849 boolean onLongClick(View v); 24850 } 24851 24852 /** 24853 * Interface definition for a callback to be invoked when a drag is being dispatched 24854 * to this view. The callback will be invoked before the hosting view's own 24855 * onDrag(event) method. If the listener wants to fall back to the hosting view's 24856 * onDrag(event) behavior, it should return 'false' from this callback. 24857 * 24858 * <div class="special reference"> 24859 * <h3>Developer Guides</h3> 24860 * <p>For a guide to implementing drag and drop features, read the 24861 * <a href="{@docRoot}guide/topics/ui/drag-drop.html">Drag and Drop</a> developer guide.</p> 24862 * </div> 24863 */ 24864 public interface OnDragListener { 24865 /** 24866 * Called when a drag event is dispatched to a view. This allows listeners 24867 * to get a chance to override base View behavior. 24868 * 24869 * @param v The View that received the drag event. 24870 * @param event The {@link android.view.DragEvent} object for the drag event. 24871 * @return {@code true} if the drag event was handled successfully, or {@code false} 24872 * if the drag event was not handled. Note that {@code false} will trigger the View 24873 * to call its {@link #onDragEvent(DragEvent) onDragEvent()} handler. 24874 */ 24875 boolean onDrag(View v, DragEvent event); 24876 } 24877 24878 /** 24879 * Interface definition for a callback to be invoked when the focus state of 24880 * a view changed. 24881 */ 24882 public interface OnFocusChangeListener { 24883 /** 24884 * Called when the focus state of a view has changed. 24885 * 24886 * @param v The view whose state has changed. 24887 * @param hasFocus The new focus state of v. 24888 */ 24889 void onFocusChange(View v, boolean hasFocus); 24890 } 24891 24892 /** 24893 * Interface definition for a callback to be invoked when a view is clicked. 24894 */ 24895 public interface OnClickListener { 24896 /** 24897 * Called when a view has been clicked. 24898 * 24899 * @param v The view that was clicked. 24900 */ 24901 void onClick(View v); 24902 } 24903 24904 /** 24905 * Interface definition for a callback to be invoked when a view is context clicked. 24906 */ 24907 public interface OnContextClickListener { 24908 /** 24909 * Called when a view is context clicked. 24910 * 24911 * @param v The view that has been context clicked. 24912 * @return true if the callback consumed the context click, false otherwise. 24913 */ 24914 boolean onContextClick(View v); 24915 } 24916 24917 /** 24918 * Interface definition for a callback to be invoked when the context menu 24919 * for this view is being built. 24920 */ 24921 public interface OnCreateContextMenuListener { 24922 /** 24923 * Called when the context menu for this view is being built. It is not 24924 * safe to hold onto the menu after this method returns. 24925 * 24926 * @param menu The context menu that is being built 24927 * @param v The view for which the context menu is being built 24928 * @param menuInfo Extra information about the item for which the 24929 * context menu should be shown. This information will vary 24930 * depending on the class of v. 24931 */ 24932 void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo); 24933 } 24934 24935 /** 24936 * Interface definition for a callback to be invoked when the status bar changes 24937 * visibility. This reports <strong>global</strong> changes to the system UI 24938 * state, not what the application is requesting. 24939 * 24940 * @see View#setOnSystemUiVisibilityChangeListener(android.view.View.OnSystemUiVisibilityChangeListener) 24941 */ 24942 public interface OnSystemUiVisibilityChangeListener { 24943 /** 24944 * Called when the status bar changes visibility because of a call to 24945 * {@link View#setSystemUiVisibility(int)}. 24946 * 24947 * @param visibility Bitwise-or of flags {@link #SYSTEM_UI_FLAG_LOW_PROFILE}, 24948 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, and {@link #SYSTEM_UI_FLAG_FULLSCREEN}. 24949 * This tells you the <strong>global</strong> state of these UI visibility 24950 * flags, not what your app is currently applying. 24951 */ 24952 public void onSystemUiVisibilityChange(int visibility); 24953 } 24954 24955 /** 24956 * Interface definition for a callback to be invoked when this view is attached 24957 * or detached from its window. 24958 */ 24959 public interface OnAttachStateChangeListener { 24960 /** 24961 * Called when the view is attached to a window. 24962 * @param v The view that was attached 24963 */ 24964 public void onViewAttachedToWindow(View v); 24965 /** 24966 * Called when the view is detached from a window. 24967 * @param v The view that was detached 24968 */ 24969 public void onViewDetachedFromWindow(View v); 24970 } 24971 24972 /** 24973 * Listener for applying window insets on a view in a custom way. 24974 * 24975 * <p>Apps may choose to implement this interface if they want to apply custom policy 24976 * to the way that window insets are treated for a view. If an OnApplyWindowInsetsListener 24977 * is set, its 24978 * {@link OnApplyWindowInsetsListener#onApplyWindowInsets(View, WindowInsets) onApplyWindowInsets} 24979 * method will be called instead of the View's own 24980 * {@link #onApplyWindowInsets(WindowInsets) onApplyWindowInsets} method. The listener 24981 * may optionally call the parameter View's <code>onApplyWindowInsets</code> method to apply 24982 * the View's normal behavior as part of its own.</p> 24983 */ 24984 public interface OnApplyWindowInsetsListener { 24985 /** 24986 * When {@link View#setOnApplyWindowInsetsListener(View.OnApplyWindowInsetsListener) set} 24987 * on a View, this listener method will be called instead of the view's own 24988 * {@link View#onApplyWindowInsets(WindowInsets) onApplyWindowInsets} method. 24989 * 24990 * @param v The view applying window insets 24991 * @param insets The insets to apply 24992 * @return The insets supplied, minus any insets that were consumed 24993 */ 24994 public WindowInsets onApplyWindowInsets(View v, WindowInsets insets); 24995 } 24996 24997 private final class UnsetPressedState implements Runnable { 24998 @Override 24999 public void run() { 25000 setPressed(false); 25001 } 25002 } 25003 25004 /** 25005 * When a view becomes invisible checks if autofill considers the view invisible too. This 25006 * happens after the regular removal operation to make sure the operation is finished by the 25007 * time this is called. 25008 */ 25009 private static class VisibilityChangeForAutofillHandler extends Handler { 25010 private final AutofillManager mAfm; 25011 private final View mView; 25012 25013 private VisibilityChangeForAutofillHandler(@NonNull AutofillManager afm, 25014 @NonNull View view) { 25015 mAfm = afm; 25016 mView = view; 25017 } 25018 25019 @Override 25020 public void handleMessage(Message msg) { 25021 mAfm.notifyViewVisibilityChanged(mView, mView.isShown()); 25022 } 25023 } 25024 25025 /** 25026 * Base class for derived classes that want to save and restore their own 25027 * state in {@link android.view.View#onSaveInstanceState()}. 25028 */ 25029 public static class BaseSavedState extends AbsSavedState { 25030 static final int START_ACTIVITY_REQUESTED_WHO_SAVED = 0b1; 25031 static final int IS_AUTOFILLED = 0b10; 25032 static final int AUTOFILL_ID = 0b100; 25033 25034 // Flags that describe what data in this state is valid 25035 int mSavedData; 25036 String mStartActivityRequestWhoSaved; 25037 boolean mIsAutofilled; 25038 int mAutofillViewId; 25039 25040 /** 25041 * Constructor used when reading from a parcel. Reads the state of the superclass. 25042 * 25043 * @param source parcel to read from 25044 */ 25045 public BaseSavedState(Parcel source) { 25046 this(source, null); 25047 } 25048 25049 /** 25050 * Constructor used when reading from a parcel using a given class loader. 25051 * Reads the state of the superclass. 25052 * 25053 * @param source parcel to read from 25054 * @param loader ClassLoader to use for reading 25055 */ 25056 public BaseSavedState(Parcel source, ClassLoader loader) { 25057 super(source, loader); 25058 mSavedData = source.readInt(); 25059 mStartActivityRequestWhoSaved = source.readString(); 25060 mIsAutofilled = source.readBoolean(); 25061 mAutofillViewId = source.readInt(); 25062 } 25063 25064 /** 25065 * Constructor called by derived classes when creating their SavedState objects 25066 * 25067 * @param superState The state of the superclass of this view 25068 */ 25069 public BaseSavedState(Parcelable superState) { 25070 super(superState); 25071 } 25072 25073 @Override 25074 public void writeToParcel(Parcel out, int flags) { 25075 super.writeToParcel(out, flags); 25076 25077 out.writeInt(mSavedData); 25078 out.writeString(mStartActivityRequestWhoSaved); 25079 out.writeBoolean(mIsAutofilled); 25080 out.writeInt(mAutofillViewId); 25081 } 25082 25083 public static final Parcelable.Creator<BaseSavedState> CREATOR 25084 = new Parcelable.ClassLoaderCreator<BaseSavedState>() { 25085 @Override 25086 public BaseSavedState createFromParcel(Parcel in) { 25087 return new BaseSavedState(in); 25088 } 25089 25090 @Override 25091 public BaseSavedState createFromParcel(Parcel in, ClassLoader loader) { 25092 return new BaseSavedState(in, loader); 25093 } 25094 25095 @Override 25096 public BaseSavedState[] newArray(int size) { 25097 return new BaseSavedState[size]; 25098 } 25099 }; 25100 } 25101 25102 /** 25103 * A set of information given to a view when it is attached to its parent 25104 * window. 25105 */ 25106 final static class AttachInfo { 25107 interface Callbacks { 25108 void playSoundEffect(int effectId); 25109 boolean performHapticFeedback(int effectId, boolean always); 25110 } 25111 25112 /** 25113 * InvalidateInfo is used to post invalidate(int, int, int, int) messages 25114 * to a Handler. This class contains the target (View) to invalidate and 25115 * the coordinates of the dirty rectangle. 25116 * 25117 * For performance purposes, this class also implements a pool of up to 25118 * POOL_LIMIT objects that get reused. This reduces memory allocations 25119 * whenever possible. 25120 */ 25121 static class InvalidateInfo { 25122 private static final int POOL_LIMIT = 10; 25123 25124 private static final SynchronizedPool<InvalidateInfo> sPool = 25125 new SynchronizedPool<InvalidateInfo>(POOL_LIMIT); 25126 25127 View target; 25128 25129 int left; 25130 int top; 25131 int right; 25132 int bottom; 25133 25134 public static InvalidateInfo obtain() { 25135 InvalidateInfo instance = sPool.acquire(); 25136 return (instance != null) ? instance : new InvalidateInfo(); 25137 } 25138 25139 public void recycle() { 25140 target = null; 25141 sPool.release(this); 25142 } 25143 } 25144 25145 final IWindowSession mSession; 25146 25147 final IWindow mWindow; 25148 25149 final IBinder mWindowToken; 25150 25151 Display mDisplay; 25152 25153 final Callbacks mRootCallbacks; 25154 25155 IWindowId mIWindowId; 25156 WindowId mWindowId; 25157 25158 /** 25159 * The top view of the hierarchy. 25160 */ 25161 View mRootView; 25162 25163 IBinder mPanelParentWindowToken; 25164 25165 boolean mHardwareAccelerated; 25166 boolean mHardwareAccelerationRequested; 25167 ThreadedRenderer mThreadedRenderer; 25168 List<RenderNode> mPendingAnimatingRenderNodes; 25169 25170 /** 25171 * The state of the display to which the window is attached, as reported 25172 * by {@link Display#getState()}. Note that the display state constants 25173 * declared by {@link Display} do not exactly line up with the screen state 25174 * constants declared by {@link View} (there are more display states than 25175 * screen states). 25176 */ 25177 int mDisplayState = Display.STATE_UNKNOWN; 25178 25179 /** 25180 * Scale factor used by the compatibility mode 25181 */ 25182 float mApplicationScale; 25183 25184 /** 25185 * Indicates whether the application is in compatibility mode 25186 */ 25187 boolean mScalingRequired; 25188 25189 /** 25190 * Left position of this view's window 25191 */ 25192 int mWindowLeft; 25193 25194 /** 25195 * Top position of this view's window 25196 */ 25197 int mWindowTop; 25198 25199 /** 25200 * Indicates whether views need to use 32-bit drawing caches 25201 */ 25202 boolean mUse32BitDrawingCache; 25203 25204 /** 25205 * For windows that are full-screen but using insets to layout inside 25206 * of the screen areas, these are the current insets to appear inside 25207 * the overscan area of the display. 25208 */ 25209 final Rect mOverscanInsets = new Rect(); 25210 25211 /** 25212 * For windows that are full-screen but using insets to layout inside 25213 * of the screen decorations, these are the current insets for the 25214 * content of the window. 25215 */ 25216 final Rect mContentInsets = new Rect(); 25217 25218 /** 25219 * For windows that are full-screen but using insets to layout inside 25220 * of the screen decorations, these are the current insets for the 25221 * actual visible parts of the window. 25222 */ 25223 final Rect mVisibleInsets = new Rect(); 25224 25225 /** 25226 * For windows that are full-screen but using insets to layout inside 25227 * of the screen decorations, these are the current insets for the 25228 * stable system windows. 25229 */ 25230 final Rect mStableInsets = new Rect(); 25231 25232 /** 25233 * For windows that include areas that are not covered by real surface these are the outsets 25234 * for real surface. 25235 */ 25236 final Rect mOutsets = new Rect(); 25237 25238 /** 25239 * In multi-window we force show the navigation bar. Because we don't want that the surface 25240 * size changes in this mode, we instead have a flag whether the navigation bar size should 25241 * always be consumed, so the app is treated like there is no virtual navigation bar at all. 25242 */ 25243 boolean mAlwaysConsumeNavBar; 25244 25245 /** 25246 * The internal insets given by this window. This value is 25247 * supplied by the client (through 25248 * {@link ViewTreeObserver.OnComputeInternalInsetsListener}) and will 25249 * be given to the window manager when changed to be used in laying 25250 * out windows behind it. 25251 */ 25252 final ViewTreeObserver.InternalInsetsInfo mGivenInternalInsets 25253 = new ViewTreeObserver.InternalInsetsInfo(); 25254 25255 /** 25256 * Set to true when mGivenInternalInsets is non-empty. 25257 */ 25258 boolean mHasNonEmptyGivenInternalInsets; 25259 25260 /** 25261 * All views in the window's hierarchy that serve as scroll containers, 25262 * used to determine if the window can be resized or must be panned 25263 * to adjust for a soft input area. 25264 */ 25265 final ArrayList<View> mScrollContainers = new ArrayList<View>(); 25266 25267 final KeyEvent.DispatcherState mKeyDispatchState 25268 = new KeyEvent.DispatcherState(); 25269 25270 /** 25271 * Indicates whether the view's window currently has the focus. 25272 */ 25273 boolean mHasWindowFocus; 25274 25275 /** 25276 * The current visibility of the window. 25277 */ 25278 int mWindowVisibility; 25279 25280 /** 25281 * Indicates the time at which drawing started to occur. 25282 */ 25283 long mDrawingTime; 25284 25285 /** 25286 * Indicates whether or not ignoring the DIRTY_MASK flags. 25287 */ 25288 boolean mIgnoreDirtyState; 25289 25290 /** 25291 * This flag tracks when the mIgnoreDirtyState flag is set during draw(), 25292 * to avoid clearing that flag prematurely. 25293 */ 25294 boolean mSetIgnoreDirtyState = false; 25295 25296 /** 25297 * Indicates whether the view's window is currently in touch mode. 25298 */ 25299 boolean mInTouchMode; 25300 25301 /** 25302 * Indicates whether the view has requested unbuffered input dispatching for the current 25303 * event stream. 25304 */ 25305 boolean mUnbufferedDispatchRequested; 25306 25307 /** 25308 * Indicates that ViewAncestor should trigger a global layout change 25309 * the next time it performs a traversal 25310 */ 25311 boolean mRecomputeGlobalAttributes; 25312 25313 /** 25314 * Always report new attributes at next traversal. 25315 */ 25316 boolean mForceReportNewAttributes; 25317 25318 /** 25319 * Set during a traveral if any views want to keep the screen on. 25320 */ 25321 boolean mKeepScreenOn; 25322 25323 /** 25324 * Set during a traveral if the light center needs to be updated. 25325 */ 25326 boolean mNeedsUpdateLightCenter; 25327 25328 /** 25329 * Bitwise-or of all of the values that views have passed to setSystemUiVisibility(). 25330 */ 25331 int mSystemUiVisibility; 25332 25333 /** 25334 * Hack to force certain system UI visibility flags to be cleared. 25335 */ 25336 int mDisabledSystemUiVisibility; 25337 25338 /** 25339 * Last global system UI visibility reported by the window manager. 25340 */ 25341 int mGlobalSystemUiVisibility = -1; 25342 25343 /** 25344 * True if a view in this hierarchy has an OnSystemUiVisibilityChangeListener 25345 * attached. 25346 */ 25347 boolean mHasSystemUiListeners; 25348 25349 /** 25350 * Set if the window has requested to extend into the overscan region 25351 * via WindowManager.LayoutParams.FLAG_LAYOUT_IN_OVERSCAN. 25352 */ 25353 boolean mOverscanRequested; 25354 25355 /** 25356 * Set if the visibility of any views has changed. 25357 */ 25358 boolean mViewVisibilityChanged; 25359 25360 /** 25361 * Set to true if a view has been scrolled. 25362 */ 25363 boolean mViewScrollChanged; 25364 25365 /** 25366 * Set to true if high contrast mode enabled 25367 */ 25368 boolean mHighContrastText; 25369 25370 /** 25371 * Set to true if a pointer event is currently being handled. 25372 */ 25373 boolean mHandlingPointerEvent; 25374 25375 /** 25376 * Global to the view hierarchy used as a temporary for dealing with 25377 * x/y points in the transparent region computations. 25378 */ 25379 final int[] mTransparentLocation = new int[2]; 25380 25381 /** 25382 * Global to the view hierarchy used as a temporary for dealing with 25383 * x/y points in the ViewGroup.invalidateChild implementation. 25384 */ 25385 final int[] mInvalidateChildLocation = new int[2]; 25386 25387 /** 25388 * Global to the view hierarchy used as a temporary for dealing with 25389 * computing absolute on-screen location. 25390 */ 25391 final int[] mTmpLocation = new int[2]; 25392 25393 /** 25394 * Global to the view hierarchy used as a temporary for dealing with 25395 * x/y location when view is transformed. 25396 */ 25397 final float[] mTmpTransformLocation = new float[2]; 25398 25399 /** 25400 * The view tree observer used to dispatch global events like 25401 * layout, pre-draw, touch mode change, etc. 25402 */ 25403 final ViewTreeObserver mTreeObserver; 25404 25405 /** 25406 * A Canvas used by the view hierarchy to perform bitmap caching. 25407 */ 25408 Canvas mCanvas; 25409 25410 /** 25411 * The view root impl. 25412 */ 25413 final ViewRootImpl mViewRootImpl; 25414 25415 /** 25416 * A Handler supplied by a view's {@link android.view.ViewRootImpl}. This 25417 * handler can be used to pump events in the UI events queue. 25418 */ 25419 final Handler mHandler; 25420 25421 /** 25422 * Temporary for use in computing invalidate rectangles while 25423 * calling up the hierarchy. 25424 */ 25425 final Rect mTmpInvalRect = new Rect(); 25426 25427 /** 25428 * Temporary for use in computing hit areas with transformed views 25429 */ 25430 final RectF mTmpTransformRect = new RectF(); 25431 25432 /** 25433 * Temporary for use in computing hit areas with transformed views 25434 */ 25435 final RectF mTmpTransformRect1 = new RectF(); 25436 25437 /** 25438 * Temporary list of rectanges. 25439 */ 25440 final List<RectF> mTmpRectList = new ArrayList<>(); 25441 25442 /** 25443 * Temporary for use in transforming invalidation rect 25444 */ 25445 final Matrix mTmpMatrix = new Matrix(); 25446 25447 /** 25448 * Temporary for use in transforming invalidation rect 25449 */ 25450 final Transformation mTmpTransformation = new Transformation(); 25451 25452 /** 25453 * Temporary for use in querying outlines from OutlineProviders 25454 */ 25455 final Outline mTmpOutline = new Outline(); 25456 25457 /** 25458 * Temporary list for use in collecting focusable descendents of a view. 25459 */ 25460 final ArrayList<View> mTempArrayList = new ArrayList<View>(24); 25461 25462 /** 25463 * The id of the window for accessibility purposes. 25464 */ 25465 int mAccessibilityWindowId = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID; 25466 25467 /** 25468 * Flags related to accessibility processing. 25469 * 25470 * @see AccessibilityNodeInfo#FLAG_INCLUDE_NOT_IMPORTANT_VIEWS 25471 * @see AccessibilityNodeInfo#FLAG_REPORT_VIEW_IDS 25472 */ 25473 int mAccessibilityFetchFlags; 25474 25475 /** 25476 * The drawable for highlighting accessibility focus. 25477 */ 25478 Drawable mAccessibilityFocusDrawable; 25479 25480 /** 25481 * The drawable for highlighting autofilled views. 25482 * 25483 * @see #isAutofilled() 25484 */ 25485 Drawable mAutofilledDrawable; 25486 25487 /** 25488 * Show where the margins, bounds and layout bounds are for each view. 25489 */ 25490 boolean mDebugLayout = SystemProperties.getBoolean(DEBUG_LAYOUT_PROPERTY, false); 25491 25492 /** 25493 * Point used to compute visible regions. 25494 */ 25495 final Point mPoint = new Point(); 25496 25497 /** 25498 * Used to track which View originated a requestLayout() call, used when 25499 * requestLayout() is called during layout. 25500 */ 25501 View mViewRequestingLayout; 25502 25503 /** 25504 * Used to track views that need (at least) a partial relayout at their current size 25505 * during the next traversal. 25506 */ 25507 List<View> mPartialLayoutViews = new ArrayList<>(); 25508 25509 /** 25510 * Swapped with mPartialLayoutViews during layout to avoid concurrent 25511 * modification. Lazily assigned during ViewRootImpl layout. 25512 */ 25513 List<View> mEmptyPartialLayoutViews; 25514 25515 /** 25516 * Used to track the identity of the current drag operation. 25517 */ 25518 IBinder mDragToken; 25519 25520 /** 25521 * The drag shadow surface for the current drag operation. 25522 */ 25523 public Surface mDragSurface; 25524 25525 25526 /** 25527 * The view that currently has a tooltip displayed. 25528 */ 25529 View mTooltipHost; 25530 25531 /** 25532 * Creates a new set of attachment information with the specified 25533 * events handler and thread. 25534 * 25535 * @param handler the events handler the view must use 25536 */ 25537 AttachInfo(IWindowSession session, IWindow window, Display display, 25538 ViewRootImpl viewRootImpl, Handler handler, Callbacks effectPlayer, 25539 Context context) { 25540 mSession = session; 25541 mWindow = window; 25542 mWindowToken = window.asBinder(); 25543 mDisplay = display; 25544 mViewRootImpl = viewRootImpl; 25545 mHandler = handler; 25546 mRootCallbacks = effectPlayer; 25547 mTreeObserver = new ViewTreeObserver(context); 25548 } 25549 } 25550 25551 /** 25552 * <p>ScrollabilityCache holds various fields used by a View when scrolling 25553 * is supported. This avoids keeping too many unused fields in most 25554 * instances of View.</p> 25555 */ 25556 private static class ScrollabilityCache implements Runnable { 25557 25558 /** 25559 * Scrollbars are not visible 25560 */ 25561 public static final int OFF = 0; 25562 25563 /** 25564 * Scrollbars are visible 25565 */ 25566 public static final int ON = 1; 25567 25568 /** 25569 * Scrollbars are fading away 25570 */ 25571 public static final int FADING = 2; 25572 25573 public boolean fadeScrollBars; 25574 25575 public int fadingEdgeLength; 25576 public int scrollBarDefaultDelayBeforeFade; 25577 public int scrollBarFadeDuration; 25578 25579 public int scrollBarSize; 25580 public int scrollBarMinTouchTarget; 25581 public ScrollBarDrawable scrollBar; 25582 public float[] interpolatorValues; 25583 public View host; 25584 25585 public final Paint paint; 25586 public final Matrix matrix; 25587 public Shader shader; 25588 25589 public final Interpolator scrollBarInterpolator = new Interpolator(1, 2); 25590 25591 private static final float[] OPAQUE = { 255 }; 25592 private static final float[] TRANSPARENT = { 0.0f }; 25593 25594 /** 25595 * When fading should start. This time moves into the future every time 25596 * a new scroll happens. Measured based on SystemClock.uptimeMillis() 25597 */ 25598 public long fadeStartTime; 25599 25600 25601 /** 25602 * The current state of the scrollbars: ON, OFF, or FADING 25603 */ 25604 public int state = OFF; 25605 25606 private int mLastColor; 25607 25608 public final Rect mScrollBarBounds = new Rect(); 25609 public final Rect mScrollBarTouchBounds = new Rect(); 25610 25611 public static final int NOT_DRAGGING = 0; 25612 public static final int DRAGGING_VERTICAL_SCROLL_BAR = 1; 25613 public static final int DRAGGING_HORIZONTAL_SCROLL_BAR = 2; 25614 public int mScrollBarDraggingState = NOT_DRAGGING; 25615 25616 public float mScrollBarDraggingPos = 0; 25617 25618 public ScrollabilityCache(ViewConfiguration configuration, View host) { 25619 fadingEdgeLength = configuration.getScaledFadingEdgeLength(); 25620 scrollBarSize = configuration.getScaledScrollBarSize(); 25621 scrollBarMinTouchTarget = configuration.getScaledMinScrollbarTouchTarget(); 25622 scrollBarDefaultDelayBeforeFade = ViewConfiguration.getScrollDefaultDelay(); 25623 scrollBarFadeDuration = ViewConfiguration.getScrollBarFadeDuration(); 25624 25625 paint = new Paint(); 25626 matrix = new Matrix(); 25627 // use use a height of 1, and then wack the matrix each time we 25628 // actually use it. 25629 shader = new LinearGradient(0, 0, 0, 1, 0xFF000000, 0, Shader.TileMode.CLAMP); 25630 paint.setShader(shader); 25631 paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); 25632 25633 this.host = host; 25634 } 25635 25636 public void setFadeColor(int color) { 25637 if (color != mLastColor) { 25638 mLastColor = color; 25639 25640 if (color != 0) { 25641 shader = new LinearGradient(0, 0, 0, 1, color | 0xFF000000, 25642 color & 0x00FFFFFF, Shader.TileMode.CLAMP); 25643 paint.setShader(shader); 25644 // Restore the default transfer mode (src_over) 25645 paint.setXfermode(null); 25646 } else { 25647 shader = new LinearGradient(0, 0, 0, 1, 0xFF000000, 0, Shader.TileMode.CLAMP); 25648 paint.setShader(shader); 25649 paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); 25650 } 25651 } 25652 } 25653 25654 public void run() { 25655 long now = AnimationUtils.currentAnimationTimeMillis(); 25656 if (now >= fadeStartTime) { 25657 25658 // the animation fades the scrollbars out by changing 25659 // the opacity (alpha) from fully opaque to fully 25660 // transparent 25661 int nextFrame = (int) now; 25662 int framesCount = 0; 25663 25664 Interpolator interpolator = scrollBarInterpolator; 25665 25666 // Start opaque 25667 interpolator.setKeyFrame(framesCount++, nextFrame, OPAQUE); 25668 25669 // End transparent 25670 nextFrame += scrollBarFadeDuration; 25671 interpolator.setKeyFrame(framesCount, nextFrame, TRANSPARENT); 25672 25673 state = FADING; 25674 25675 // Kick off the fade animation 25676 host.invalidate(true); 25677 } 25678 } 25679 } 25680 25681 /** 25682 * Resuable callback for sending 25683 * {@link AccessibilityEvent#TYPE_VIEW_SCROLLED} accessibility event. 25684 */ 25685 private class SendViewScrolledAccessibilityEvent implements Runnable { 25686 public volatile boolean mIsPending; 25687 25688 public void run() { 25689 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SCROLLED); 25690 mIsPending = false; 25691 } 25692 } 25693 25694 /** 25695 * <p> 25696 * This class represents a delegate that can be registered in a {@link View} 25697 * to enhance accessibility support via composition rather via inheritance. 25698 * It is specifically targeted to widget developers that extend basic View 25699 * classes i.e. classes in package android.view, that would like their 25700 * applications to be backwards compatible. 25701 * </p> 25702 * <div class="special reference"> 25703 * <h3>Developer Guides</h3> 25704 * <p>For more information about making applications accessible, read the 25705 * <a href="{@docRoot}guide/topics/ui/accessibility/index.html">Accessibility</a> 25706 * developer guide.</p> 25707 * </div> 25708 * <p> 25709 * A scenario in which a developer would like to use an accessibility delegate 25710 * is overriding a method introduced in a later API version than the minimal API 25711 * version supported by the application. For example, the method 25712 * {@link View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} is not available 25713 * in API version 4 when the accessibility APIs were first introduced. If a 25714 * developer would like his application to run on API version 4 devices (assuming 25715 * all other APIs used by the application are version 4 or lower) and take advantage 25716 * of this method, instead of overriding the method which would break the application's 25717 * backwards compatibility, he can override the corresponding method in this 25718 * delegate and register the delegate in the target View if the API version of 25719 * the system is high enough, i.e. the API version is the same as or higher than the API 25720 * version that introduced 25721 * {@link View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)}. 25722 * </p> 25723 * <p> 25724 * Here is an example implementation: 25725 * </p> 25726 * <code><pre><p> 25727 * if (Build.VERSION.SDK_INT >= 14) { 25728 * // If the API version is equal of higher than the version in 25729 * // which onInitializeAccessibilityNodeInfo was introduced we 25730 * // register a delegate with a customized implementation. 25731 * View view = findViewById(R.id.view_id); 25732 * view.setAccessibilityDelegate(new AccessibilityDelegate() { 25733 * public void onInitializeAccessibilityNodeInfo(View host, 25734 * AccessibilityNodeInfo info) { 25735 * // Let the default implementation populate the info. 25736 * super.onInitializeAccessibilityNodeInfo(host, info); 25737 * // Set some other information. 25738 * info.setEnabled(host.isEnabled()); 25739 * } 25740 * }); 25741 * } 25742 * </code></pre></p> 25743 * <p> 25744 * This delegate contains methods that correspond to the accessibility methods 25745 * in View. If a delegate has been specified the implementation in View hands 25746 * off handling to the corresponding method in this delegate. The default 25747 * implementation the delegate methods behaves exactly as the corresponding 25748 * method in View for the case of no accessibility delegate been set. Hence, 25749 * to customize the behavior of a View method, clients can override only the 25750 * corresponding delegate method without altering the behavior of the rest 25751 * accessibility related methods of the host view. 25752 * </p> 25753 * <p> 25754 * <strong>Note:</strong> On platform versions prior to 25755 * {@link android.os.Build.VERSION_CODES#M API 23}, delegate methods on 25756 * views in the {@code android.widget.*} package are called <i>before</i> 25757 * host methods. This prevents certain properties such as class name from 25758 * being modified by overriding 25759 * {@link AccessibilityDelegate#onInitializeAccessibilityNodeInfo(View, AccessibilityNodeInfo)}, 25760 * as any changes will be overwritten by the host class. 25761 * <p> 25762 * Starting in {@link android.os.Build.VERSION_CODES#M API 23}, delegate 25763 * methods are called <i>after</i> host methods, which all properties to be 25764 * modified without being overwritten by the host class. 25765 */ 25766 public static class AccessibilityDelegate { 25767 25768 /** 25769 * Sends an accessibility event of the given type. If accessibility is not 25770 * enabled this method has no effect. 25771 * <p> 25772 * The default implementation behaves as {@link View#sendAccessibilityEvent(int) 25773 * View#sendAccessibilityEvent(int)} for the case of no accessibility delegate 25774 * been set. 25775 * </p> 25776 * 25777 * @param host The View hosting the delegate. 25778 * @param eventType The type of the event to send. 25779 * 25780 * @see View#sendAccessibilityEvent(int) View#sendAccessibilityEvent(int) 25781 */ 25782 public void sendAccessibilityEvent(View host, int eventType) { 25783 host.sendAccessibilityEventInternal(eventType); 25784 } 25785 25786 /** 25787 * Performs the specified accessibility action on the view. For 25788 * possible accessibility actions look at {@link AccessibilityNodeInfo}. 25789 * <p> 25790 * The default implementation behaves as 25791 * {@link View#performAccessibilityAction(int, Bundle) 25792 * View#performAccessibilityAction(int, Bundle)} for the case of 25793 * no accessibility delegate been set. 25794 * </p> 25795 * 25796 * @param action The action to perform. 25797 * @return Whether the action was performed. 25798 * 25799 * @see View#performAccessibilityAction(int, Bundle) 25800 * View#performAccessibilityAction(int, Bundle) 25801 */ 25802 public boolean performAccessibilityAction(View host, int action, Bundle args) { 25803 return host.performAccessibilityActionInternal(action, args); 25804 } 25805 25806 /** 25807 * Sends an accessibility event. This method behaves exactly as 25808 * {@link #sendAccessibilityEvent(View, int)} but takes as an argument an 25809 * empty {@link AccessibilityEvent} and does not perform a check whether 25810 * accessibility is enabled. 25811 * <p> 25812 * The default implementation behaves as 25813 * {@link View#sendAccessibilityEventUnchecked(AccessibilityEvent) 25814 * View#sendAccessibilityEventUnchecked(AccessibilityEvent)} for 25815 * the case of no accessibility delegate been set. 25816 * </p> 25817 * 25818 * @param host The View hosting the delegate. 25819 * @param event The event to send. 25820 * 25821 * @see View#sendAccessibilityEventUnchecked(AccessibilityEvent) 25822 * View#sendAccessibilityEventUnchecked(AccessibilityEvent) 25823 */ 25824 public void sendAccessibilityEventUnchecked(View host, AccessibilityEvent event) { 25825 host.sendAccessibilityEventUncheckedInternal(event); 25826 } 25827 25828 /** 25829 * Dispatches an {@link AccessibilityEvent} to the host {@link View} first and then 25830 * to its children for adding their text content to the event. 25831 * <p> 25832 * The default implementation behaves as 25833 * {@link View#dispatchPopulateAccessibilityEvent(AccessibilityEvent) 25834 * View#dispatchPopulateAccessibilityEvent(AccessibilityEvent)} for 25835 * the case of no accessibility delegate been set. 25836 * </p> 25837 * 25838 * @param host The View hosting the delegate. 25839 * @param event The event. 25840 * @return True if the event population was completed. 25841 * 25842 * @see View#dispatchPopulateAccessibilityEvent(AccessibilityEvent) 25843 * View#dispatchPopulateAccessibilityEvent(AccessibilityEvent) 25844 */ 25845 public boolean dispatchPopulateAccessibilityEvent(View host, AccessibilityEvent event) { 25846 return host.dispatchPopulateAccessibilityEventInternal(event); 25847 } 25848 25849 /** 25850 * Gives a chance to the host View to populate the accessibility event with its 25851 * text content. 25852 * <p> 25853 * The default implementation behaves as 25854 * {@link View#onPopulateAccessibilityEvent(AccessibilityEvent) 25855 * View#onPopulateAccessibilityEvent(AccessibilityEvent)} for 25856 * the case of no accessibility delegate been set. 25857 * </p> 25858 * 25859 * @param host The View hosting the delegate. 25860 * @param event The accessibility event which to populate. 25861 * 25862 * @see View#onPopulateAccessibilityEvent(AccessibilityEvent) 25863 * View#onPopulateAccessibilityEvent(AccessibilityEvent) 25864 */ 25865 public void onPopulateAccessibilityEvent(View host, AccessibilityEvent event) { 25866 host.onPopulateAccessibilityEventInternal(event); 25867 } 25868 25869 /** 25870 * Initializes an {@link AccessibilityEvent} with information about the 25871 * the host View which is the event source. 25872 * <p> 25873 * The default implementation behaves as 25874 * {@link View#onInitializeAccessibilityEvent(AccessibilityEvent) 25875 * View#onInitializeAccessibilityEvent(AccessibilityEvent)} for 25876 * the case of no accessibility delegate been set. 25877 * </p> 25878 * 25879 * @param host The View hosting the delegate. 25880 * @param event The event to initialize. 25881 * 25882 * @see View#onInitializeAccessibilityEvent(AccessibilityEvent) 25883 * View#onInitializeAccessibilityEvent(AccessibilityEvent) 25884 */ 25885 public void onInitializeAccessibilityEvent(View host, AccessibilityEvent event) { 25886 host.onInitializeAccessibilityEventInternal(event); 25887 } 25888 25889 /** 25890 * Initializes an {@link AccessibilityNodeInfo} with information about the host view. 25891 * <p> 25892 * The default implementation behaves as 25893 * {@link View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo) 25894 * View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} for 25895 * the case of no accessibility delegate been set. 25896 * </p> 25897 * 25898 * @param host The View hosting the delegate. 25899 * @param info The instance to initialize. 25900 * 25901 * @see View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo) 25902 * View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo) 25903 */ 25904 public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) { 25905 host.onInitializeAccessibilityNodeInfoInternal(info); 25906 } 25907 25908 /** 25909 * Adds extra data to an {@link AccessibilityNodeInfo} based on an explicit request for the 25910 * additional data. 25911 * <p> 25912 * This method only needs to be implemented if the View offers to provide additional data. 25913 * </p> 25914 * <p> 25915 * The default implementation behaves as 25916 * {@link View#addExtraDataToAccessibilityNodeInfo(AccessibilityNodeInfo, String, Bundle) 25917 * for the case where no accessibility delegate is set. 25918 * </p> 25919 * 25920 * @param host The View hosting the delegate. Never {@code null}. 25921 * @param info The info to which to add the extra data. Never {@code null}. 25922 * @param extraDataKey A key specifying the type of extra data to add to the info. The 25923 * extra data should be added to the {@link Bundle} returned by 25924 * the info's {@link AccessibilityNodeInfo#getExtras} method. Never 25925 * {@code null}. 25926 * @param arguments A {@link Bundle} holding any arguments relevant for this request. 25927 * May be {@code null} if the if the service provided no arguments. 25928 * 25929 * @see AccessibilityNodeInfo#setExtraAvailableData 25930 */ 25931 public void addExtraDataToAccessibilityNodeInfo(@NonNull View host, 25932 @NonNull AccessibilityNodeInfo info, @NonNull String extraDataKey, 25933 @Nullable Bundle arguments) { 25934 host.addExtraDataToAccessibilityNodeInfo(info, extraDataKey, arguments); 25935 } 25936 25937 /** 25938 * Called when a child of the host View has requested sending an 25939 * {@link AccessibilityEvent} and gives an opportunity to the parent (the host) 25940 * to augment the event. 25941 * <p> 25942 * The default implementation behaves as 25943 * {@link ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent) 25944 * ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent)} for 25945 * the case of no accessibility delegate been set. 25946 * </p> 25947 * 25948 * @param host The View hosting the delegate. 25949 * @param child The child which requests sending the event. 25950 * @param event The event to be sent. 25951 * @return True if the event should be sent 25952 * 25953 * @see ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent) 25954 * ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent) 25955 */ 25956 public boolean onRequestSendAccessibilityEvent(ViewGroup host, View child, 25957 AccessibilityEvent event) { 25958 return host.onRequestSendAccessibilityEventInternal(child, event); 25959 } 25960 25961 /** 25962 * Gets the provider for managing a virtual view hierarchy rooted at this View 25963 * and reported to {@link android.accessibilityservice.AccessibilityService}s 25964 * that explore the window content. 25965 * <p> 25966 * The default implementation behaves as 25967 * {@link View#getAccessibilityNodeProvider() View#getAccessibilityNodeProvider()} for 25968 * the case of no accessibility delegate been set. 25969 * </p> 25970 * 25971 * @return The provider. 25972 * 25973 * @see AccessibilityNodeProvider 25974 */ 25975 public AccessibilityNodeProvider getAccessibilityNodeProvider(View host) { 25976 return null; 25977 } 25978 25979 /** 25980 * Returns an {@link AccessibilityNodeInfo} representing the host view from the 25981 * point of view of an {@link android.accessibilityservice.AccessibilityService}. 25982 * This method is responsible for obtaining an accessibility node info from a 25983 * pool of reusable instances and calling 25984 * {@link #onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} on the host 25985 * view to initialize the former. 25986 * <p> 25987 * <strong>Note:</strong> The client is responsible for recycling the obtained 25988 * instance by calling {@link AccessibilityNodeInfo#recycle()} to minimize object 25989 * creation. 25990 * </p> 25991 * <p> 25992 * The default implementation behaves as 25993 * {@link View#createAccessibilityNodeInfo() View#createAccessibilityNodeInfo()} for 25994 * the case of no accessibility delegate been set. 25995 * </p> 25996 * @return A populated {@link AccessibilityNodeInfo}. 25997 * 25998 * @see AccessibilityNodeInfo 25999 * 26000 * @hide 26001 */ 26002 public AccessibilityNodeInfo createAccessibilityNodeInfo(View host) { 26003 return host.createAccessibilityNodeInfoInternal(); 26004 } 26005 } 26006 26007 private static class MatchIdPredicate implements Predicate<View> { 26008 public int mId; 26009 26010 @Override 26011 public boolean test(View view) { 26012 return (view.mID == mId); 26013 } 26014 } 26015 26016 private static class MatchLabelForPredicate implements Predicate<View> { 26017 private int mLabeledId; 26018 26019 @Override 26020 public boolean test(View view) { 26021 return (view.mLabelForId == mLabeledId); 26022 } 26023 } 26024 26025 /** 26026 * Dump all private flags in readable format, useful for documentation and 26027 * sanity checking. 26028 */ 26029 private static void dumpFlags() { 26030 final HashMap<String, String> found = Maps.newHashMap(); 26031 try { 26032 for (Field field : View.class.getDeclaredFields()) { 26033 final int modifiers = field.getModifiers(); 26034 if (Modifier.isStatic(modifiers) && Modifier.isFinal(modifiers)) { 26035 if (field.getType().equals(int.class)) { 26036 final int value = field.getInt(null); 26037 dumpFlag(found, field.getName(), value); 26038 } else if (field.getType().equals(int[].class)) { 26039 final int[] values = (int[]) field.get(null); 26040 for (int i = 0; i < values.length; i++) { 26041 dumpFlag(found, field.getName() + "[" + i + "]", values[i]); 26042 } 26043 } 26044 } 26045 } 26046 } catch (IllegalAccessException e) { 26047 throw new RuntimeException(e); 26048 } 26049 26050 final ArrayList<String> keys = Lists.newArrayList(); 26051 keys.addAll(found.keySet()); 26052 Collections.sort(keys); 26053 for (String key : keys) { 26054 Log.d(VIEW_LOG_TAG, found.get(key)); 26055 } 26056 } 26057 26058 private static void dumpFlag(HashMap<String, String> found, String name, int value) { 26059 // Sort flags by prefix, then by bits, always keeping unique keys 26060 final String bits = String.format("%32s", Integer.toBinaryString(value)).replace('0', ' '); 26061 final int prefix = name.indexOf('_'); 26062 final String key = (prefix > 0 ? name.substring(0, prefix) : name) + bits + name; 26063 final String output = bits + " " + name; 26064 found.put(key, output); 26065 } 26066 26067 /** {@hide} */ 26068 public void encode(@NonNull ViewHierarchyEncoder stream) { 26069 stream.beginObject(this); 26070 encodeProperties(stream); 26071 stream.endObject(); 26072 } 26073 26074 /** {@hide} */ 26075 @CallSuper 26076 protected void encodeProperties(@NonNull ViewHierarchyEncoder stream) { 26077 Object resolveId = ViewDebug.resolveId(getContext(), mID); 26078 if (resolveId instanceof String) { 26079 stream.addProperty("id", (String) resolveId); 26080 } else { 26081 stream.addProperty("id", mID); 26082 } 26083 26084 stream.addProperty("misc:transformation.alpha", 26085 mTransformationInfo != null ? mTransformationInfo.mAlpha : 0); 26086 stream.addProperty("misc:transitionName", getTransitionName()); 26087 26088 // layout 26089 stream.addProperty("layout:left", mLeft); 26090 stream.addProperty("layout:right", mRight); 26091 stream.addProperty("layout:top", mTop); 26092 stream.addProperty("layout:bottom", mBottom); 26093 stream.addProperty("layout:width", getWidth()); 26094 stream.addProperty("layout:height", getHeight()); 26095 stream.addProperty("layout:layoutDirection", getLayoutDirection()); 26096 stream.addProperty("layout:layoutRtl", isLayoutRtl()); 26097 stream.addProperty("layout:hasTransientState", hasTransientState()); 26098 stream.addProperty("layout:baseline", getBaseline()); 26099 26100 // layout params 26101 ViewGroup.LayoutParams layoutParams = getLayoutParams(); 26102 if (layoutParams != null) { 26103 stream.addPropertyKey("layoutParams"); 26104 layoutParams.encode(stream); 26105 } 26106 26107 // scrolling 26108 stream.addProperty("scrolling:scrollX", mScrollX); 26109 stream.addProperty("scrolling:scrollY", mScrollY); 26110 26111 // padding 26112 stream.addProperty("padding:paddingLeft", mPaddingLeft); 26113 stream.addProperty("padding:paddingRight", mPaddingRight); 26114 stream.addProperty("padding:paddingTop", mPaddingTop); 26115 stream.addProperty("padding:paddingBottom", mPaddingBottom); 26116 stream.addProperty("padding:userPaddingRight", mUserPaddingRight); 26117 stream.addProperty("padding:userPaddingLeft", mUserPaddingLeft); 26118 stream.addProperty("padding:userPaddingBottom", mUserPaddingBottom); 26119 stream.addProperty("padding:userPaddingStart", mUserPaddingStart); 26120 stream.addProperty("padding:userPaddingEnd", mUserPaddingEnd); 26121 26122 // measurement 26123 stream.addProperty("measurement:minHeight", mMinHeight); 26124 stream.addProperty("measurement:minWidth", mMinWidth); 26125 stream.addProperty("measurement:measuredWidth", mMeasuredWidth); 26126 stream.addProperty("measurement:measuredHeight", mMeasuredHeight); 26127 26128 // drawing 26129 stream.addProperty("drawing:elevation", getElevation()); 26130 stream.addProperty("drawing:translationX", getTranslationX()); 26131 stream.addProperty("drawing:translationY", getTranslationY()); 26132 stream.addProperty("drawing:translationZ", getTranslationZ()); 26133 stream.addProperty("drawing:rotation", getRotation()); 26134 stream.addProperty("drawing:rotationX", getRotationX()); 26135 stream.addProperty("drawing:rotationY", getRotationY()); 26136 stream.addProperty("drawing:scaleX", getScaleX()); 26137 stream.addProperty("drawing:scaleY", getScaleY()); 26138 stream.addProperty("drawing:pivotX", getPivotX()); 26139 stream.addProperty("drawing:pivotY", getPivotY()); 26140 stream.addProperty("drawing:opaque", isOpaque()); 26141 stream.addProperty("drawing:alpha", getAlpha()); 26142 stream.addProperty("drawing:transitionAlpha", getTransitionAlpha()); 26143 stream.addProperty("drawing:shadow", hasShadow()); 26144 stream.addProperty("drawing:solidColor", getSolidColor()); 26145 stream.addProperty("drawing:layerType", mLayerType); 26146 stream.addProperty("drawing:willNotDraw", willNotDraw()); 26147 stream.addProperty("drawing:hardwareAccelerated", isHardwareAccelerated()); 26148 stream.addProperty("drawing:willNotCacheDrawing", willNotCacheDrawing()); 26149 stream.addProperty("drawing:drawingCacheEnabled", isDrawingCacheEnabled()); 26150 stream.addProperty("drawing:overlappingRendering", hasOverlappingRendering()); 26151 26152 // focus 26153 stream.addProperty("focus:hasFocus", hasFocus()); 26154 stream.addProperty("focus:isFocused", isFocused()); 26155 stream.addProperty("focus:focusable", getFocusable()); 26156 stream.addProperty("focus:isFocusable", isFocusable()); 26157 stream.addProperty("focus:isFocusableInTouchMode", isFocusableInTouchMode()); 26158 26159 stream.addProperty("misc:clickable", isClickable()); 26160 stream.addProperty("misc:pressed", isPressed()); 26161 stream.addProperty("misc:selected", isSelected()); 26162 stream.addProperty("misc:touchMode", isInTouchMode()); 26163 stream.addProperty("misc:hovered", isHovered()); 26164 stream.addProperty("misc:activated", isActivated()); 26165 26166 stream.addProperty("misc:visibility", getVisibility()); 26167 stream.addProperty("misc:fitsSystemWindows", getFitsSystemWindows()); 26168 stream.addProperty("misc:filterTouchesWhenObscured", getFilterTouchesWhenObscured()); 26169 26170 stream.addProperty("misc:enabled", isEnabled()); 26171 stream.addProperty("misc:soundEffectsEnabled", isSoundEffectsEnabled()); 26172 stream.addProperty("misc:hapticFeedbackEnabled", isHapticFeedbackEnabled()); 26173 26174 // theme attributes 26175 Resources.Theme theme = getContext().getTheme(); 26176 if (theme != null) { 26177 stream.addPropertyKey("theme"); 26178 theme.encode(stream); 26179 } 26180 26181 // view attribute information 26182 int n = mAttributes != null ? mAttributes.length : 0; 26183 stream.addProperty("meta:__attrCount__", n/2); 26184 for (int i = 0; i < n; i += 2) { 26185 stream.addProperty("meta:__attr__" + mAttributes[i], mAttributes[i+1]); 26186 } 26187 26188 stream.addProperty("misc:scrollBarStyle", getScrollBarStyle()); 26189 26190 // text 26191 stream.addProperty("text:textDirection", getTextDirection()); 26192 stream.addProperty("text:textAlignment", getTextAlignment()); 26193 26194 // accessibility 26195 CharSequence contentDescription = getContentDescription(); 26196 stream.addProperty("accessibility:contentDescription", 26197 contentDescription == null ? "" : contentDescription.toString()); 26198 stream.addProperty("accessibility:labelFor", getLabelFor()); 26199 stream.addProperty("accessibility:importantForAccessibility", getImportantForAccessibility()); 26200 } 26201 26202 /** 26203 * Determine if this view is rendered on a round wearable device and is the main view 26204 * on the screen. 26205 */ 26206 boolean shouldDrawRoundScrollbar() { 26207 if (!mResources.getConfiguration().isScreenRound() || mAttachInfo == null) { 26208 return false; 26209 } 26210 26211 final View rootView = getRootView(); 26212 final WindowInsets insets = getRootWindowInsets(); 26213 26214 int height = getHeight(); 26215 int width = getWidth(); 26216 int displayHeight = rootView.getHeight(); 26217 int displayWidth = rootView.getWidth(); 26218 26219 if (height != displayHeight || width != displayWidth) { 26220 return false; 26221 } 26222 26223 getLocationInWindow(mAttachInfo.mTmpLocation); 26224 return mAttachInfo.mTmpLocation[0] == insets.getStableInsetLeft() 26225 && mAttachInfo.mTmpLocation[1] == insets.getStableInsetTop(); 26226 } 26227 26228 /** 26229 * Sets the tooltip text which will be displayed in a small popup next to the view. 26230 * <p> 26231 * The tooltip will be displayed: 26232 * <ul> 26233 * <li>On long click, unless it is handled otherwise (by OnLongClickListener or a context 26234 * menu). </li> 26235 * <li>On hover, after a brief delay since the pointer has stopped moving </li> 26236 * </ul> 26237 * <p> 26238 * <strong>Note:</strong> Do not override this method, as it will have no 26239 * effect on the text displayed in the tooltip. 26240 * 26241 * @param tooltipText the tooltip text, or null if no tooltip is required 26242 * @see #getTooltipText() 26243 * @attr ref android.R.styleable#View_tooltipText 26244 */ 26245 public void setTooltipText(@Nullable CharSequence tooltipText) { 26246 if (TextUtils.isEmpty(tooltipText)) { 26247 setFlags(0, TOOLTIP); 26248 hideTooltip(); 26249 mTooltipInfo = null; 26250 } else { 26251 setFlags(TOOLTIP, TOOLTIP); 26252 if (mTooltipInfo == null) { 26253 mTooltipInfo = new TooltipInfo(); 26254 mTooltipInfo.mShowTooltipRunnable = this::showHoverTooltip; 26255 mTooltipInfo.mHideTooltipRunnable = this::hideTooltip; 26256 } 26257 mTooltipInfo.mTooltipText = tooltipText; 26258 } 26259 } 26260 26261 /** 26262 * @hide Binary compatibility stub. To be removed when we finalize O APIs. 26263 */ 26264 public void setTooltip(@Nullable CharSequence tooltipText) { 26265 setTooltipText(tooltipText); 26266 } 26267 26268 /** 26269 * Returns the view's tooltip text. 26270 * 26271 * <strong>Note:</strong> Do not override this method, as it will have no 26272 * effect on the text displayed in the tooltip. You must call 26273 * {@link #setTooltipText(CharSequence)} to modify the tooltip text. 26274 * 26275 * @return the tooltip text 26276 * @see #setTooltipText(CharSequence) 26277 * @attr ref android.R.styleable#View_tooltipText 26278 */ 26279 @Nullable 26280 public CharSequence getTooltipText() { 26281 return mTooltipInfo != null ? mTooltipInfo.mTooltipText : null; 26282 } 26283 26284 /** 26285 * @hide Binary compatibility stub. To be removed when we finalize O APIs. 26286 */ 26287 @Nullable 26288 public CharSequence getTooltip() { 26289 return getTooltipText(); 26290 } 26291 26292 private boolean showTooltip(int x, int y, boolean fromLongClick) { 26293 if (mAttachInfo == null || mTooltipInfo == null) { 26294 return false; 26295 } 26296 if ((mViewFlags & ENABLED_MASK) != ENABLED) { 26297 return false; 26298 } 26299 if (TextUtils.isEmpty(mTooltipInfo.mTooltipText)) { 26300 return false; 26301 } 26302 hideTooltip(); 26303 mTooltipInfo.mTooltipFromLongClick = fromLongClick; 26304 mTooltipInfo.mTooltipPopup = new TooltipPopup(getContext()); 26305 final boolean fromTouch = (mPrivateFlags3 & PFLAG3_FINGER_DOWN) == PFLAG3_FINGER_DOWN; 26306 mTooltipInfo.mTooltipPopup.show(this, x, y, fromTouch, mTooltipInfo.mTooltipText); 26307 mAttachInfo.mTooltipHost = this; 26308 return true; 26309 } 26310 26311 void hideTooltip() { 26312 if (mTooltipInfo == null) { 26313 return; 26314 } 26315 removeCallbacks(mTooltipInfo.mShowTooltipRunnable); 26316 if (mTooltipInfo.mTooltipPopup == null) { 26317 return; 26318 } 26319 mTooltipInfo.mTooltipPopup.hide(); 26320 mTooltipInfo.mTooltipPopup = null; 26321 mTooltipInfo.mTooltipFromLongClick = false; 26322 if (mAttachInfo != null) { 26323 mAttachInfo.mTooltipHost = null; 26324 } 26325 } 26326 26327 private boolean showLongClickTooltip(int x, int y) { 26328 removeCallbacks(mTooltipInfo.mShowTooltipRunnable); 26329 removeCallbacks(mTooltipInfo.mHideTooltipRunnable); 26330 return showTooltip(x, y, true); 26331 } 26332 26333 private void showHoverTooltip() { 26334 showTooltip(mTooltipInfo.mAnchorX, mTooltipInfo.mAnchorY, false); 26335 } 26336 26337 boolean dispatchTooltipHoverEvent(MotionEvent event) { 26338 if (mTooltipInfo == null) { 26339 return false; 26340 } 26341 switch(event.getAction()) { 26342 case MotionEvent.ACTION_HOVER_MOVE: 26343 if ((mViewFlags & TOOLTIP) != TOOLTIP || (mViewFlags & ENABLED_MASK) != ENABLED) { 26344 break; 26345 } 26346 if (!mTooltipInfo.mTooltipFromLongClick) { 26347 if (mTooltipInfo.mTooltipPopup == null) { 26348 // Schedule showing the tooltip after a timeout. 26349 mTooltipInfo.mAnchorX = (int) event.getX(); 26350 mTooltipInfo.mAnchorY = (int) event.getY(); 26351 removeCallbacks(mTooltipInfo.mShowTooltipRunnable); 26352 postDelayed(mTooltipInfo.mShowTooltipRunnable, 26353 ViewConfiguration.getHoverTooltipShowTimeout()); 26354 } 26355 26356 // Hide hover-triggered tooltip after a period of inactivity. 26357 // Match the timeout used by NativeInputManager to hide the mouse pointer 26358 // (depends on SYSTEM_UI_FLAG_LOW_PROFILE being set). 26359 final int timeout; 26360 if ((getWindowSystemUiVisibility() & SYSTEM_UI_FLAG_LOW_PROFILE) 26361 == SYSTEM_UI_FLAG_LOW_PROFILE) { 26362 timeout = ViewConfiguration.getHoverTooltipHideShortTimeout(); 26363 } else { 26364 timeout = ViewConfiguration.getHoverTooltipHideTimeout(); 26365 } 26366 removeCallbacks(mTooltipInfo.mHideTooltipRunnable); 26367 postDelayed(mTooltipInfo.mHideTooltipRunnable, timeout); 26368 } 26369 return true; 26370 26371 case MotionEvent.ACTION_HOVER_EXIT: 26372 if (!mTooltipInfo.mTooltipFromLongClick) { 26373 hideTooltip(); 26374 } 26375 break; 26376 } 26377 return false; 26378 } 26379 26380 void handleTooltipKey(KeyEvent event) { 26381 switch (event.getAction()) { 26382 case KeyEvent.ACTION_DOWN: 26383 if (event.getRepeatCount() == 0) { 26384 hideTooltip(); 26385 } 26386 break; 26387 26388 case KeyEvent.ACTION_UP: 26389 handleTooltipUp(); 26390 break; 26391 } 26392 } 26393 26394 private void handleTooltipUp() { 26395 if (mTooltipInfo == null || mTooltipInfo.mTooltipPopup == null) { 26396 return; 26397 } 26398 removeCallbacks(mTooltipInfo.mHideTooltipRunnable); 26399 postDelayed(mTooltipInfo.mHideTooltipRunnable, 26400 ViewConfiguration.getLongPressTooltipHideTimeout()); 26401 } 26402 26403 private int getFocusableAttribute(TypedArray attributes) { 26404 TypedValue val = new TypedValue(); 26405 if (attributes.getValue(com.android.internal.R.styleable.View_focusable, val)) { 26406 if (val.type == TypedValue.TYPE_INT_BOOLEAN) { 26407 return (val.data == 0 ? NOT_FOCUSABLE : FOCUSABLE); 26408 } else { 26409 return val.data; 26410 } 26411 } else { 26412 return FOCUSABLE_AUTO; 26413 } 26414 } 26415 26416 /** 26417 * @return The content view of the tooltip popup currently being shown, or null if the tooltip 26418 * is not showing. 26419 * @hide 26420 */ 26421 @TestApi 26422 public View getTooltipView() { 26423 if (mTooltipInfo == null || mTooltipInfo.mTooltipPopup == null) { 26424 return null; 26425 } 26426 return mTooltipInfo.mTooltipPopup.getContentView(); 26427 } 26428} 26429