View.java revision 85d1c2d2905362b984563d9b5e8332010c272fc5
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.AutofillManager; 104import android.view.autofill.AutofillValue; 105import android.view.inputmethod.EditorInfo; 106import android.view.inputmethod.InputConnection; 107import android.view.inputmethod.InputMethodManager; 108import android.widget.Checkable; 109import android.widget.FrameLayout; 110import android.widget.ScrollBarDrawable; 111 112import com.android.internal.R; 113import com.android.internal.view.TooltipPopup; 114import com.android.internal.view.menu.MenuBuilder; 115import com.android.internal.widget.ScrollBarUtils; 116 117import com.google.android.collect.Lists; 118import com.google.android.collect.Maps; 119 120import java.lang.annotation.Retention; 121import java.lang.annotation.RetentionPolicy; 122import java.lang.ref.WeakReference; 123import java.lang.reflect.Field; 124import java.lang.reflect.InvocationTargetException; 125import java.lang.reflect.Method; 126import java.lang.reflect.Modifier; 127import java.util.ArrayList; 128import java.util.Arrays; 129import java.util.Collection; 130import java.util.Collections; 131import java.util.HashMap; 132import java.util.List; 133import java.util.Locale; 134import java.util.Map; 135import java.util.concurrent.CopyOnWriteArrayList; 136import java.util.concurrent.atomic.AtomicInteger; 137import java.util.function.Predicate; 138 139/** 140 * <p> 141 * This class represents the basic building block for user interface components. A View 142 * occupies a rectangular area on the screen and is responsible for drawing and 143 * event handling. View is the base class for <em>widgets</em>, which are 144 * used to create interactive UI components (buttons, text fields, etc.). The 145 * {@link android.view.ViewGroup} subclass is the base class for <em>layouts</em>, which 146 * are invisible containers that hold other Views (or other ViewGroups) and define 147 * their layout properties. 148 * </p> 149 * 150 * <div class="special reference"> 151 * <h3>Developer Guides</h3> 152 * <p>For information about using this class to develop your application's user interface, 153 * read the <a href="{@docRoot}guide/topics/ui/index.html">User Interface</a> developer guide. 154 * </div> 155 * 156 * <a name="Using"></a> 157 * <h3>Using Views</h3> 158 * <p> 159 * All of the views in a window are arranged in a single tree. You can add views 160 * either from code or by specifying a tree of views in one or more XML layout 161 * files. There are many specialized subclasses of views that act as controls or 162 * are capable of displaying text, images, or other content. 163 * </p> 164 * <p> 165 * Once you have created a tree of views, there are typically a few types of 166 * common operations you may wish to perform: 167 * <ul> 168 * <li><strong>Set properties:</strong> for example setting the text of a 169 * {@link android.widget.TextView}. The available properties and the methods 170 * that set them will vary among the different subclasses of views. Note that 171 * properties that are known at build time can be set in the XML layout 172 * files.</li> 173 * <li><strong>Set focus:</strong> The framework will handle moving focus in 174 * response to user input. To force focus to a specific view, call 175 * {@link #requestFocus}.</li> 176 * <li><strong>Set up listeners:</strong> Views allow clients to set listeners 177 * that will be notified when something interesting happens to the view. For 178 * example, all views will let you set a listener to be notified when the view 179 * gains or loses focus. You can register such a listener using 180 * {@link #setOnFocusChangeListener(android.view.View.OnFocusChangeListener)}. 181 * Other view subclasses offer more specialized listeners. For example, a Button 182 * exposes a listener to notify clients when the button is clicked.</li> 183 * <li><strong>Set visibility:</strong> You can hide or show views using 184 * {@link #setVisibility(int)}.</li> 185 * </ul> 186 * </p> 187 * <p><em> 188 * Note: The Android framework is responsible for measuring, laying out and 189 * drawing views. You should not call methods that perform these actions on 190 * views yourself unless you are actually implementing a 191 * {@link android.view.ViewGroup}. 192 * </em></p> 193 * 194 * <a name="Lifecycle"></a> 195 * <h3>Implementing a Custom View</h3> 196 * 197 * <p> 198 * To implement a custom view, you will usually begin by providing overrides for 199 * some of the standard methods that the framework calls on all views. You do 200 * not need to override all of these methods. In fact, you can start by just 201 * overriding {@link #onDraw(android.graphics.Canvas)}. 202 * <table border="2" width="85%" align="center" cellpadding="5"> 203 * <thead> 204 * <tr><th>Category</th> <th>Methods</th> <th>Description</th></tr> 205 * </thead> 206 * 207 * <tbody> 208 * <tr> 209 * <td rowspan="2">Creation</td> 210 * <td>Constructors</td> 211 * <td>There is a form of the constructor that are called when the view 212 * is created from code and a form that is called when the view is 213 * inflated from a layout file. The second form should parse and apply 214 * any attributes defined in the layout file. 215 * </td> 216 * </tr> 217 * <tr> 218 * <td><code>{@link #onFinishInflate()}</code></td> 219 * <td>Called after a view and all of its children has been inflated 220 * from XML.</td> 221 * </tr> 222 * 223 * <tr> 224 * <td rowspan="3">Layout</td> 225 * <td><code>{@link #onMeasure(int, int)}</code></td> 226 * <td>Called to determine the size requirements for this view and all 227 * of its children. 228 * </td> 229 * </tr> 230 * <tr> 231 * <td><code>{@link #onLayout(boolean, int, int, int, int)}</code></td> 232 * <td>Called when this view should assign a size and position to all 233 * of its children. 234 * </td> 235 * </tr> 236 * <tr> 237 * <td><code>{@link #onSizeChanged(int, int, int, int)}</code></td> 238 * <td>Called when the size of this view has changed. 239 * </td> 240 * </tr> 241 * 242 * <tr> 243 * <td>Drawing</td> 244 * <td><code>{@link #onDraw(android.graphics.Canvas)}</code></td> 245 * <td>Called when the view should render its content. 246 * </td> 247 * </tr> 248 * 249 * <tr> 250 * <td rowspan="4">Event processing</td> 251 * <td><code>{@link #onKeyDown(int, KeyEvent)}</code></td> 252 * <td>Called when a new hardware key event occurs. 253 * </td> 254 * </tr> 255 * <tr> 256 * <td><code>{@link #onKeyUp(int, KeyEvent)}</code></td> 257 * <td>Called when a hardware key up event occurs. 258 * </td> 259 * </tr> 260 * <tr> 261 * <td><code>{@link #onTrackballEvent(MotionEvent)}</code></td> 262 * <td>Called when a trackball motion event occurs. 263 * </td> 264 * </tr> 265 * <tr> 266 * <td><code>{@link #onTouchEvent(MotionEvent)}</code></td> 267 * <td>Called when a touch screen motion event occurs. 268 * </td> 269 * </tr> 270 * 271 * <tr> 272 * <td rowspan="2">Focus</td> 273 * <td><code>{@link #onFocusChanged(boolean, int, android.graphics.Rect)}</code></td> 274 * <td>Called when the view gains or loses focus. 275 * </td> 276 * </tr> 277 * 278 * <tr> 279 * <td><code>{@link #onWindowFocusChanged(boolean)}</code></td> 280 * <td>Called when the window containing the view gains or loses focus. 281 * </td> 282 * </tr> 283 * 284 * <tr> 285 * <td rowspan="3">Attaching</td> 286 * <td><code>{@link #onAttachedToWindow()}</code></td> 287 * <td>Called when the view is attached to a window. 288 * </td> 289 * </tr> 290 * 291 * <tr> 292 * <td><code>{@link #onDetachedFromWindow}</code></td> 293 * <td>Called when the view is detached from its window. 294 * </td> 295 * </tr> 296 * 297 * <tr> 298 * <td><code>{@link #onWindowVisibilityChanged(int)}</code></td> 299 * <td>Called when the visibility of the window containing the view 300 * has changed. 301 * </td> 302 * </tr> 303 * </tbody> 304 * 305 * </table> 306 * </p> 307 * 308 * <a name="IDs"></a> 309 * <h3>IDs</h3> 310 * Views may have an integer id associated with them. These ids are typically 311 * assigned in the layout XML files, and are used to find specific views within 312 * the view tree. A common pattern is to: 313 * <ul> 314 * <li>Define a Button in the layout file and assign it a unique ID. 315 * <pre> 316 * <Button 317 * android:id="@+id/my_button" 318 * android:layout_width="wrap_content" 319 * android:layout_height="wrap_content" 320 * android:text="@string/my_button_text"/> 321 * </pre></li> 322 * <li>From the onCreate method of an Activity, find the Button 323 * <pre class="prettyprint"> 324 * Button myButton = findViewById(R.id.my_button); 325 * </pre></li> 326 * </ul> 327 * <p> 328 * View IDs need not be unique throughout the tree, but it is good practice to 329 * ensure that they are at least unique within the part of the tree you are 330 * searching. 331 * </p> 332 * 333 * <a name="Position"></a> 334 * <h3>Position</h3> 335 * <p> 336 * The geometry of a view is that of a rectangle. A view has a location, 337 * expressed as a pair of <em>left</em> and <em>top</em> coordinates, and 338 * two dimensions, expressed as a width and a height. The unit for location 339 * and dimensions is the pixel. 340 * </p> 341 * 342 * <p> 343 * It is possible to retrieve the location of a view by invoking the methods 344 * {@link #getLeft()} and {@link #getTop()}. The former returns the left, or X, 345 * coordinate of the rectangle representing the view. The latter returns the 346 * top, or Y, coordinate of the rectangle representing the view. These methods 347 * both return the location of the view relative to its parent. For instance, 348 * when getLeft() returns 20, that means the view is located 20 pixels to the 349 * right of the left edge of its direct parent. 350 * </p> 351 * 352 * <p> 353 * In addition, several convenience methods are offered to avoid unnecessary 354 * computations, namely {@link #getRight()} and {@link #getBottom()}. 355 * These methods return the coordinates of the right and bottom edges of the 356 * rectangle representing the view. For instance, calling {@link #getRight()} 357 * is similar to the following computation: <code>getLeft() + getWidth()</code> 358 * (see <a href="#SizePaddingMargins">Size</a> for more information about the width.) 359 * </p> 360 * 361 * <a name="SizePaddingMargins"></a> 362 * <h3>Size, padding and margins</h3> 363 * <p> 364 * The size of a view is expressed with a width and a height. A view actually 365 * possess two pairs of width and height values. 366 * </p> 367 * 368 * <p> 369 * The first pair is known as <em>measured width</em> and 370 * <em>measured height</em>. These dimensions define how big a view wants to be 371 * within its parent (see <a href="#Layout">Layout</a> for more details.) The 372 * measured dimensions can be obtained by calling {@link #getMeasuredWidth()} 373 * and {@link #getMeasuredHeight()}. 374 * </p> 375 * 376 * <p> 377 * The second pair is simply known as <em>width</em> and <em>height</em>, or 378 * sometimes <em>drawing width</em> and <em>drawing height</em>. These 379 * dimensions define the actual size of the view on screen, at drawing time and 380 * after layout. These values may, but do not have to, be different from the 381 * measured width and height. The width and height can be obtained by calling 382 * {@link #getWidth()} and {@link #getHeight()}. 383 * </p> 384 * 385 * <p> 386 * To measure its dimensions, a view takes into account its padding. The padding 387 * is expressed in pixels for the left, top, right and bottom parts of the view. 388 * Padding can be used to offset the content of the view by a specific amount of 389 * pixels. For instance, a left padding of 2 will push the view's content by 390 * 2 pixels to the right of the left edge. Padding can be set using the 391 * {@link #setPadding(int, int, int, int)} or {@link #setPaddingRelative(int, int, int, int)} 392 * method and queried by calling {@link #getPaddingLeft()}, {@link #getPaddingTop()}, 393 * {@link #getPaddingRight()}, {@link #getPaddingBottom()}, {@link #getPaddingStart()}, 394 * {@link #getPaddingEnd()}. 395 * </p> 396 * 397 * <p> 398 * Even though a view can define a padding, it does not provide any support for 399 * margins. However, view groups provide such a support. Refer to 400 * {@link android.view.ViewGroup} and 401 * {@link android.view.ViewGroup.MarginLayoutParams} for further information. 402 * </p> 403 * 404 * <a name="Layout"></a> 405 * <h3>Layout</h3> 406 * <p> 407 * Layout is a two pass process: a measure pass and a layout pass. The measuring 408 * pass is implemented in {@link #measure(int, int)} and is a top-down traversal 409 * of the view tree. Each view pushes dimension specifications down the tree 410 * during the recursion. At the end of the measure pass, every view has stored 411 * its measurements. The second pass happens in 412 * {@link #layout(int,int,int,int)} and is also top-down. During 413 * this pass each parent is responsible for positioning all of its children 414 * using the sizes computed in the measure pass. 415 * </p> 416 * 417 * <p> 418 * When a view's measure() method returns, its {@link #getMeasuredWidth()} and 419 * {@link #getMeasuredHeight()} values must be set, along with those for all of 420 * that view's descendants. A view's measured width and measured height values 421 * must respect the constraints imposed by the view's parents. This guarantees 422 * that at the end of the measure pass, all parents accept all of their 423 * children's measurements. A parent view may call measure() more than once on 424 * its children. For example, the parent may measure each child once with 425 * unspecified dimensions to find out how big they want to be, then call 426 * measure() on them again with actual numbers if the sum of all the children's 427 * unconstrained sizes is too big or too small. 428 * </p> 429 * 430 * <p> 431 * The measure pass uses two classes to communicate dimensions. The 432 * {@link MeasureSpec} class is used by views to tell their parents how they 433 * want to be measured and positioned. The base LayoutParams class just 434 * describes how big the view wants to be for both width and height. For each 435 * dimension, it can specify one of: 436 * <ul> 437 * <li> an exact number 438 * <li>MATCH_PARENT, which means the view wants to be as big as its parent 439 * (minus padding) 440 * <li> WRAP_CONTENT, which means that the view wants to be just big enough to 441 * enclose its content (plus padding). 442 * </ul> 443 * There are subclasses of LayoutParams for different subclasses of ViewGroup. 444 * For example, AbsoluteLayout has its own subclass of LayoutParams which adds 445 * an X and Y value. 446 * </p> 447 * 448 * <p> 449 * MeasureSpecs are used to push requirements down the tree from parent to 450 * child. A MeasureSpec can be in one of three modes: 451 * <ul> 452 * <li>UNSPECIFIED: This is used by a parent to determine the desired dimension 453 * of a child view. For example, a LinearLayout may call measure() on its child 454 * with the height set to UNSPECIFIED and a width of EXACTLY 240 to find out how 455 * tall the child view wants to be given a width of 240 pixels. 456 * <li>EXACTLY: This is used by the parent to impose an exact size on the 457 * child. The child must use this size, and guarantee that all of its 458 * descendants will fit within this size. 459 * <li>AT_MOST: This is used by the parent to impose a maximum size on the 460 * child. The child must guarantee that it and all of its descendants will fit 461 * within this size. 462 * </ul> 463 * </p> 464 * 465 * <p> 466 * To initiate a layout, call {@link #requestLayout}. This method is typically 467 * called by a view on itself when it believes that is can no longer fit within 468 * its current bounds. 469 * </p> 470 * 471 * <a name="Drawing"></a> 472 * <h3>Drawing</h3> 473 * <p> 474 * Drawing is handled by walking the tree and recording the drawing commands of 475 * any View that needs to update. After this, the drawing commands of the 476 * entire tree are issued to screen, clipped to the newly damaged area. 477 * </p> 478 * 479 * <p> 480 * The tree is largely recorded and drawn in order, with parents drawn before 481 * (i.e., behind) their children, with siblings drawn in the order they appear 482 * in the tree. If you set a background drawable for a View, then the View will 483 * draw it before calling back to its <code>onDraw()</code> method. The child 484 * drawing order can be overridden with 485 * {@link ViewGroup#setChildrenDrawingOrderEnabled(boolean) custom child drawing order} 486 * in a ViewGroup, and with {@link #setZ(float)} custom Z values} set on Views. 487 * </p> 488 * 489 * <p> 490 * To force a view to draw, call {@link #invalidate()}. 491 * </p> 492 * 493 * <a name="EventHandlingThreading"></a> 494 * <h3>Event Handling and Threading</h3> 495 * <p> 496 * The basic cycle of a view is as follows: 497 * <ol> 498 * <li>An event comes in and is dispatched to the appropriate view. The view 499 * handles the event and notifies any listeners.</li> 500 * <li>If in the course of processing the event, the view's bounds may need 501 * to be changed, the view will call {@link #requestLayout()}.</li> 502 * <li>Similarly, if in the course of processing the event the view's appearance 503 * may need to be changed, the view will call {@link #invalidate()}.</li> 504 * <li>If either {@link #requestLayout()} or {@link #invalidate()} were called, 505 * the framework will take care of measuring, laying out, and drawing the tree 506 * as appropriate.</li> 507 * </ol> 508 * </p> 509 * 510 * <p><em>Note: The entire view tree is single threaded. You must always be on 511 * the UI thread when calling any method on any view.</em> 512 * If you are doing work on other threads and want to update the state of a view 513 * from that thread, you should use a {@link Handler}. 514 * </p> 515 * 516 * <a name="FocusHandling"></a> 517 * <h3>Focus Handling</h3> 518 * <p> 519 * The framework will handle routine focus movement in response to user input. 520 * This includes changing the focus as views are removed or hidden, or as new 521 * views become available. Views indicate their willingness to take focus 522 * through the {@link #isFocusable} method. To change whether a view can take 523 * focus, call {@link #setFocusable(boolean)}. When in touch mode (see notes below) 524 * views indicate whether they still would like focus via {@link #isFocusableInTouchMode} 525 * and can change this via {@link #setFocusableInTouchMode(boolean)}. 526 * </p> 527 * <p> 528 * Focus movement is based on an algorithm which finds the nearest neighbor in a 529 * given direction. In rare cases, the default algorithm may not match the 530 * intended behavior of the developer. In these situations, you can provide 531 * explicit overrides by using these XML attributes in the layout file: 532 * <pre> 533 * nextFocusDown 534 * nextFocusLeft 535 * nextFocusRight 536 * nextFocusUp 537 * </pre> 538 * </p> 539 * 540 * 541 * <p> 542 * To get a particular view to take focus, call {@link #requestFocus()}. 543 * </p> 544 * 545 * <a name="TouchMode"></a> 546 * <h3>Touch Mode</h3> 547 * <p> 548 * When a user is navigating a user interface via directional keys such as a D-pad, it is 549 * necessary to give focus to actionable items such as buttons so the user can see 550 * what will take input. If the device has touch capabilities, however, and the user 551 * begins interacting with the interface by touching it, it is no longer necessary to 552 * always highlight, or give focus to, a particular view. This motivates a mode 553 * for interaction named 'touch mode'. 554 * </p> 555 * <p> 556 * For a touch capable device, once the user touches the screen, the device 557 * will enter touch mode. From this point onward, only views for which 558 * {@link #isFocusableInTouchMode} is true will be focusable, such as text editing widgets. 559 * Other views that are touchable, like buttons, will not take focus when touched; they will 560 * only fire the on click listeners. 561 * </p> 562 * <p> 563 * Any time a user hits a directional key, such as a D-pad direction, the view device will 564 * exit touch mode, and find a view to take focus, so that the user may resume interacting 565 * with the user interface without touching the screen again. 566 * </p> 567 * <p> 568 * The touch mode state is maintained across {@link android.app.Activity}s. Call 569 * {@link #isInTouchMode} to see whether the device is currently in touch mode. 570 * </p> 571 * 572 * <a name="Scrolling"></a> 573 * <h3>Scrolling</h3> 574 * <p> 575 * The framework provides basic support for views that wish to internally 576 * scroll their content. This includes keeping track of the X and Y scroll 577 * offset as well as mechanisms for drawing scrollbars. See 578 * {@link #scrollBy(int, int)}, {@link #scrollTo(int, int)}, and 579 * {@link #awakenScrollBars()} for more details. 580 * </p> 581 * 582 * <a name="Tags"></a> 583 * <h3>Tags</h3> 584 * <p> 585 * Unlike IDs, tags are not used to identify views. Tags are essentially an 586 * extra piece of information that can be associated with a view. They are most 587 * often used as a convenience to store data related to views in the views 588 * themselves rather than by putting them in a separate structure. 589 * </p> 590 * <p> 591 * Tags may be specified with character sequence values in layout XML as either 592 * a single tag using the {@link android.R.styleable#View_tag android:tag} 593 * attribute or multiple tags using the {@code <tag>} child element: 594 * <pre> 595 * <View ... 596 * android:tag="@string/mytag_value" /> 597 * <View ...> 598 * <tag android:id="@+id/mytag" 599 * android:value="@string/mytag_value" /> 600 * </View> 601 * </pre> 602 * </p> 603 * <p> 604 * Tags may also be specified with arbitrary objects from code using 605 * {@link #setTag(Object)} or {@link #setTag(int, Object)}. 606 * </p> 607 * 608 * <a name="Themes"></a> 609 * <h3>Themes</h3> 610 * <p> 611 * By default, Views are created using the theme of the Context object supplied 612 * to their constructor; however, a different theme may be specified by using 613 * the {@link android.R.styleable#View_theme android:theme} attribute in layout 614 * XML or by passing a {@link ContextThemeWrapper} to the constructor from 615 * code. 616 * </p> 617 * <p> 618 * When the {@link android.R.styleable#View_theme android:theme} attribute is 619 * used in XML, the specified theme is applied on top of the inflation 620 * context's theme (see {@link LayoutInflater}) and used for the view itself as 621 * well as any child elements. 622 * </p> 623 * <p> 624 * In the following example, both views will be created using the Material dark 625 * color scheme; however, because an overlay theme is used which only defines a 626 * subset of attributes, the value of 627 * {@link android.R.styleable#Theme_colorAccent android:colorAccent} defined on 628 * the inflation context's theme (e.g. the Activity theme) will be preserved. 629 * <pre> 630 * <LinearLayout 631 * ... 632 * android:theme="@android:theme/ThemeOverlay.Material.Dark"> 633 * <View ...> 634 * </LinearLayout> 635 * </pre> 636 * </p> 637 * 638 * <a name="Properties"></a> 639 * <h3>Properties</h3> 640 * <p> 641 * The View class exposes an {@link #ALPHA} property, as well as several transform-related 642 * properties, such as {@link #TRANSLATION_X} and {@link #TRANSLATION_Y}. These properties are 643 * available both in the {@link Property} form as well as in similarly-named setter/getter 644 * methods (such as {@link #setAlpha(float)} for {@link #ALPHA}). These properties can 645 * be used to set persistent state associated with these rendering-related properties on the view. 646 * The properties and methods can also be used in conjunction with 647 * {@link android.animation.Animator Animator}-based animations, described more in the 648 * <a href="#Animation">Animation</a> section. 649 * </p> 650 * 651 * <a name="Animation"></a> 652 * <h3>Animation</h3> 653 * <p> 654 * Starting with Android 3.0, the preferred way of animating views is to use the 655 * {@link android.animation} package APIs. These {@link android.animation.Animator Animator}-based 656 * classes change actual properties of the View object, such as {@link #setAlpha(float) alpha} and 657 * {@link #setTranslationX(float) translationX}. This behavior is contrasted to that of the pre-3.0 658 * {@link android.view.animation.Animation Animation}-based classes, which instead animate only 659 * how the view is drawn on the display. In particular, the {@link ViewPropertyAnimator} class 660 * makes animating these View properties particularly easy and efficient. 661 * </p> 662 * <p> 663 * Alternatively, you can use the pre-3.0 animation classes to animate how Views are rendered. 664 * You can attach an {@link Animation} object to a view using 665 * {@link #setAnimation(Animation)} or 666 * {@link #startAnimation(Animation)}. The animation can alter the scale, 667 * rotation, translation and alpha of a view over time. If the animation is 668 * attached to a view that has children, the animation will affect the entire 669 * subtree rooted by that node. When an animation is started, the framework will 670 * take care of redrawing the appropriate views until the animation completes. 671 * </p> 672 * 673 * <a name="Security"></a> 674 * <h3>Security</h3> 675 * <p> 676 * Sometimes it is essential that an application be able to verify that an action 677 * is being performed with the full knowledge and consent of the user, such as 678 * granting a permission request, making a purchase or clicking on an advertisement. 679 * Unfortunately, a malicious application could try to spoof the user into 680 * performing these actions, unaware, by concealing the intended purpose of the view. 681 * As a remedy, the framework offers a touch filtering mechanism that can be used to 682 * improve the security of views that provide access to sensitive functionality. 683 * </p><p> 684 * To enable touch filtering, call {@link #setFilterTouchesWhenObscured(boolean)} or set the 685 * android:filterTouchesWhenObscured layout attribute to true. When enabled, the framework 686 * will discard touches that are received whenever the view's window is obscured by 687 * another visible window. As a result, the view will not receive touches whenever a 688 * toast, dialog or other window appears above the view's window. 689 * </p><p> 690 * For more fine-grained control over security, consider overriding the 691 * {@link #onFilterTouchEventForSecurity(MotionEvent)} method to implement your own 692 * security policy. See also {@link MotionEvent#FLAG_WINDOW_IS_OBSCURED}. 693 * </p> 694 * 695 * @attr ref android.R.styleable#View_alpha 696 * @attr ref android.R.styleable#View_background 697 * @attr ref android.R.styleable#View_clickable 698 * @attr ref android.R.styleable#View_contentDescription 699 * @attr ref android.R.styleable#View_drawingCacheQuality 700 * @attr ref android.R.styleable#View_duplicateParentState 701 * @attr ref android.R.styleable#View_id 702 * @attr ref android.R.styleable#View_requiresFadingEdge 703 * @attr ref android.R.styleable#View_fadeScrollbars 704 * @attr ref android.R.styleable#View_fadingEdgeLength 705 * @attr ref android.R.styleable#View_filterTouchesWhenObscured 706 * @attr ref android.R.styleable#View_fitsSystemWindows 707 * @attr ref android.R.styleable#View_isScrollContainer 708 * @attr ref android.R.styleable#View_focusable 709 * @attr ref android.R.styleable#View_focusableInTouchMode 710 * @attr ref android.R.styleable#View_focusedByDefault 711 * @attr ref android.R.styleable#View_hapticFeedbackEnabled 712 * @attr ref android.R.styleable#View_keepScreenOn 713 * @attr ref android.R.styleable#View_keyboardNavigationCluster 714 * @attr ref android.R.styleable#View_layerType 715 * @attr ref android.R.styleable#View_layoutDirection 716 * @attr ref android.R.styleable#View_longClickable 717 * @attr ref android.R.styleable#View_minHeight 718 * @attr ref android.R.styleable#View_minWidth 719 * @attr ref android.R.styleable#View_nextClusterForward 720 * @attr ref android.R.styleable#View_nextFocusDown 721 * @attr ref android.R.styleable#View_nextFocusLeft 722 * @attr ref android.R.styleable#View_nextFocusRight 723 * @attr ref android.R.styleable#View_nextFocusUp 724 * @attr ref android.R.styleable#View_onClick 725 * @attr ref android.R.styleable#View_padding 726 * @attr ref android.R.styleable#View_paddingBottom 727 * @attr ref android.R.styleable#View_paddingLeft 728 * @attr ref android.R.styleable#View_paddingRight 729 * @attr ref android.R.styleable#View_paddingTop 730 * @attr ref android.R.styleable#View_paddingStart 731 * @attr ref android.R.styleable#View_paddingEnd 732 * @attr ref android.R.styleable#View_saveEnabled 733 * @attr ref android.R.styleable#View_rotation 734 * @attr ref android.R.styleable#View_rotationX 735 * @attr ref android.R.styleable#View_rotationY 736 * @attr ref android.R.styleable#View_scaleX 737 * @attr ref android.R.styleable#View_scaleY 738 * @attr ref android.R.styleable#View_scrollX 739 * @attr ref android.R.styleable#View_scrollY 740 * @attr ref android.R.styleable#View_scrollbarSize 741 * @attr ref android.R.styleable#View_scrollbarStyle 742 * @attr ref android.R.styleable#View_scrollbars 743 * @attr ref android.R.styleable#View_scrollbarDefaultDelayBeforeFade 744 * @attr ref android.R.styleable#View_scrollbarFadeDuration 745 * @attr ref android.R.styleable#View_scrollbarTrackHorizontal 746 * @attr ref android.R.styleable#View_scrollbarThumbHorizontal 747 * @attr ref android.R.styleable#View_scrollbarThumbVertical 748 * @attr ref android.R.styleable#View_scrollbarTrackVertical 749 * @attr ref android.R.styleable#View_scrollbarAlwaysDrawHorizontalTrack 750 * @attr ref android.R.styleable#View_scrollbarAlwaysDrawVerticalTrack 751 * @attr ref android.R.styleable#View_stateListAnimator 752 * @attr ref android.R.styleable#View_transitionName 753 * @attr ref android.R.styleable#View_soundEffectsEnabled 754 * @attr ref android.R.styleable#View_tag 755 * @attr ref android.R.styleable#View_textAlignment 756 * @attr ref android.R.styleable#View_textDirection 757 * @attr ref android.R.styleable#View_transformPivotX 758 * @attr ref android.R.styleable#View_transformPivotY 759 * @attr ref android.R.styleable#View_translationX 760 * @attr ref android.R.styleable#View_translationY 761 * @attr ref android.R.styleable#View_translationZ 762 * @attr ref android.R.styleable#View_visibility 763 * @attr ref android.R.styleable#View_theme 764 * 765 * @see android.view.ViewGroup 766 */ 767@UiThread 768public class View implements Drawable.Callback, KeyEvent.Callback, 769 AccessibilityEventSource { 770 private static final boolean DBG = false; 771 772 /** @hide */ 773 public static boolean DEBUG_DRAW = false; 774 775 /** 776 * The logging tag used by this class with android.util.Log. 777 */ 778 protected static final String VIEW_LOG_TAG = "View"; 779 780 /** 781 * When set to true, apps will draw debugging information about their layouts. 782 * 783 * @hide 784 */ 785 public static final String DEBUG_LAYOUT_PROPERTY = "debug.layout"; 786 787 /** 788 * When set to true, this view will save its attribute data. 789 * 790 * @hide 791 */ 792 public static boolean mDebugViewAttributes = false; 793 794 /** 795 * Used to mark a View that has no ID. 796 */ 797 public static final int NO_ID = -1; 798 799 /** 800 * Last ID that is given to Views that are no part of activities. 801 * 802 * {@hide} 803 */ 804 public static final int LAST_APP_ACCESSIBILITY_ID = Integer.MAX_VALUE / 2; 805 806 /** 807 * Signals that compatibility booleans have been initialized according to 808 * target SDK versions. 809 */ 810 private static boolean sCompatibilityDone = false; 811 812 /** 813 * Use the old (broken) way of building MeasureSpecs. 814 */ 815 private static boolean sUseBrokenMakeMeasureSpec = false; 816 817 /** 818 * Always return a size of 0 for MeasureSpec values with a mode of UNSPECIFIED 819 */ 820 static boolean sUseZeroUnspecifiedMeasureSpec = false; 821 822 /** 823 * Ignore any optimizations using the measure cache. 824 */ 825 private static boolean sIgnoreMeasureCache = false; 826 827 /** 828 * Ignore an optimization that skips unnecessary EXACTLY layout passes. 829 */ 830 private static boolean sAlwaysRemeasureExactly = false; 831 832 /** 833 * Relax constraints around whether setLayoutParams() must be called after 834 * modifying the layout params. 835 */ 836 private static boolean sLayoutParamsAlwaysChanged = false; 837 838 /** 839 * Allow setForeground/setBackground to be called (and ignored) on a textureview, 840 * without throwing 841 */ 842 static boolean sTextureViewIgnoresDrawableSetters = false; 843 844 /** 845 * Prior to N, some ViewGroups would not convert LayoutParams properly even though both extend 846 * MarginLayoutParams. For instance, converting LinearLayout.LayoutParams to 847 * RelativeLayout.LayoutParams would lose margin information. This is fixed on N but target API 848 * check is implemented for backwards compatibility. 849 * 850 * {@hide} 851 */ 852 protected static boolean sPreserveMarginParamsInLayoutParamConversion; 853 854 /** 855 * Prior to N, when drag enters into child of a view that has already received an 856 * ACTION_DRAG_ENTERED event, the parent doesn't get a ACTION_DRAG_EXITED event. 857 * ACTION_DRAG_LOCATION and ACTION_DROP were delivered to the parent of a view that returned 858 * false from its event handler for these events. 859 * Starting from N, the parent will get ACTION_DRAG_EXITED event before the child gets its 860 * ACTION_DRAG_ENTERED. ACTION_DRAG_LOCATION and ACTION_DROP are never propagated to the parent. 861 * sCascadedDragDrop is true for pre-N apps for backwards compatibility implementation. 862 */ 863 static boolean sCascadedDragDrop; 864 865 /** 866 * Prior to O, auto-focusable didn't exist and widgets such as ListView use hasFocusable 867 * to determine things like whether or not to permit item click events. We can't break 868 * apps that do this just because more things (clickable things) are now auto-focusable 869 * and they would get different results, so give old behavior to old apps. 870 */ 871 static boolean sHasFocusableExcludeAutoFocusable; 872 873 /** 874 * Prior to O, auto-focusable didn't exist and views marked as clickable weren't implicitly 875 * made focusable by default. As a result, apps could (incorrectly) change the clickable 876 * setting of views off the UI thread. Now that clickable can effect the focusable state, 877 * changing the clickable attribute off the UI thread will cause an exception (since changing 878 * the focusable state checks). In order to prevent apps from crashing, we will handle this 879 * specific case and just not notify parents on new focusables resulting from marking views 880 * clickable from outside the UI thread. 881 */ 882 private static boolean sAutoFocusableOffUIThreadWontNotifyParents; 883 884 /** @hide */ 885 @IntDef({NOT_FOCUSABLE, FOCUSABLE, FOCUSABLE_AUTO}) 886 @Retention(RetentionPolicy.SOURCE) 887 public @interface Focusable {} 888 889 /** 890 * This view does not want keystrokes. 891 * <p> 892 * Use with {@link #setFocusable(int)} and <a href="#attr_android:focusable">{@code 893 * android:focusable}. 894 */ 895 public static final int NOT_FOCUSABLE = 0x00000000; 896 897 /** 898 * This view wants keystrokes. 899 * <p> 900 * Use with {@link #setFocusable(int)} and <a href="#attr_android:focusable">{@code 901 * android:focusable}. 902 */ 903 public static final int FOCUSABLE = 0x00000001; 904 905 /** 906 * This view determines focusability automatically. This is the default. 907 * <p> 908 * Use with {@link #setFocusable(int)} and <a href="#attr_android:focusable">{@code 909 * android:focusable}. 910 */ 911 public static final int FOCUSABLE_AUTO = 0x00000010; 912 913 /** 914 * Mask for use with setFlags indicating bits used for focus. 915 */ 916 private static final int FOCUSABLE_MASK = 0x00000011; 917 918 /** 919 * This view will adjust its padding to fit sytem windows (e.g. status bar) 920 */ 921 private static final int FITS_SYSTEM_WINDOWS = 0x00000002; 922 923 /** @hide */ 924 @IntDef({VISIBLE, INVISIBLE, GONE}) 925 @Retention(RetentionPolicy.SOURCE) 926 public @interface Visibility {} 927 928 /** 929 * This view is visible. 930 * Use with {@link #setVisibility} and <a href="#attr_android:visibility">{@code 931 * android:visibility}. 932 */ 933 public static final int VISIBLE = 0x00000000; 934 935 /** 936 * This view is invisible, but it still takes up space for layout purposes. 937 * Use with {@link #setVisibility} and <a href="#attr_android:visibility">{@code 938 * android:visibility}. 939 */ 940 public static final int INVISIBLE = 0x00000004; 941 942 /** 943 * This view is invisible, and it doesn't take any space for layout 944 * purposes. Use with {@link #setVisibility} and <a href="#attr_android:visibility">{@code 945 * android:visibility}. 946 */ 947 public static final int GONE = 0x00000008; 948 949 /** 950 * Mask for use with setFlags indicating bits used for visibility. 951 * {@hide} 952 */ 953 static final int VISIBILITY_MASK = 0x0000000C; 954 955 private static final int[] VISIBILITY_FLAGS = {VISIBLE, INVISIBLE, GONE}; 956 957 /** 958 * This view contains an email address. 959 * 960 * Use with {@link #setAutofillHints(String[])}, or set "{@value #AUTOFILL_HINT_EMAIL_ADDRESS}" 961 * to <a href="#attr_android:autofillHint"> {@code android:autofillHint}. 962 */ 963 public static final String AUTOFILL_HINT_EMAIL_ADDRESS = "emailAddress"; 964 965 /** 966 * The view contains a real name. 967 * 968 * Use with {@link #setAutofillHints(String[])}, or set "{@value #AUTOFILL_HINT_NAME}" to 969 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}. 970 */ 971 public static final String AUTOFILL_HINT_NAME = "name"; 972 973 /** 974 * The view contains a user name. 975 * 976 * Use with {@link #setAutofillHints(String[])}, or set "{@value #AUTOFILL_HINT_USERNAME}" to 977 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}. 978 */ 979 public static final String AUTOFILL_HINT_USERNAME = "username"; 980 981 /** 982 * The view contains a password. 983 * 984 * Use with {@link #setAutofillHints(String[])}, or set "{@value #AUTOFILL_HINT_PASSWORD}" to 985 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}. 986 */ 987 public static final String AUTOFILL_HINT_PASSWORD = "password"; 988 989 /** 990 * The view contains a phone number. 991 * 992 * Use with {@link #setAutofillHints(String[])}, or set "{@value #AUTOFILL_HINT_PHONE}" to 993 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}. 994 */ 995 public static final String AUTOFILL_HINT_PHONE = "phone"; 996 997 /** 998 * The view contains a postal address. 999 * 1000 * Use with {@link #setAutofillHints(String[])}, or set "{@value #AUTOFILL_HINT_POSTAL_ADDRESS}" 1001 * to <a href="#attr_android:autofillHint"> {@code android:autofillHint}. 1002 */ 1003 public static final String AUTOFILL_HINT_POSTAL_ADDRESS = "postalAddress"; 1004 1005 /** 1006 * The view contains a postal code. 1007 * 1008 * Use with {@link #setAutofillHints(String[])}, or set "{@value #AUTOFILL_HINT_POSTAL_CODE}" to 1009 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}. 1010 */ 1011 public static final String AUTOFILL_HINT_POSTAL_CODE = "postalCode"; 1012 1013 /** 1014 * The view contains a credit card number. 1015 * 1016 * Use with {@link #setAutofillHints(String[])}, or set "{@value 1017 * #AUTOFILL_HINT_CREDIT_CARD_NUMBER}" to <a href="#attr_android:autofillHint"> {@code 1018 * android:autofillHint}. 1019 */ 1020 public static final String AUTOFILL_HINT_CREDIT_CARD_NUMBER = "creditCardNumber"; 1021 1022 /** 1023 * The view contains a credit card security code. 1024 * 1025 * Use with {@link #setAutofillHints(String[])}, or set "{@value 1026 * #AUTOFILL_HINT_CREDIT_CARD_SECURITY_CODE}" to <a href="#attr_android:autofillHint"> {@code 1027 * android:autofillHint}. 1028 */ 1029 public static final String AUTOFILL_HINT_CREDIT_CARD_SECURITY_CODE = "creditCardSecurityCode"; 1030 1031 /** 1032 * The view contains a credit card expiration date. 1033 * 1034 * Use with {@link #setAutofillHints(String[])}, or set "{@value 1035 * #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE}" to <a href="#attr_android:autofillHint"> {@code 1036 * android:autofillHint}. 1037 */ 1038 public static final String AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE = 1039 "creditCardExpirationDate"; 1040 1041 /** 1042 * The view contains the month a credit card expires. 1043 * 1044 * Use with {@link #setAutofillHints(String[])}, or set "{@value 1045 * #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH}" to <a href="#attr_android:autofillHint"> {@code 1046 * android:autofillHint}. 1047 */ 1048 public static final String AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH = 1049 "creditCardExpirationMonth"; 1050 1051 /** 1052 * The view contains the year a credit card expires. 1053 * 1054 * Use with {@link #setAutofillHints(String[])}, or set "{@value 1055 * #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR}" to <a href="#attr_android:autofillHint"> {@code 1056 * android:autofillHint}. 1057 */ 1058 public static final String AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR = 1059 "creditCardExpirationYear"; 1060 1061 /** 1062 * The view contains the day a credit card expires. 1063 * 1064 * Use with {@link #setAutofillHints(String[])}, or set "{@value 1065 * #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DAY}" to <a href="#attr_android:autofillHint"> {@code 1066 * android:autofillHint}. 1067 */ 1068 public static final String AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DAY = "creditCardExpirationDay"; 1069 1070 /** 1071 * Hintd for the autofill services that describes the content of the view. 1072 */ 1073 private @Nullable String[] mAutofillHints; 1074 1075 /** @hide */ 1076 @IntDef({ 1077 AUTOFILL_TYPE_NONE, 1078 AUTOFILL_TYPE_TEXT, 1079 AUTOFILL_TYPE_TOGGLE, 1080 AUTOFILL_TYPE_LIST, 1081 AUTOFILL_TYPE_DATE 1082 }) 1083 @Retention(RetentionPolicy.SOURCE) 1084 public @interface AutofillType {} 1085 1086 /** 1087 * Autofill type for views that cannot be autofilled. 1088 */ 1089 public static final int AUTOFILL_TYPE_NONE = 0; 1090 1091 /** 1092 * Autofill type for a text field, which is filled by a {@link CharSequence}. 1093 * 1094 * <p>{@link AutofillValue} instances for autofilling a {@link View} can be obtained through 1095 * {@link AutofillValue#forText(CharSequence)}, and the value passed to autofill a 1096 * {@link View} can be fetched through {@link AutofillValue#getTextValue()}. 1097 */ 1098 public static final int AUTOFILL_TYPE_TEXT = 1; 1099 1100 /** 1101 * Autofill type for a togglable field, which is filled by a {@code boolean}. 1102 * 1103 * <p>{@link AutofillValue} instances for autofilling a {@link View} can be obtained through 1104 * {@link AutofillValue#forToggle(boolean)}, and the value passed to autofill a 1105 * {@link View} can be fetched through {@link AutofillValue#getToggleValue()}. 1106 */ 1107 public static final int AUTOFILL_TYPE_TOGGLE = 2; 1108 1109 /** 1110 * Autofill type for a selection list field, which is filled by an {@code int} 1111 * representing the element index inside the list (starting at {@code 0}). 1112 * 1113 * <p>{@link AutofillValue} instances for autofilling a {@link View} can be obtained through 1114 * {@link AutofillValue#forList(int)}, and the value passed to autofill a 1115 * {@link View} can be fetched through {@link AutofillValue#getListValue()}. 1116 * 1117 * <p>The available options in the selection list are typically provided by 1118 * {@link android.app.assist.AssistStructure.ViewNode#getAutofillOptions()}. 1119 */ 1120 public static final int AUTOFILL_TYPE_LIST = 3; 1121 1122 1123 /** 1124 * Autofill type for a field that contains a date, which is represented by a long representing 1125 * the number of milliseconds since the standard base time known as "the epoch", namely 1126 * January 1, 1970, 00:00:00 GMT (see {@link java.util.Date#getTime()}. 1127 * 1128 * <p>{@link AutofillValue} instances for autofilling a {@link View} can be obtained through 1129 * {@link AutofillValue#forDate(long)}, and the values passed to 1130 * autofill a {@link View} can be fetched through {@link AutofillValue#getDateValue()}. 1131 */ 1132 public static final int AUTOFILL_TYPE_DATE = 4; 1133 1134 /** @hide */ 1135 @IntDef({ 1136 IMPORTANT_FOR_AUTOFILL_AUTO, 1137 IMPORTANT_FOR_AUTOFILL_YES, 1138 IMPORTANT_FOR_AUTOFILL_NO, 1139 IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS, 1140 IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS 1141 }) 1142 @Retention(RetentionPolicy.SOURCE) 1143 public @interface AutofillImportance {} 1144 1145 /** 1146 * Automatically determine whether a view is important for autofill. 1147 */ 1148 public static final int IMPORTANT_FOR_AUTOFILL_AUTO = 0x0; 1149 1150 /** 1151 * The view is important for autofill, and its children (if any) will be traversed. 1152 */ 1153 public static final int IMPORTANT_FOR_AUTOFILL_YES = 0x1; 1154 1155 /** 1156 * The view is not important for autofill, and its children (if any) will be traversed. 1157 */ 1158 public static final int IMPORTANT_FOR_AUTOFILL_NO = 0x2; 1159 1160 /** 1161 * The view is important for autofill, but its children (if any) will not be traversed. 1162 */ 1163 public static final int IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS = 0x4; 1164 1165 /** 1166 * The view is not important for autofill, and its children (if any) will not be traversed. 1167 */ 1168 public static final int IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS = 0x8; 1169 1170 /** 1171 * This view is enabled. Interpretation varies by subclass. 1172 * Use with ENABLED_MASK when calling setFlags. 1173 * {@hide} 1174 */ 1175 static final int ENABLED = 0x00000000; 1176 1177 /** 1178 * This view is disabled. Interpretation varies by subclass. 1179 * Use with ENABLED_MASK when calling setFlags. 1180 * {@hide} 1181 */ 1182 static final int DISABLED = 0x00000020; 1183 1184 /** 1185 * Mask for use with setFlags indicating bits used for indicating whether 1186 * this view is enabled 1187 * {@hide} 1188 */ 1189 static final int ENABLED_MASK = 0x00000020; 1190 1191 /** 1192 * This view won't draw. {@link #onDraw(android.graphics.Canvas)} won't be 1193 * called and further optimizations will be performed. It is okay to have 1194 * this flag set and a background. Use with DRAW_MASK when calling setFlags. 1195 * {@hide} 1196 */ 1197 static final int WILL_NOT_DRAW = 0x00000080; 1198 1199 /** 1200 * Mask for use with setFlags indicating bits used for indicating whether 1201 * this view is will draw 1202 * {@hide} 1203 */ 1204 static final int DRAW_MASK = 0x00000080; 1205 1206 /** 1207 * <p>This view doesn't show scrollbars.</p> 1208 * {@hide} 1209 */ 1210 static final int SCROLLBARS_NONE = 0x00000000; 1211 1212 /** 1213 * <p>This view shows horizontal scrollbars.</p> 1214 * {@hide} 1215 */ 1216 static final int SCROLLBARS_HORIZONTAL = 0x00000100; 1217 1218 /** 1219 * <p>This view shows vertical scrollbars.</p> 1220 * {@hide} 1221 */ 1222 static final int SCROLLBARS_VERTICAL = 0x00000200; 1223 1224 /** 1225 * <p>Mask for use with setFlags indicating bits used for indicating which 1226 * scrollbars are enabled.</p> 1227 * {@hide} 1228 */ 1229 static final int SCROLLBARS_MASK = 0x00000300; 1230 1231 /** 1232 * Indicates that the view should filter touches when its window is obscured. 1233 * Refer to the class comments for more information about this security feature. 1234 * {@hide} 1235 */ 1236 static final int FILTER_TOUCHES_WHEN_OBSCURED = 0x00000400; 1237 1238 /** 1239 * Set for framework elements that use FITS_SYSTEM_WINDOWS, to indicate 1240 * that they are optional and should be skipped if the window has 1241 * requested system UI flags that ignore those insets for layout. 1242 */ 1243 static final int OPTIONAL_FITS_SYSTEM_WINDOWS = 0x00000800; 1244 1245 /** 1246 * <p>This view doesn't show fading edges.</p> 1247 * {@hide} 1248 */ 1249 static final int FADING_EDGE_NONE = 0x00000000; 1250 1251 /** 1252 * <p>This view shows horizontal fading edges.</p> 1253 * {@hide} 1254 */ 1255 static final int FADING_EDGE_HORIZONTAL = 0x00001000; 1256 1257 /** 1258 * <p>This view shows vertical fading edges.</p> 1259 * {@hide} 1260 */ 1261 static final int FADING_EDGE_VERTICAL = 0x00002000; 1262 1263 /** 1264 * <p>Mask for use with setFlags indicating bits used for indicating which 1265 * fading edges are enabled.</p> 1266 * {@hide} 1267 */ 1268 static final int FADING_EDGE_MASK = 0x00003000; 1269 1270 /** 1271 * <p>Indicates this view can be clicked. When clickable, a View reacts 1272 * to clicks by notifying the OnClickListener.<p> 1273 * {@hide} 1274 */ 1275 static final int CLICKABLE = 0x00004000; 1276 1277 /** 1278 * <p>Indicates this view is caching its drawing into a bitmap.</p> 1279 * {@hide} 1280 */ 1281 static final int DRAWING_CACHE_ENABLED = 0x00008000; 1282 1283 /** 1284 * <p>Indicates that no icicle should be saved for this view.<p> 1285 * {@hide} 1286 */ 1287 static final int SAVE_DISABLED = 0x000010000; 1288 1289 /** 1290 * <p>Mask for use with setFlags indicating bits used for the saveEnabled 1291 * property.</p> 1292 * {@hide} 1293 */ 1294 static final int SAVE_DISABLED_MASK = 0x000010000; 1295 1296 /** 1297 * <p>Indicates that no drawing cache should ever be created for this view.<p> 1298 * {@hide} 1299 */ 1300 static final int WILL_NOT_CACHE_DRAWING = 0x000020000; 1301 1302 /** 1303 * <p>Indicates this view can take / keep focus when int touch mode.</p> 1304 * {@hide} 1305 */ 1306 static final int FOCUSABLE_IN_TOUCH_MODE = 0x00040000; 1307 1308 /** @hide */ 1309 @Retention(RetentionPolicy.SOURCE) 1310 @IntDef({DRAWING_CACHE_QUALITY_LOW, DRAWING_CACHE_QUALITY_HIGH, DRAWING_CACHE_QUALITY_AUTO}) 1311 public @interface DrawingCacheQuality {} 1312 1313 /** 1314 * <p>Enables low quality mode for the drawing cache.</p> 1315 */ 1316 public static final int DRAWING_CACHE_QUALITY_LOW = 0x00080000; 1317 1318 /** 1319 * <p>Enables high quality mode for the drawing cache.</p> 1320 */ 1321 public static final int DRAWING_CACHE_QUALITY_HIGH = 0x00100000; 1322 1323 /** 1324 * <p>Enables automatic quality mode for the drawing cache.</p> 1325 */ 1326 public static final int DRAWING_CACHE_QUALITY_AUTO = 0x00000000; 1327 1328 private static final int[] DRAWING_CACHE_QUALITY_FLAGS = { 1329 DRAWING_CACHE_QUALITY_AUTO, DRAWING_CACHE_QUALITY_LOW, DRAWING_CACHE_QUALITY_HIGH 1330 }; 1331 1332 /** 1333 * <p>Mask for use with setFlags indicating bits used for the cache 1334 * quality property.</p> 1335 * {@hide} 1336 */ 1337 static final int DRAWING_CACHE_QUALITY_MASK = 0x00180000; 1338 1339 /** 1340 * <p> 1341 * Indicates this view can be long clicked. When long clickable, a View 1342 * reacts to long clicks by notifying the OnLongClickListener or showing a 1343 * context menu. 1344 * </p> 1345 * {@hide} 1346 */ 1347 static final int LONG_CLICKABLE = 0x00200000; 1348 1349 /** 1350 * <p>Indicates that this view gets its drawable states from its direct parent 1351 * and ignores its original internal states.</p> 1352 * 1353 * @hide 1354 */ 1355 static final int DUPLICATE_PARENT_STATE = 0x00400000; 1356 1357 /** 1358 * <p> 1359 * Indicates this view can be context clicked. When context clickable, a View reacts to a 1360 * context click (e.g. a primary stylus button press or right mouse click) by notifying the 1361 * OnContextClickListener. 1362 * </p> 1363 * {@hide} 1364 */ 1365 static final int CONTEXT_CLICKABLE = 0x00800000; 1366 1367 1368 /** @hide */ 1369 @IntDef({ 1370 SCROLLBARS_INSIDE_OVERLAY, 1371 SCROLLBARS_INSIDE_INSET, 1372 SCROLLBARS_OUTSIDE_OVERLAY, 1373 SCROLLBARS_OUTSIDE_INSET 1374 }) 1375 @Retention(RetentionPolicy.SOURCE) 1376 public @interface ScrollBarStyle {} 1377 1378 /** 1379 * The scrollbar style to display the scrollbars inside the content area, 1380 * without increasing the padding. The scrollbars will be overlaid with 1381 * translucency on the view's content. 1382 */ 1383 public static final int SCROLLBARS_INSIDE_OVERLAY = 0; 1384 1385 /** 1386 * The scrollbar style to display the scrollbars inside the padded area, 1387 * increasing the padding of the view. The scrollbars will not overlap the 1388 * content area of the view. 1389 */ 1390 public static final int SCROLLBARS_INSIDE_INSET = 0x01000000; 1391 1392 /** 1393 * The scrollbar style to display the scrollbars at the edge of the view, 1394 * without increasing the padding. The scrollbars will be overlaid with 1395 * translucency. 1396 */ 1397 public static final int SCROLLBARS_OUTSIDE_OVERLAY = 0x02000000; 1398 1399 /** 1400 * The scrollbar style to display the scrollbars at the edge of the view, 1401 * increasing the padding of the view. The scrollbars will only overlap the 1402 * background, if any. 1403 */ 1404 public static final int SCROLLBARS_OUTSIDE_INSET = 0x03000000; 1405 1406 /** 1407 * Mask to check if the scrollbar style is overlay or inset. 1408 * {@hide} 1409 */ 1410 static final int SCROLLBARS_INSET_MASK = 0x01000000; 1411 1412 /** 1413 * Mask to check if the scrollbar style is inside or outside. 1414 * {@hide} 1415 */ 1416 static final int SCROLLBARS_OUTSIDE_MASK = 0x02000000; 1417 1418 /** 1419 * Mask for scrollbar style. 1420 * {@hide} 1421 */ 1422 static final int SCROLLBARS_STYLE_MASK = 0x03000000; 1423 1424 /** 1425 * View flag indicating that the screen should remain on while the 1426 * window containing this view is visible to the user. This effectively 1427 * takes care of automatically setting the WindowManager's 1428 * {@link WindowManager.LayoutParams#FLAG_KEEP_SCREEN_ON}. 1429 */ 1430 public static final int KEEP_SCREEN_ON = 0x04000000; 1431 1432 /** 1433 * View flag indicating whether this view should have sound effects enabled 1434 * for events such as clicking and touching. 1435 */ 1436 public static final int SOUND_EFFECTS_ENABLED = 0x08000000; 1437 1438 /** 1439 * View flag indicating whether this view should have haptic feedback 1440 * enabled for events such as long presses. 1441 */ 1442 public static final int HAPTIC_FEEDBACK_ENABLED = 0x10000000; 1443 1444 /** 1445 * <p>Indicates that the view hierarchy should stop saving state when 1446 * it reaches this view. If state saving is initiated immediately at 1447 * the view, it will be allowed. 1448 * {@hide} 1449 */ 1450 static final int PARENT_SAVE_DISABLED = 0x20000000; 1451 1452 /** 1453 * <p>Mask for use with setFlags indicating bits used for PARENT_SAVE_DISABLED.</p> 1454 * {@hide} 1455 */ 1456 static final int PARENT_SAVE_DISABLED_MASK = 0x20000000; 1457 1458 private static Paint sDebugPaint; 1459 1460 /** 1461 * <p>Indicates this view can display a tooltip on hover or long press.</p> 1462 * {@hide} 1463 */ 1464 static final int TOOLTIP = 0x40000000; 1465 1466 /** @hide */ 1467 @IntDef(flag = true, 1468 value = { 1469 FOCUSABLES_ALL, 1470 FOCUSABLES_TOUCH_MODE 1471 }) 1472 @Retention(RetentionPolicy.SOURCE) 1473 public @interface FocusableMode {} 1474 1475 /** 1476 * View flag indicating whether {@link #addFocusables(ArrayList, int, int)} 1477 * should add all focusable Views regardless if they are focusable in touch mode. 1478 */ 1479 public static final int FOCUSABLES_ALL = 0x00000000; 1480 1481 /** 1482 * View flag indicating whether {@link #addFocusables(ArrayList, int, int)} 1483 * should add only Views focusable in touch mode. 1484 */ 1485 public static final int FOCUSABLES_TOUCH_MODE = 0x00000001; 1486 1487 /** @hide */ 1488 @IntDef({ 1489 FOCUS_BACKWARD, 1490 FOCUS_FORWARD, 1491 FOCUS_LEFT, 1492 FOCUS_UP, 1493 FOCUS_RIGHT, 1494 FOCUS_DOWN 1495 }) 1496 @Retention(RetentionPolicy.SOURCE) 1497 public @interface FocusDirection {} 1498 1499 /** @hide */ 1500 @IntDef({ 1501 FOCUS_LEFT, 1502 FOCUS_UP, 1503 FOCUS_RIGHT, 1504 FOCUS_DOWN 1505 }) 1506 @Retention(RetentionPolicy.SOURCE) 1507 public @interface FocusRealDirection {} // Like @FocusDirection, but without forward/backward 1508 1509 /** 1510 * Use with {@link #focusSearch(int)}. Move focus to the previous selectable 1511 * item. 1512 */ 1513 public static final int FOCUS_BACKWARD = 0x00000001; 1514 1515 /** 1516 * Use with {@link #focusSearch(int)}. Move focus to the next selectable 1517 * item. 1518 */ 1519 public static final int FOCUS_FORWARD = 0x00000002; 1520 1521 /** 1522 * Use with {@link #focusSearch(int)}. Move focus to the left. 1523 */ 1524 public static final int FOCUS_LEFT = 0x00000011; 1525 1526 /** 1527 * Use with {@link #focusSearch(int)}. Move focus up. 1528 */ 1529 public static final int FOCUS_UP = 0x00000021; 1530 1531 /** 1532 * Use with {@link #focusSearch(int)}. Move focus to the right. 1533 */ 1534 public static final int FOCUS_RIGHT = 0x00000042; 1535 1536 /** 1537 * Use with {@link #focusSearch(int)}. Move focus down. 1538 */ 1539 public static final int FOCUS_DOWN = 0x00000082; 1540 1541 /** 1542 * Bits of {@link #getMeasuredWidthAndState()} and 1543 * {@link #getMeasuredWidthAndState()} that provide the actual measured size. 1544 */ 1545 public static final int MEASURED_SIZE_MASK = 0x00ffffff; 1546 1547 /** 1548 * Bits of {@link #getMeasuredWidthAndState()} and 1549 * {@link #getMeasuredWidthAndState()} that provide the additional state bits. 1550 */ 1551 public static final int MEASURED_STATE_MASK = 0xff000000; 1552 1553 /** 1554 * Bit shift of {@link #MEASURED_STATE_MASK} to get to the height bits 1555 * for functions that combine both width and height into a single int, 1556 * such as {@link #getMeasuredState()} and the childState argument of 1557 * {@link #resolveSizeAndState(int, int, int)}. 1558 */ 1559 public static final int MEASURED_HEIGHT_STATE_SHIFT = 16; 1560 1561 /** 1562 * Bit of {@link #getMeasuredWidthAndState()} and 1563 * {@link #getMeasuredWidthAndState()} that indicates the measured size 1564 * is smaller that the space the view would like to have. 1565 */ 1566 public static final int MEASURED_STATE_TOO_SMALL = 0x01000000; 1567 1568 /** 1569 * Base View state sets 1570 */ 1571 // Singles 1572 /** 1573 * Indicates the view has no states set. States are used with 1574 * {@link android.graphics.drawable.Drawable} to change the drawing of the 1575 * view depending on its state. 1576 * 1577 * @see android.graphics.drawable.Drawable 1578 * @see #getDrawableState() 1579 */ 1580 protected static final int[] EMPTY_STATE_SET; 1581 /** 1582 * Indicates the view is enabled. States are used with 1583 * {@link android.graphics.drawable.Drawable} to change the drawing of the 1584 * view depending on its state. 1585 * 1586 * @see android.graphics.drawable.Drawable 1587 * @see #getDrawableState() 1588 */ 1589 protected static final int[] ENABLED_STATE_SET; 1590 /** 1591 * Indicates the view is focused. States are used with 1592 * {@link android.graphics.drawable.Drawable} to change the drawing of the 1593 * view depending on its state. 1594 * 1595 * @see android.graphics.drawable.Drawable 1596 * @see #getDrawableState() 1597 */ 1598 protected static final int[] FOCUSED_STATE_SET; 1599 /** 1600 * Indicates the view is selected. States are used with 1601 * {@link android.graphics.drawable.Drawable} to change the drawing of the 1602 * view depending on its state. 1603 * 1604 * @see android.graphics.drawable.Drawable 1605 * @see #getDrawableState() 1606 */ 1607 protected static final int[] SELECTED_STATE_SET; 1608 /** 1609 * Indicates the view is pressed. States are used with 1610 * {@link android.graphics.drawable.Drawable} to change the drawing of the 1611 * view depending on its state. 1612 * 1613 * @see android.graphics.drawable.Drawable 1614 * @see #getDrawableState() 1615 */ 1616 protected static final int[] PRESSED_STATE_SET; 1617 /** 1618 * Indicates the view's window has focus. States are used with 1619 * {@link android.graphics.drawable.Drawable} to change the drawing of the 1620 * view depending on its state. 1621 * 1622 * @see android.graphics.drawable.Drawable 1623 * @see #getDrawableState() 1624 */ 1625 protected static final int[] WINDOW_FOCUSED_STATE_SET; 1626 // Doubles 1627 /** 1628 * Indicates the view is enabled and has the focus. 1629 * 1630 * @see #ENABLED_STATE_SET 1631 * @see #FOCUSED_STATE_SET 1632 */ 1633 protected static final int[] ENABLED_FOCUSED_STATE_SET; 1634 /** 1635 * Indicates the view is enabled and selected. 1636 * 1637 * @see #ENABLED_STATE_SET 1638 * @see #SELECTED_STATE_SET 1639 */ 1640 protected static final int[] ENABLED_SELECTED_STATE_SET; 1641 /** 1642 * Indicates the view is enabled and that its window has focus. 1643 * 1644 * @see #ENABLED_STATE_SET 1645 * @see #WINDOW_FOCUSED_STATE_SET 1646 */ 1647 protected static final int[] ENABLED_WINDOW_FOCUSED_STATE_SET; 1648 /** 1649 * Indicates the view is focused and selected. 1650 * 1651 * @see #FOCUSED_STATE_SET 1652 * @see #SELECTED_STATE_SET 1653 */ 1654 protected static final int[] FOCUSED_SELECTED_STATE_SET; 1655 /** 1656 * Indicates the view has the focus and that its window has the focus. 1657 * 1658 * @see #FOCUSED_STATE_SET 1659 * @see #WINDOW_FOCUSED_STATE_SET 1660 */ 1661 protected static final int[] FOCUSED_WINDOW_FOCUSED_STATE_SET; 1662 /** 1663 * Indicates the view is selected and that its window has the focus. 1664 * 1665 * @see #SELECTED_STATE_SET 1666 * @see #WINDOW_FOCUSED_STATE_SET 1667 */ 1668 protected static final int[] SELECTED_WINDOW_FOCUSED_STATE_SET; 1669 // Triples 1670 /** 1671 * Indicates the view is enabled, focused and selected. 1672 * 1673 * @see #ENABLED_STATE_SET 1674 * @see #FOCUSED_STATE_SET 1675 * @see #SELECTED_STATE_SET 1676 */ 1677 protected static final int[] ENABLED_FOCUSED_SELECTED_STATE_SET; 1678 /** 1679 * Indicates the view is enabled, focused and its window has the focus. 1680 * 1681 * @see #ENABLED_STATE_SET 1682 * @see #FOCUSED_STATE_SET 1683 * @see #WINDOW_FOCUSED_STATE_SET 1684 */ 1685 protected static final int[] ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET; 1686 /** 1687 * Indicates the view is enabled, selected and its window has the focus. 1688 * 1689 * @see #ENABLED_STATE_SET 1690 * @see #SELECTED_STATE_SET 1691 * @see #WINDOW_FOCUSED_STATE_SET 1692 */ 1693 protected static final int[] ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET; 1694 /** 1695 * Indicates the view is focused, selected and its window has the focus. 1696 * 1697 * @see #FOCUSED_STATE_SET 1698 * @see #SELECTED_STATE_SET 1699 * @see #WINDOW_FOCUSED_STATE_SET 1700 */ 1701 protected static final int[] FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 1702 /** 1703 * Indicates the view is enabled, focused, selected and its window 1704 * has the focus. 1705 * 1706 * @see #ENABLED_STATE_SET 1707 * @see #FOCUSED_STATE_SET 1708 * @see #SELECTED_STATE_SET 1709 * @see #WINDOW_FOCUSED_STATE_SET 1710 */ 1711 protected static final int[] ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 1712 /** 1713 * Indicates the view is pressed and its window has the focus. 1714 * 1715 * @see #PRESSED_STATE_SET 1716 * @see #WINDOW_FOCUSED_STATE_SET 1717 */ 1718 protected static final int[] PRESSED_WINDOW_FOCUSED_STATE_SET; 1719 /** 1720 * Indicates the view is pressed and selected. 1721 * 1722 * @see #PRESSED_STATE_SET 1723 * @see #SELECTED_STATE_SET 1724 */ 1725 protected static final int[] PRESSED_SELECTED_STATE_SET; 1726 /** 1727 * Indicates the view is pressed, selected and its window has the focus. 1728 * 1729 * @see #PRESSED_STATE_SET 1730 * @see #SELECTED_STATE_SET 1731 * @see #WINDOW_FOCUSED_STATE_SET 1732 */ 1733 protected static final int[] PRESSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 1734 /** 1735 * Indicates the view is pressed and focused. 1736 * 1737 * @see #PRESSED_STATE_SET 1738 * @see #FOCUSED_STATE_SET 1739 */ 1740 protected static final int[] PRESSED_FOCUSED_STATE_SET; 1741 /** 1742 * Indicates the view is pressed, focused and its window has the focus. 1743 * 1744 * @see #PRESSED_STATE_SET 1745 * @see #FOCUSED_STATE_SET 1746 * @see #WINDOW_FOCUSED_STATE_SET 1747 */ 1748 protected static final int[] PRESSED_FOCUSED_WINDOW_FOCUSED_STATE_SET; 1749 /** 1750 * Indicates the view is pressed, focused and selected. 1751 * 1752 * @see #PRESSED_STATE_SET 1753 * @see #SELECTED_STATE_SET 1754 * @see #FOCUSED_STATE_SET 1755 */ 1756 protected static final int[] PRESSED_FOCUSED_SELECTED_STATE_SET; 1757 /** 1758 * Indicates the view is pressed, focused, selected and its window has the focus. 1759 * 1760 * @see #PRESSED_STATE_SET 1761 * @see #FOCUSED_STATE_SET 1762 * @see #SELECTED_STATE_SET 1763 * @see #WINDOW_FOCUSED_STATE_SET 1764 */ 1765 protected static final int[] PRESSED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 1766 /** 1767 * Indicates the view is pressed and enabled. 1768 * 1769 * @see #PRESSED_STATE_SET 1770 * @see #ENABLED_STATE_SET 1771 */ 1772 protected static final int[] PRESSED_ENABLED_STATE_SET; 1773 /** 1774 * Indicates the view is pressed, enabled and its window has the focus. 1775 * 1776 * @see #PRESSED_STATE_SET 1777 * @see #ENABLED_STATE_SET 1778 * @see #WINDOW_FOCUSED_STATE_SET 1779 */ 1780 protected static final int[] PRESSED_ENABLED_WINDOW_FOCUSED_STATE_SET; 1781 /** 1782 * Indicates the view is pressed, enabled and selected. 1783 * 1784 * @see #PRESSED_STATE_SET 1785 * @see #ENABLED_STATE_SET 1786 * @see #SELECTED_STATE_SET 1787 */ 1788 protected static final int[] PRESSED_ENABLED_SELECTED_STATE_SET; 1789 /** 1790 * Indicates the view is pressed, enabled, selected and its window has the 1791 * focus. 1792 * 1793 * @see #PRESSED_STATE_SET 1794 * @see #ENABLED_STATE_SET 1795 * @see #SELECTED_STATE_SET 1796 * @see #WINDOW_FOCUSED_STATE_SET 1797 */ 1798 protected static final int[] PRESSED_ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET; 1799 /** 1800 * Indicates the view is pressed, enabled and focused. 1801 * 1802 * @see #PRESSED_STATE_SET 1803 * @see #ENABLED_STATE_SET 1804 * @see #FOCUSED_STATE_SET 1805 */ 1806 protected static final int[] PRESSED_ENABLED_FOCUSED_STATE_SET; 1807 /** 1808 * Indicates the view is pressed, enabled, focused and its window has the 1809 * focus. 1810 * 1811 * @see #PRESSED_STATE_SET 1812 * @see #ENABLED_STATE_SET 1813 * @see #FOCUSED_STATE_SET 1814 * @see #WINDOW_FOCUSED_STATE_SET 1815 */ 1816 protected static final int[] PRESSED_ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET; 1817 /** 1818 * Indicates the view is pressed, enabled, focused and selected. 1819 * 1820 * @see #PRESSED_STATE_SET 1821 * @see #ENABLED_STATE_SET 1822 * @see #SELECTED_STATE_SET 1823 * @see #FOCUSED_STATE_SET 1824 */ 1825 protected static final int[] PRESSED_ENABLED_FOCUSED_SELECTED_STATE_SET; 1826 /** 1827 * Indicates the view is pressed, enabled, focused, selected and its window 1828 * has the focus. 1829 * 1830 * @see #PRESSED_STATE_SET 1831 * @see #ENABLED_STATE_SET 1832 * @see #SELECTED_STATE_SET 1833 * @see #FOCUSED_STATE_SET 1834 * @see #WINDOW_FOCUSED_STATE_SET 1835 */ 1836 protected static final int[] PRESSED_ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 1837 1838 static { 1839 EMPTY_STATE_SET = StateSet.get(0); 1840 1841 WINDOW_FOCUSED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_WINDOW_FOCUSED); 1842 1843 SELECTED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_SELECTED); 1844 SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1845 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED); 1846 1847 FOCUSED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_FOCUSED); 1848 FOCUSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1849 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_FOCUSED); 1850 FOCUSED_SELECTED_STATE_SET = StateSet.get( 1851 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_FOCUSED); 1852 FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1853 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 1854 | StateSet.VIEW_STATE_FOCUSED); 1855 1856 ENABLED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_ENABLED); 1857 ENABLED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1858 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_ENABLED); 1859 ENABLED_SELECTED_STATE_SET = StateSet.get( 1860 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_ENABLED); 1861 ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1862 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 1863 | StateSet.VIEW_STATE_ENABLED); 1864 ENABLED_FOCUSED_STATE_SET = StateSet.get( 1865 StateSet.VIEW_STATE_FOCUSED | StateSet.VIEW_STATE_ENABLED); 1866 ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1867 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_FOCUSED 1868 | StateSet.VIEW_STATE_ENABLED); 1869 ENABLED_FOCUSED_SELECTED_STATE_SET = StateSet.get( 1870 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_FOCUSED 1871 | StateSet.VIEW_STATE_ENABLED); 1872 ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1873 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 1874 | StateSet.VIEW_STATE_FOCUSED| StateSet.VIEW_STATE_ENABLED); 1875 1876 PRESSED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_PRESSED); 1877 PRESSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1878 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_PRESSED); 1879 PRESSED_SELECTED_STATE_SET = StateSet.get( 1880 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_PRESSED); 1881 PRESSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1882 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 1883 | StateSet.VIEW_STATE_PRESSED); 1884 PRESSED_FOCUSED_STATE_SET = StateSet.get( 1885 StateSet.VIEW_STATE_FOCUSED | StateSet.VIEW_STATE_PRESSED); 1886 PRESSED_FOCUSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1887 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_FOCUSED 1888 | StateSet.VIEW_STATE_PRESSED); 1889 PRESSED_FOCUSED_SELECTED_STATE_SET = StateSet.get( 1890 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_FOCUSED 1891 | StateSet.VIEW_STATE_PRESSED); 1892 PRESSED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1893 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 1894 | StateSet.VIEW_STATE_FOCUSED | StateSet.VIEW_STATE_PRESSED); 1895 PRESSED_ENABLED_STATE_SET = StateSet.get( 1896 StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_PRESSED); 1897 PRESSED_ENABLED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1898 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_ENABLED 1899 | StateSet.VIEW_STATE_PRESSED); 1900 PRESSED_ENABLED_SELECTED_STATE_SET = StateSet.get( 1901 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_ENABLED 1902 | StateSet.VIEW_STATE_PRESSED); 1903 PRESSED_ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1904 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 1905 | StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_PRESSED); 1906 PRESSED_ENABLED_FOCUSED_STATE_SET = StateSet.get( 1907 StateSet.VIEW_STATE_FOCUSED | StateSet.VIEW_STATE_ENABLED 1908 | StateSet.VIEW_STATE_PRESSED); 1909 PRESSED_ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1910 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_FOCUSED 1911 | StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_PRESSED); 1912 PRESSED_ENABLED_FOCUSED_SELECTED_STATE_SET = StateSet.get( 1913 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_FOCUSED 1914 | StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_PRESSED); 1915 PRESSED_ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1916 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 1917 | StateSet.VIEW_STATE_FOCUSED| StateSet.VIEW_STATE_ENABLED 1918 | StateSet.VIEW_STATE_PRESSED); 1919 } 1920 1921 /** 1922 * Accessibility event types that are dispatched for text population. 1923 */ 1924 private static final int POPULATING_ACCESSIBILITY_EVENT_TYPES = 1925 AccessibilityEvent.TYPE_VIEW_CLICKED 1926 | AccessibilityEvent.TYPE_VIEW_LONG_CLICKED 1927 | AccessibilityEvent.TYPE_VIEW_SELECTED 1928 | AccessibilityEvent.TYPE_VIEW_FOCUSED 1929 | AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED 1930 | AccessibilityEvent.TYPE_VIEW_HOVER_ENTER 1931 | AccessibilityEvent.TYPE_VIEW_HOVER_EXIT 1932 | AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED 1933 | AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED 1934 | AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED 1935 | AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY; 1936 1937 static final int DEBUG_CORNERS_COLOR = Color.rgb(63, 127, 255); 1938 1939 static final int DEBUG_CORNERS_SIZE_DIP = 8; 1940 1941 /** 1942 * Temporary Rect currently for use in setBackground(). This will probably 1943 * be extended in the future to hold our own class with more than just 1944 * a Rect. :) 1945 */ 1946 static final ThreadLocal<Rect> sThreadLocal = new ThreadLocal<Rect>(); 1947 1948 /** 1949 * Map used to store views' tags. 1950 */ 1951 private SparseArray<Object> mKeyedTags; 1952 1953 /** 1954 * The animation currently associated with this view. 1955 * @hide 1956 */ 1957 protected Animation mCurrentAnimation = null; 1958 1959 /** 1960 * Width as measured during measure pass. 1961 * {@hide} 1962 */ 1963 @ViewDebug.ExportedProperty(category = "measurement") 1964 int mMeasuredWidth; 1965 1966 /** 1967 * Height as measured during measure pass. 1968 * {@hide} 1969 */ 1970 @ViewDebug.ExportedProperty(category = "measurement") 1971 int mMeasuredHeight; 1972 1973 /** 1974 * Flag to indicate that this view was marked INVALIDATED, or had its display list 1975 * invalidated, prior to the current drawing iteration. If true, the view must re-draw 1976 * its display list. This flag, used only when hw accelerated, allows us to clear the 1977 * flag while retaining this information until it's needed (at getDisplayList() time and 1978 * in drawChild(), when we decide to draw a view's children's display lists into our own). 1979 * 1980 * {@hide} 1981 */ 1982 boolean mRecreateDisplayList = false; 1983 1984 /** 1985 * The view's identifier. 1986 * {@hide} 1987 * 1988 * @see #setId(int) 1989 * @see #getId() 1990 */ 1991 @IdRes 1992 @ViewDebug.ExportedProperty(resolveId = true) 1993 int mID = NO_ID; 1994 1995 /** The ID of this view for accessibility and autofill purposes. 1996 * <ul> 1997 * <li>== {@link #NO_ID}: ID has not been assigned yet 1998 * <li>≤ {@link #LAST_APP_ACCESSIBILITY_ID}: View is not part of a activity. The ID is 1999 * unique in the process. This might change 2000 * over activity lifecycle events. 2001 * <li>> {@link #LAST_APP_ACCESSIBILITY_ID}: View is part of a activity. The ID is 2002 * unique in the activity. This stays the same 2003 * over activity lifecycle events. 2004 */ 2005 private int mAccessibilityViewId = NO_ID; 2006 2007 private int mAccessibilityCursorPosition = ACCESSIBILITY_CURSOR_POSITION_UNDEFINED; 2008 2009 SendViewStateChangedAccessibilityEvent mSendViewStateChangedAccessibilityEvent; 2010 2011 /** 2012 * The view's tag. 2013 * {@hide} 2014 * 2015 * @see #setTag(Object) 2016 * @see #getTag() 2017 */ 2018 protected Object mTag = null; 2019 2020 // for mPrivateFlags: 2021 /** {@hide} */ 2022 static final int PFLAG_WANTS_FOCUS = 0x00000001; 2023 /** {@hide} */ 2024 static final int PFLAG_FOCUSED = 0x00000002; 2025 /** {@hide} */ 2026 static final int PFLAG_SELECTED = 0x00000004; 2027 /** {@hide} */ 2028 static final int PFLAG_IS_ROOT_NAMESPACE = 0x00000008; 2029 /** {@hide} */ 2030 static final int PFLAG_HAS_BOUNDS = 0x00000010; 2031 /** {@hide} */ 2032 static final int PFLAG_DRAWN = 0x00000020; 2033 /** 2034 * When this flag is set, this view is running an animation on behalf of its 2035 * children and should therefore not cancel invalidate requests, even if they 2036 * lie outside of this view's bounds. 2037 * 2038 * {@hide} 2039 */ 2040 static final int PFLAG_DRAW_ANIMATION = 0x00000040; 2041 /** {@hide} */ 2042 static final int PFLAG_SKIP_DRAW = 0x00000080; 2043 /** {@hide} */ 2044 static final int PFLAG_REQUEST_TRANSPARENT_REGIONS = 0x00000200; 2045 /** {@hide} */ 2046 static final int PFLAG_DRAWABLE_STATE_DIRTY = 0x00000400; 2047 /** {@hide} */ 2048 static final int PFLAG_MEASURED_DIMENSION_SET = 0x00000800; 2049 /** {@hide} */ 2050 static final int PFLAG_FORCE_LAYOUT = 0x00001000; 2051 /** {@hide} */ 2052 static final int PFLAG_LAYOUT_REQUIRED = 0x00002000; 2053 2054 private static final int PFLAG_PRESSED = 0x00004000; 2055 2056 /** {@hide} */ 2057 static final int PFLAG_DRAWING_CACHE_VALID = 0x00008000; 2058 /** 2059 * Flag used to indicate that this view should be drawn once more (and only once 2060 * more) after its animation has completed. 2061 * {@hide} 2062 */ 2063 static final int PFLAG_ANIMATION_STARTED = 0x00010000; 2064 2065 private static final int PFLAG_SAVE_STATE_CALLED = 0x00020000; 2066 2067 /** 2068 * Indicates that the View returned true when onSetAlpha() was called and that 2069 * the alpha must be restored. 2070 * {@hide} 2071 */ 2072 static final int PFLAG_ALPHA_SET = 0x00040000; 2073 2074 /** 2075 * Set by {@link #setScrollContainer(boolean)}. 2076 */ 2077 static final int PFLAG_SCROLL_CONTAINER = 0x00080000; 2078 2079 /** 2080 * Set by {@link #setScrollContainer(boolean)}. 2081 */ 2082 static final int PFLAG_SCROLL_CONTAINER_ADDED = 0x00100000; 2083 2084 /** 2085 * View flag indicating whether this view was invalidated (fully or partially.) 2086 * 2087 * @hide 2088 */ 2089 static final int PFLAG_DIRTY = 0x00200000; 2090 2091 /** 2092 * View flag indicating whether this view was invalidated by an opaque 2093 * invalidate request. 2094 * 2095 * @hide 2096 */ 2097 static final int PFLAG_DIRTY_OPAQUE = 0x00400000; 2098 2099 /** 2100 * Mask for {@link #PFLAG_DIRTY} and {@link #PFLAG_DIRTY_OPAQUE}. 2101 * 2102 * @hide 2103 */ 2104 static final int PFLAG_DIRTY_MASK = 0x00600000; 2105 2106 /** 2107 * Indicates whether the background is opaque. 2108 * 2109 * @hide 2110 */ 2111 static final int PFLAG_OPAQUE_BACKGROUND = 0x00800000; 2112 2113 /** 2114 * Indicates whether the scrollbars are opaque. 2115 * 2116 * @hide 2117 */ 2118 static final int PFLAG_OPAQUE_SCROLLBARS = 0x01000000; 2119 2120 /** 2121 * Indicates whether the view is opaque. 2122 * 2123 * @hide 2124 */ 2125 static final int PFLAG_OPAQUE_MASK = 0x01800000; 2126 2127 /** 2128 * Indicates a prepressed state; 2129 * the short time between ACTION_DOWN and recognizing 2130 * a 'real' press. Prepressed is used to recognize quick taps 2131 * even when they are shorter than ViewConfiguration.getTapTimeout(). 2132 * 2133 * @hide 2134 */ 2135 private static final int PFLAG_PREPRESSED = 0x02000000; 2136 2137 /** 2138 * Indicates whether the view is temporarily detached. 2139 * 2140 * @hide 2141 */ 2142 static final int PFLAG_CANCEL_NEXT_UP_EVENT = 0x04000000; 2143 2144 /** 2145 * Indicates that we should awaken scroll bars once attached 2146 * 2147 * PLEASE NOTE: This flag is now unused as we now send onVisibilityChanged 2148 * during window attachment and it is no longer needed. Feel free to repurpose it. 2149 * 2150 * @hide 2151 */ 2152 private static final int PFLAG_AWAKEN_SCROLL_BARS_ON_ATTACH = 0x08000000; 2153 2154 /** 2155 * Indicates that the view has received HOVER_ENTER. Cleared on HOVER_EXIT. 2156 * @hide 2157 */ 2158 private static final int PFLAG_HOVERED = 0x10000000; 2159 2160 /** 2161 * no longer needed, should be reused 2162 */ 2163 private static final int PFLAG_DOES_NOTHING_REUSE_PLEASE = 0x20000000; 2164 2165 /** {@hide} */ 2166 static final int PFLAG_ACTIVATED = 0x40000000; 2167 2168 /** 2169 * Indicates that this view was specifically invalidated, not just dirtied because some 2170 * child view was invalidated. The flag is used to determine when we need to recreate 2171 * a view's display list (as opposed to just returning a reference to its existing 2172 * display list). 2173 * 2174 * @hide 2175 */ 2176 static final int PFLAG_INVALIDATED = 0x80000000; 2177 2178 /** 2179 * Masks for mPrivateFlags2, as generated by dumpFlags(): 2180 * 2181 * |-------|-------|-------|-------| 2182 * 1 PFLAG2_DRAG_CAN_ACCEPT 2183 * 1 PFLAG2_DRAG_HOVERED 2184 * 11 PFLAG2_LAYOUT_DIRECTION_MASK 2185 * 1 PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL 2186 * 1 PFLAG2_LAYOUT_DIRECTION_RESOLVED 2187 * 11 PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK 2188 * 1 PFLAG2_TEXT_DIRECTION_FLAGS[1] 2189 * 1 PFLAG2_TEXT_DIRECTION_FLAGS[2] 2190 * 11 PFLAG2_TEXT_DIRECTION_FLAGS[3] 2191 * 1 PFLAG2_TEXT_DIRECTION_FLAGS[4] 2192 * 1 1 PFLAG2_TEXT_DIRECTION_FLAGS[5] 2193 * 11 PFLAG2_TEXT_DIRECTION_FLAGS[6] 2194 * 111 PFLAG2_TEXT_DIRECTION_FLAGS[7] 2195 * 111 PFLAG2_TEXT_DIRECTION_MASK 2196 * 1 PFLAG2_TEXT_DIRECTION_RESOLVED 2197 * 1 PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT 2198 * 111 PFLAG2_TEXT_DIRECTION_RESOLVED_MASK 2199 * 1 PFLAG2_TEXT_ALIGNMENT_FLAGS[1] 2200 * 1 PFLAG2_TEXT_ALIGNMENT_FLAGS[2] 2201 * 11 PFLAG2_TEXT_ALIGNMENT_FLAGS[3] 2202 * 1 PFLAG2_TEXT_ALIGNMENT_FLAGS[4] 2203 * 1 1 PFLAG2_TEXT_ALIGNMENT_FLAGS[5] 2204 * 11 PFLAG2_TEXT_ALIGNMENT_FLAGS[6] 2205 * 111 PFLAG2_TEXT_ALIGNMENT_MASK 2206 * 1 PFLAG2_TEXT_ALIGNMENT_RESOLVED 2207 * 1 PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT 2208 * 111 PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK 2209 * 111 PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK 2210 * 11 PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK 2211 * 1 PFLAG2_ACCESSIBILITY_FOCUSED 2212 * 1 PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED 2213 * 1 PFLAG2_VIEW_QUICK_REJECTED 2214 * 1 PFLAG2_PADDING_RESOLVED 2215 * 1 PFLAG2_DRAWABLE_RESOLVED 2216 * 1 PFLAG2_HAS_TRANSIENT_STATE 2217 * |-------|-------|-------|-------| 2218 */ 2219 2220 /** 2221 * Indicates that this view has reported that it can accept the current drag's content. 2222 * Cleared when the drag operation concludes. 2223 * @hide 2224 */ 2225 static final int PFLAG2_DRAG_CAN_ACCEPT = 0x00000001; 2226 2227 /** 2228 * Indicates that this view is currently directly under the drag location in a 2229 * drag-and-drop operation involving content that it can accept. Cleared when 2230 * the drag exits the view, or when the drag operation concludes. 2231 * @hide 2232 */ 2233 static final int PFLAG2_DRAG_HOVERED = 0x00000002; 2234 2235 /** @hide */ 2236 @IntDef({ 2237 LAYOUT_DIRECTION_LTR, 2238 LAYOUT_DIRECTION_RTL, 2239 LAYOUT_DIRECTION_INHERIT, 2240 LAYOUT_DIRECTION_LOCALE 2241 }) 2242 @Retention(RetentionPolicy.SOURCE) 2243 // Not called LayoutDirection to avoid conflict with android.util.LayoutDirection 2244 public @interface LayoutDir {} 2245 2246 /** @hide */ 2247 @IntDef({ 2248 LAYOUT_DIRECTION_LTR, 2249 LAYOUT_DIRECTION_RTL 2250 }) 2251 @Retention(RetentionPolicy.SOURCE) 2252 public @interface ResolvedLayoutDir {} 2253 2254 /** 2255 * A flag to indicate that the layout direction of this view has not been defined yet. 2256 * @hide 2257 */ 2258 public static final int LAYOUT_DIRECTION_UNDEFINED = LayoutDirection.UNDEFINED; 2259 2260 /** 2261 * Horizontal layout direction of this view is from Left to Right. 2262 * Use with {@link #setLayoutDirection}. 2263 */ 2264 public static final int LAYOUT_DIRECTION_LTR = LayoutDirection.LTR; 2265 2266 /** 2267 * Horizontal layout direction of this view is from Right to Left. 2268 * Use with {@link #setLayoutDirection}. 2269 */ 2270 public static final int LAYOUT_DIRECTION_RTL = LayoutDirection.RTL; 2271 2272 /** 2273 * Horizontal layout direction of this view is inherited from its parent. 2274 * Use with {@link #setLayoutDirection}. 2275 */ 2276 public static final int LAYOUT_DIRECTION_INHERIT = LayoutDirection.INHERIT; 2277 2278 /** 2279 * Horizontal layout direction of this view is from deduced from the default language 2280 * script for the locale. Use with {@link #setLayoutDirection}. 2281 */ 2282 public static final int LAYOUT_DIRECTION_LOCALE = LayoutDirection.LOCALE; 2283 2284 /** 2285 * Bit shift to get the horizontal layout direction. (bits after DRAG_HOVERED) 2286 * @hide 2287 */ 2288 static final int PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT = 2; 2289 2290 /** 2291 * Mask for use with private flags indicating bits used for horizontal layout direction. 2292 * @hide 2293 */ 2294 static final int PFLAG2_LAYOUT_DIRECTION_MASK = 0x00000003 << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 2295 2296 /** 2297 * Indicates whether the view horizontal layout direction has been resolved and drawn to the 2298 * right-to-left direction. 2299 * @hide 2300 */ 2301 static final int PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL = 4 << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 2302 2303 /** 2304 * Indicates whether the view horizontal layout direction has been resolved. 2305 * @hide 2306 */ 2307 static final int PFLAG2_LAYOUT_DIRECTION_RESOLVED = 8 << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 2308 2309 /** 2310 * Mask for use with private flags indicating bits used for resolved horizontal layout direction. 2311 * @hide 2312 */ 2313 static final int PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK = 0x0000000C 2314 << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 2315 2316 /* 2317 * Array of horizontal layout direction flags for mapping attribute "layoutDirection" to correct 2318 * flag value. 2319 * @hide 2320 */ 2321 private static final int[] LAYOUT_DIRECTION_FLAGS = { 2322 LAYOUT_DIRECTION_LTR, 2323 LAYOUT_DIRECTION_RTL, 2324 LAYOUT_DIRECTION_INHERIT, 2325 LAYOUT_DIRECTION_LOCALE 2326 }; 2327 2328 /** 2329 * Default horizontal layout direction. 2330 */ 2331 private static final int LAYOUT_DIRECTION_DEFAULT = LAYOUT_DIRECTION_INHERIT; 2332 2333 /** 2334 * Default horizontal layout direction. 2335 * @hide 2336 */ 2337 static final int LAYOUT_DIRECTION_RESOLVED_DEFAULT = LAYOUT_DIRECTION_LTR; 2338 2339 /** 2340 * Text direction is inherited through {@link ViewGroup} 2341 */ 2342 public static final int TEXT_DIRECTION_INHERIT = 0; 2343 2344 /** 2345 * Text direction is using "first strong algorithm". The first strong directional character 2346 * determines the paragraph direction. If there is no strong directional character, the 2347 * paragraph direction is the view's resolved layout direction. 2348 */ 2349 public static final int TEXT_DIRECTION_FIRST_STRONG = 1; 2350 2351 /** 2352 * Text direction is using "any-RTL" algorithm. The paragraph direction is RTL if it contains 2353 * any strong RTL character, otherwise it is LTR if it contains any strong LTR characters. 2354 * If there are neither, the paragraph direction is the view's resolved layout direction. 2355 */ 2356 public static final int TEXT_DIRECTION_ANY_RTL = 2; 2357 2358 /** 2359 * Text direction is forced to LTR. 2360 */ 2361 public static final int TEXT_DIRECTION_LTR = 3; 2362 2363 /** 2364 * Text direction is forced to RTL. 2365 */ 2366 public static final int TEXT_DIRECTION_RTL = 4; 2367 2368 /** 2369 * Text direction is coming from the system Locale. 2370 */ 2371 public static final int TEXT_DIRECTION_LOCALE = 5; 2372 2373 /** 2374 * Text direction is using "first strong algorithm". The first strong directional character 2375 * determines the paragraph direction. If there is no strong directional character, the 2376 * paragraph direction is LTR. 2377 */ 2378 public static final int TEXT_DIRECTION_FIRST_STRONG_LTR = 6; 2379 2380 /** 2381 * Text direction is using "first strong algorithm". The first strong directional character 2382 * determines the paragraph direction. If there is no strong directional character, the 2383 * paragraph direction is RTL. 2384 */ 2385 public static final int TEXT_DIRECTION_FIRST_STRONG_RTL = 7; 2386 2387 /** 2388 * Default text direction is inherited 2389 */ 2390 private static final int TEXT_DIRECTION_DEFAULT = TEXT_DIRECTION_INHERIT; 2391 2392 /** 2393 * Default resolved text direction 2394 * @hide 2395 */ 2396 static final int TEXT_DIRECTION_RESOLVED_DEFAULT = TEXT_DIRECTION_FIRST_STRONG; 2397 2398 /** 2399 * Bit shift to get the horizontal layout direction. (bits after LAYOUT_DIRECTION_RESOLVED) 2400 * @hide 2401 */ 2402 static final int PFLAG2_TEXT_DIRECTION_MASK_SHIFT = 6; 2403 2404 /** 2405 * Mask for use with private flags indicating bits used for text direction. 2406 * @hide 2407 */ 2408 static final int PFLAG2_TEXT_DIRECTION_MASK = 0x00000007 2409 << PFLAG2_TEXT_DIRECTION_MASK_SHIFT; 2410 2411 /** 2412 * Array of text direction flags for mapping attribute "textDirection" to correct 2413 * flag value. 2414 * @hide 2415 */ 2416 private static final int[] PFLAG2_TEXT_DIRECTION_FLAGS = { 2417 TEXT_DIRECTION_INHERIT << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2418 TEXT_DIRECTION_FIRST_STRONG << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2419 TEXT_DIRECTION_ANY_RTL << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2420 TEXT_DIRECTION_LTR << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2421 TEXT_DIRECTION_RTL << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2422 TEXT_DIRECTION_LOCALE << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2423 TEXT_DIRECTION_FIRST_STRONG_LTR << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2424 TEXT_DIRECTION_FIRST_STRONG_RTL << PFLAG2_TEXT_DIRECTION_MASK_SHIFT 2425 }; 2426 2427 /** 2428 * Indicates whether the view text direction has been resolved. 2429 * @hide 2430 */ 2431 static final int PFLAG2_TEXT_DIRECTION_RESOLVED = 0x00000008 2432 << PFLAG2_TEXT_DIRECTION_MASK_SHIFT; 2433 2434 /** 2435 * Bit shift to get the horizontal layout direction. (bits after DRAG_HOVERED) 2436 * @hide 2437 */ 2438 static final int PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT = 10; 2439 2440 /** 2441 * Mask for use with private flags indicating bits used for resolved text direction. 2442 * @hide 2443 */ 2444 static final int PFLAG2_TEXT_DIRECTION_RESOLVED_MASK = 0x00000007 2445 << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT; 2446 2447 /** 2448 * Indicates whether the view text direction has been resolved to the "first strong" heuristic. 2449 * @hide 2450 */ 2451 static final int PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT = 2452 TEXT_DIRECTION_RESOLVED_DEFAULT << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT; 2453 2454 /** @hide */ 2455 @IntDef({ 2456 TEXT_ALIGNMENT_INHERIT, 2457 TEXT_ALIGNMENT_GRAVITY, 2458 TEXT_ALIGNMENT_CENTER, 2459 TEXT_ALIGNMENT_TEXT_START, 2460 TEXT_ALIGNMENT_TEXT_END, 2461 TEXT_ALIGNMENT_VIEW_START, 2462 TEXT_ALIGNMENT_VIEW_END 2463 }) 2464 @Retention(RetentionPolicy.SOURCE) 2465 public @interface TextAlignment {} 2466 2467 /** 2468 * Default text alignment. The text alignment of this View is inherited from its parent. 2469 * Use with {@link #setTextAlignment(int)} 2470 */ 2471 public static final int TEXT_ALIGNMENT_INHERIT = 0; 2472 2473 /** 2474 * Default for the root view. The gravity determines the text alignment, ALIGN_NORMAL, 2475 * ALIGN_CENTER, or ALIGN_OPPOSITE, which are relative to each paragraph’s text direction. 2476 * 2477 * Use with {@link #setTextAlignment(int)} 2478 */ 2479 public static final int TEXT_ALIGNMENT_GRAVITY = 1; 2480 2481 /** 2482 * Align to the start of the paragraph, e.g. ALIGN_NORMAL. 2483 * 2484 * Use with {@link #setTextAlignment(int)} 2485 */ 2486 public static final int TEXT_ALIGNMENT_TEXT_START = 2; 2487 2488 /** 2489 * Align to the end of the paragraph, e.g. ALIGN_OPPOSITE. 2490 * 2491 * Use with {@link #setTextAlignment(int)} 2492 */ 2493 public static final int TEXT_ALIGNMENT_TEXT_END = 3; 2494 2495 /** 2496 * Center the paragraph, e.g. ALIGN_CENTER. 2497 * 2498 * Use with {@link #setTextAlignment(int)} 2499 */ 2500 public static final int TEXT_ALIGNMENT_CENTER = 4; 2501 2502 /** 2503 * Align to the start of the view, which is ALIGN_LEFT if the view’s resolved 2504 * layoutDirection is LTR, and ALIGN_RIGHT otherwise. 2505 * 2506 * Use with {@link #setTextAlignment(int)} 2507 */ 2508 public static final int TEXT_ALIGNMENT_VIEW_START = 5; 2509 2510 /** 2511 * Align to the end of the view, which is ALIGN_RIGHT if the view’s resolved 2512 * layoutDirection is LTR, and ALIGN_LEFT otherwise. 2513 * 2514 * Use with {@link #setTextAlignment(int)} 2515 */ 2516 public static final int TEXT_ALIGNMENT_VIEW_END = 6; 2517 2518 /** 2519 * Default text alignment is inherited 2520 */ 2521 private static final int TEXT_ALIGNMENT_DEFAULT = TEXT_ALIGNMENT_GRAVITY; 2522 2523 /** 2524 * Default resolved text alignment 2525 * @hide 2526 */ 2527 static final int TEXT_ALIGNMENT_RESOLVED_DEFAULT = TEXT_ALIGNMENT_GRAVITY; 2528 2529 /** 2530 * Bit shift to get the horizontal layout direction. (bits after DRAG_HOVERED) 2531 * @hide 2532 */ 2533 static final int PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT = 13; 2534 2535 /** 2536 * Mask for use with private flags indicating bits used for text alignment. 2537 * @hide 2538 */ 2539 static final int PFLAG2_TEXT_ALIGNMENT_MASK = 0x00000007 << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT; 2540 2541 /** 2542 * Array of text direction flags for mapping attribute "textAlignment" to correct 2543 * flag value. 2544 * @hide 2545 */ 2546 private static final int[] PFLAG2_TEXT_ALIGNMENT_FLAGS = { 2547 TEXT_ALIGNMENT_INHERIT << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 2548 TEXT_ALIGNMENT_GRAVITY << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 2549 TEXT_ALIGNMENT_TEXT_START << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 2550 TEXT_ALIGNMENT_TEXT_END << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 2551 TEXT_ALIGNMENT_CENTER << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 2552 TEXT_ALIGNMENT_VIEW_START << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 2553 TEXT_ALIGNMENT_VIEW_END << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT 2554 }; 2555 2556 /** 2557 * Indicates whether the view text alignment has been resolved. 2558 * @hide 2559 */ 2560 static final int PFLAG2_TEXT_ALIGNMENT_RESOLVED = 0x00000008 << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT; 2561 2562 /** 2563 * Bit shift to get the resolved text alignment. 2564 * @hide 2565 */ 2566 static final int PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT = 17; 2567 2568 /** 2569 * Mask for use with private flags indicating bits used for text alignment. 2570 * @hide 2571 */ 2572 static final int PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK = 0x00000007 2573 << PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT; 2574 2575 /** 2576 * Indicates whether if the view text alignment has been resolved to gravity 2577 */ 2578 private static final int PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT = 2579 TEXT_ALIGNMENT_RESOLVED_DEFAULT << PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT; 2580 2581 // Accessiblity constants for mPrivateFlags2 2582 2583 /** 2584 * Shift for the bits in {@link #mPrivateFlags2} related to the 2585 * "importantForAccessibility" attribute. 2586 */ 2587 static final int PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT = 20; 2588 2589 /** 2590 * Automatically determine whether a view is important for accessibility. 2591 */ 2592 public static final int IMPORTANT_FOR_ACCESSIBILITY_AUTO = 0x00000000; 2593 2594 /** 2595 * The view is important for accessibility. 2596 */ 2597 public static final int IMPORTANT_FOR_ACCESSIBILITY_YES = 0x00000001; 2598 2599 /** 2600 * The view is not important for accessibility. 2601 */ 2602 public static final int IMPORTANT_FOR_ACCESSIBILITY_NO = 0x00000002; 2603 2604 /** 2605 * The view is not important for accessibility, nor are any of its 2606 * descendant views. 2607 */ 2608 public static final int IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS = 0x00000004; 2609 2610 /** 2611 * The default whether the view is important for accessibility. 2612 */ 2613 static final int IMPORTANT_FOR_ACCESSIBILITY_DEFAULT = IMPORTANT_FOR_ACCESSIBILITY_AUTO; 2614 2615 /** 2616 * Mask for obtaining the bits which specify how to determine 2617 * whether a view is important for accessibility. 2618 */ 2619 static final int PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK = (IMPORTANT_FOR_ACCESSIBILITY_AUTO 2620 | IMPORTANT_FOR_ACCESSIBILITY_YES | IMPORTANT_FOR_ACCESSIBILITY_NO 2621 | IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS) 2622 << PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT; 2623 2624 /** 2625 * Shift for the bits in {@link #mPrivateFlags2} related to the 2626 * "accessibilityLiveRegion" attribute. 2627 */ 2628 static final int PFLAG2_ACCESSIBILITY_LIVE_REGION_SHIFT = 23; 2629 2630 /** 2631 * Live region mode specifying that accessibility services should not 2632 * automatically announce changes to this view. This is the default live 2633 * region mode for most views. 2634 * <p> 2635 * Use with {@link #setAccessibilityLiveRegion(int)}. 2636 */ 2637 public static final int ACCESSIBILITY_LIVE_REGION_NONE = 0x00000000; 2638 2639 /** 2640 * Live region mode specifying that accessibility services should announce 2641 * changes to this view. 2642 * <p> 2643 * Use with {@link #setAccessibilityLiveRegion(int)}. 2644 */ 2645 public static final int ACCESSIBILITY_LIVE_REGION_POLITE = 0x00000001; 2646 2647 /** 2648 * Live region mode specifying that accessibility services should interrupt 2649 * ongoing speech to immediately announce changes to this view. 2650 * <p> 2651 * Use with {@link #setAccessibilityLiveRegion(int)}. 2652 */ 2653 public static final int ACCESSIBILITY_LIVE_REGION_ASSERTIVE = 0x00000002; 2654 2655 /** 2656 * The default whether the view is important for accessibility. 2657 */ 2658 static final int ACCESSIBILITY_LIVE_REGION_DEFAULT = ACCESSIBILITY_LIVE_REGION_NONE; 2659 2660 /** 2661 * Mask for obtaining the bits which specify a view's accessibility live 2662 * region mode. 2663 */ 2664 static final int PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK = (ACCESSIBILITY_LIVE_REGION_NONE 2665 | ACCESSIBILITY_LIVE_REGION_POLITE | ACCESSIBILITY_LIVE_REGION_ASSERTIVE) 2666 << PFLAG2_ACCESSIBILITY_LIVE_REGION_SHIFT; 2667 2668 /** 2669 * Flag indicating whether a view has accessibility focus. 2670 */ 2671 static final int PFLAG2_ACCESSIBILITY_FOCUSED = 0x04000000; 2672 2673 /** 2674 * Flag whether the accessibility state of the subtree rooted at this view changed. 2675 */ 2676 static final int PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED = 0x08000000; 2677 2678 /** 2679 * Flag indicating whether a view failed the quickReject() check in draw(). This condition 2680 * is used to check whether later changes to the view's transform should invalidate the 2681 * view to force the quickReject test to run again. 2682 */ 2683 static final int PFLAG2_VIEW_QUICK_REJECTED = 0x10000000; 2684 2685 /** 2686 * Flag indicating that start/end padding has been resolved into left/right padding 2687 * for use in measurement, layout, drawing, etc. This is set by {@link #resolvePadding()} 2688 * and checked by {@link #measure(int, int)} to determine if padding needs to be resolved 2689 * during measurement. In some special cases this is required such as when an adapter-based 2690 * view measures prospective children without attaching them to a window. 2691 */ 2692 static final int PFLAG2_PADDING_RESOLVED = 0x20000000; 2693 2694 /** 2695 * Flag indicating that the start/end drawables has been resolved into left/right ones. 2696 */ 2697 static final int PFLAG2_DRAWABLE_RESOLVED = 0x40000000; 2698 2699 /** 2700 * Indicates that the view is tracking some sort of transient state 2701 * that the app should not need to be aware of, but that the framework 2702 * should take special care to preserve. 2703 */ 2704 static final int PFLAG2_HAS_TRANSIENT_STATE = 0x80000000; 2705 2706 /** 2707 * Group of bits indicating that RTL properties resolution is done. 2708 */ 2709 static final int ALL_RTL_PROPERTIES_RESOLVED = PFLAG2_LAYOUT_DIRECTION_RESOLVED | 2710 PFLAG2_TEXT_DIRECTION_RESOLVED | 2711 PFLAG2_TEXT_ALIGNMENT_RESOLVED | 2712 PFLAG2_PADDING_RESOLVED | 2713 PFLAG2_DRAWABLE_RESOLVED; 2714 2715 // There are a couple of flags left in mPrivateFlags2 2716 2717 /* End of masks for mPrivateFlags2 */ 2718 2719 /** 2720 * Masks for mPrivateFlags3, as generated by dumpFlags(): 2721 * 2722 * |-------|-------|-------|-------| 2723 * 1 PFLAG3_VIEW_IS_ANIMATING_TRANSFORM 2724 * 1 PFLAG3_VIEW_IS_ANIMATING_ALPHA 2725 * 1 PFLAG3_IS_LAID_OUT 2726 * 1 PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT 2727 * 1 PFLAG3_CALLED_SUPER 2728 * 1 PFLAG3_APPLYING_INSETS 2729 * 1 PFLAG3_FITTING_SYSTEM_WINDOWS 2730 * 1 PFLAG3_NESTED_SCROLLING_ENABLED 2731 * 1 PFLAG3_SCROLL_INDICATOR_TOP 2732 * 1 PFLAG3_SCROLL_INDICATOR_BOTTOM 2733 * 1 PFLAG3_SCROLL_INDICATOR_LEFT 2734 * 1 PFLAG3_SCROLL_INDICATOR_RIGHT 2735 * 1 PFLAG3_SCROLL_INDICATOR_START 2736 * 1 PFLAG3_SCROLL_INDICATOR_END 2737 * 1 PFLAG3_ASSIST_BLOCKED 2738 * 1 PFLAG3_CLUSTER 2739 * 1 PFLAG3_IS_AUTOFILLED 2740 * 1 PFLAG3_FINGER_DOWN 2741 * 1 PFLAG3_FOCUSED_BY_DEFAULT 2742 * __ unused 2743 * 11 PFLAG3_IMPORTANT_FOR_AUTOFILL 2744 * 1 PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE 2745 * 1 PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED 2746 * 1 PFLAG3_TEMPORARY_DETACH 2747 * 1 PFLAG3_NO_REVEAL_ON_FOCUS 2748 * |-------|-------|-------|-------| 2749 */ 2750 2751 /** 2752 * Flag indicating that view has a transform animation set on it. This is used to track whether 2753 * an animation is cleared between successive frames, in order to tell the associated 2754 * DisplayList to clear its animation matrix. 2755 */ 2756 static final int PFLAG3_VIEW_IS_ANIMATING_TRANSFORM = 0x1; 2757 2758 /** 2759 * Flag indicating that view has an alpha animation set on it. This is used to track whether an 2760 * animation is cleared between successive frames, in order to tell the associated 2761 * DisplayList to restore its alpha value. 2762 */ 2763 static final int PFLAG3_VIEW_IS_ANIMATING_ALPHA = 0x2; 2764 2765 /** 2766 * Flag indicating that the view has been through at least one layout since it 2767 * was last attached to a window. 2768 */ 2769 static final int PFLAG3_IS_LAID_OUT = 0x4; 2770 2771 /** 2772 * Flag indicating that a call to measure() was skipped and should be done 2773 * instead when layout() is invoked. 2774 */ 2775 static final int PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT = 0x8; 2776 2777 /** 2778 * Flag indicating that an overridden method correctly called down to 2779 * the superclass implementation as required by the API spec. 2780 */ 2781 static final int PFLAG3_CALLED_SUPER = 0x10; 2782 2783 /** 2784 * Flag indicating that we're in the process of applying window insets. 2785 */ 2786 static final int PFLAG3_APPLYING_INSETS = 0x20; 2787 2788 /** 2789 * Flag indicating that we're in the process of fitting system windows using the old method. 2790 */ 2791 static final int PFLAG3_FITTING_SYSTEM_WINDOWS = 0x40; 2792 2793 /** 2794 * Flag indicating that nested scrolling is enabled for this view. 2795 * The view will optionally cooperate with views up its parent chain to allow for 2796 * integrated nested scrolling along the same axis. 2797 */ 2798 static final int PFLAG3_NESTED_SCROLLING_ENABLED = 0x80; 2799 2800 /** 2801 * Flag indicating that the bottom scroll indicator should be displayed 2802 * when this view can scroll up. 2803 */ 2804 static final int PFLAG3_SCROLL_INDICATOR_TOP = 0x0100; 2805 2806 /** 2807 * Flag indicating that the bottom scroll indicator should be displayed 2808 * when this view can scroll down. 2809 */ 2810 static final int PFLAG3_SCROLL_INDICATOR_BOTTOM = 0x0200; 2811 2812 /** 2813 * Flag indicating that the left scroll indicator should be displayed 2814 * when this view can scroll left. 2815 */ 2816 static final int PFLAG3_SCROLL_INDICATOR_LEFT = 0x0400; 2817 2818 /** 2819 * Flag indicating that the right scroll indicator should be displayed 2820 * when this view can scroll right. 2821 */ 2822 static final int PFLAG3_SCROLL_INDICATOR_RIGHT = 0x0800; 2823 2824 /** 2825 * Flag indicating that the start scroll indicator should be displayed 2826 * when this view can scroll in the start direction. 2827 */ 2828 static final int PFLAG3_SCROLL_INDICATOR_START = 0x1000; 2829 2830 /** 2831 * Flag indicating that the end scroll indicator should be displayed 2832 * when this view can scroll in the end direction. 2833 */ 2834 static final int PFLAG3_SCROLL_INDICATOR_END = 0x2000; 2835 2836 static final int DRAG_MASK = PFLAG2_DRAG_CAN_ACCEPT | PFLAG2_DRAG_HOVERED; 2837 2838 static final int SCROLL_INDICATORS_NONE = 0x0000; 2839 2840 /** 2841 * Mask for use with setFlags indicating bits used for indicating which 2842 * scroll indicators are enabled. 2843 */ 2844 static final int SCROLL_INDICATORS_PFLAG3_MASK = PFLAG3_SCROLL_INDICATOR_TOP 2845 | PFLAG3_SCROLL_INDICATOR_BOTTOM | PFLAG3_SCROLL_INDICATOR_LEFT 2846 | PFLAG3_SCROLL_INDICATOR_RIGHT | PFLAG3_SCROLL_INDICATOR_START 2847 | PFLAG3_SCROLL_INDICATOR_END; 2848 2849 /** 2850 * Left-shift required to translate between public scroll indicator flags 2851 * and internal PFLAGS3 flags. When used as a right-shift, translates 2852 * PFLAGS3 flags to public flags. 2853 */ 2854 static final int SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT = 8; 2855 2856 /** @hide */ 2857 @Retention(RetentionPolicy.SOURCE) 2858 @IntDef(flag = true, 2859 value = { 2860 SCROLL_INDICATOR_TOP, 2861 SCROLL_INDICATOR_BOTTOM, 2862 SCROLL_INDICATOR_LEFT, 2863 SCROLL_INDICATOR_RIGHT, 2864 SCROLL_INDICATOR_START, 2865 SCROLL_INDICATOR_END, 2866 }) 2867 public @interface ScrollIndicators {} 2868 2869 /** 2870 * Scroll indicator direction for the top edge of the view. 2871 * 2872 * @see #setScrollIndicators(int) 2873 * @see #setScrollIndicators(int, int) 2874 * @see #getScrollIndicators() 2875 */ 2876 public static final int SCROLL_INDICATOR_TOP = 2877 PFLAG3_SCROLL_INDICATOR_TOP >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 2878 2879 /** 2880 * Scroll indicator direction for the bottom edge of the view. 2881 * 2882 * @see #setScrollIndicators(int) 2883 * @see #setScrollIndicators(int, int) 2884 * @see #getScrollIndicators() 2885 */ 2886 public static final int SCROLL_INDICATOR_BOTTOM = 2887 PFLAG3_SCROLL_INDICATOR_BOTTOM >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 2888 2889 /** 2890 * Scroll indicator direction for the left edge of the view. 2891 * 2892 * @see #setScrollIndicators(int) 2893 * @see #setScrollIndicators(int, int) 2894 * @see #getScrollIndicators() 2895 */ 2896 public static final int SCROLL_INDICATOR_LEFT = 2897 PFLAG3_SCROLL_INDICATOR_LEFT >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 2898 2899 /** 2900 * Scroll indicator direction for the right edge of the view. 2901 * 2902 * @see #setScrollIndicators(int) 2903 * @see #setScrollIndicators(int, int) 2904 * @see #getScrollIndicators() 2905 */ 2906 public static final int SCROLL_INDICATOR_RIGHT = 2907 PFLAG3_SCROLL_INDICATOR_RIGHT >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 2908 2909 /** 2910 * Scroll indicator direction for the starting edge of the view. 2911 * <p> 2912 * Resolved according to the view's layout direction, see 2913 * {@link #getLayoutDirection()} for more information. 2914 * 2915 * @see #setScrollIndicators(int) 2916 * @see #setScrollIndicators(int, int) 2917 * @see #getScrollIndicators() 2918 */ 2919 public static final int SCROLL_INDICATOR_START = 2920 PFLAG3_SCROLL_INDICATOR_START >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 2921 2922 /** 2923 * Scroll indicator direction for the ending edge of the view. 2924 * <p> 2925 * Resolved according to the view's layout direction, see 2926 * {@link #getLayoutDirection()} for more information. 2927 * 2928 * @see #setScrollIndicators(int) 2929 * @see #setScrollIndicators(int, int) 2930 * @see #getScrollIndicators() 2931 */ 2932 public static final int SCROLL_INDICATOR_END = 2933 PFLAG3_SCROLL_INDICATOR_END >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 2934 2935 /** 2936 * <p>Indicates that we are allowing {@link ViewStructure} to traverse 2937 * into this view.<p> 2938 */ 2939 static final int PFLAG3_ASSIST_BLOCKED = 0x4000; 2940 2941 /** 2942 * Flag indicating that the view is a root of a keyboard navigation cluster. 2943 * 2944 * @see #isKeyboardNavigationCluster() 2945 * @see #setKeyboardNavigationCluster(boolean) 2946 */ 2947 private static final int PFLAG3_CLUSTER = 0x8000; 2948 2949 /** 2950 * Flag indicating that the view is autofilled 2951 * 2952 * @see #isAutofilled() 2953 * @see #setAutofilled(boolean) 2954 */ 2955 private static final int PFLAG3_IS_AUTOFILLED = 0x10000; 2956 2957 /** 2958 * Indicates that the user is currently touching the screen. 2959 * Currently used for the tooltip positioning only. 2960 */ 2961 private static final int PFLAG3_FINGER_DOWN = 0x20000; 2962 2963 /** 2964 * Flag indicating that this view is the default-focus view. 2965 * 2966 * @see #isFocusedByDefault() 2967 * @see #setFocusedByDefault(boolean) 2968 */ 2969 private static final int PFLAG3_FOCUSED_BY_DEFAULT = 0x40000; 2970 2971 /** 2972 * Shift for the bits in {@link #mPrivateFlags3} related to the 2973 * "importantForAutofill" attribute. 2974 */ 2975 static final int PFLAG3_IMPORTANT_FOR_AUTOFILL_SHIFT = 21; 2976 2977 /** 2978 * Mask for obtaining the bits which specify how to determine 2979 * whether a view is important for autofill. 2980 */ 2981 static final int PFLAG3_IMPORTANT_FOR_AUTOFILL_MASK = (IMPORTANT_FOR_AUTOFILL_AUTO 2982 | IMPORTANT_FOR_AUTOFILL_YES | IMPORTANT_FOR_AUTOFILL_NO) 2983 << PFLAG3_IMPORTANT_FOR_AUTOFILL_SHIFT; 2984 2985 /** 2986 * Whether this view has rendered elements that overlap (see {@link 2987 * #hasOverlappingRendering()}, {@link #forceHasOverlappingRendering(boolean)}, and 2988 * {@link #getHasOverlappingRendering()} ). The value in this bit is only valid when 2989 * PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED has been set. Otherwise, the value is 2990 * determined by whatever {@link #hasOverlappingRendering()} returns. 2991 */ 2992 private static final int PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE = 0x800000; 2993 2994 /** 2995 * Whether {@link #forceHasOverlappingRendering(boolean)} has been called. When true, value 2996 * in PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE is valid. 2997 */ 2998 private static final int PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED = 0x1000000; 2999 3000 /** 3001 * Flag indicating that the view is temporarily detached from the parent view. 3002 * 3003 * @see #onStartTemporaryDetach() 3004 * @see #onFinishTemporaryDetach() 3005 */ 3006 static final int PFLAG3_TEMPORARY_DETACH = 0x2000000; 3007 3008 /** 3009 * Flag indicating that the view does not wish to be revealed within its parent 3010 * hierarchy when it gains focus. Expressed in the negative since the historical 3011 * default behavior is to reveal on focus; this flag suppresses that behavior. 3012 * 3013 * @see #setRevealOnFocusHint(boolean) 3014 * @see #getRevealOnFocusHint() 3015 */ 3016 private static final int PFLAG3_NO_REVEAL_ON_FOCUS = 0x4000000; 3017 3018 /* End of masks for mPrivateFlags3 */ 3019 3020 /** 3021 * Always allow a user to over-scroll this view, provided it is a 3022 * view that can scroll. 3023 * 3024 * @see #getOverScrollMode() 3025 * @see #setOverScrollMode(int) 3026 */ 3027 public static final int OVER_SCROLL_ALWAYS = 0; 3028 3029 /** 3030 * Allow a user to over-scroll this view only if the content is large 3031 * enough to meaningfully scroll, provided it is a view that can scroll. 3032 * 3033 * @see #getOverScrollMode() 3034 * @see #setOverScrollMode(int) 3035 */ 3036 public static final int OVER_SCROLL_IF_CONTENT_SCROLLS = 1; 3037 3038 /** 3039 * Never allow a user to over-scroll this view. 3040 * 3041 * @see #getOverScrollMode() 3042 * @see #setOverScrollMode(int) 3043 */ 3044 public static final int OVER_SCROLL_NEVER = 2; 3045 3046 /** 3047 * Special constant for {@link #setSystemUiVisibility(int)}: View has 3048 * requested the system UI (status bar) to be visible (the default). 3049 * 3050 * @see #setSystemUiVisibility(int) 3051 */ 3052 public static final int SYSTEM_UI_FLAG_VISIBLE = 0; 3053 3054 /** 3055 * Flag for {@link #setSystemUiVisibility(int)}: View has requested the 3056 * system UI to enter an unobtrusive "low profile" mode. 3057 * 3058 * <p>This is for use in games, book readers, video players, or any other 3059 * "immersive" application where the usual system chrome is deemed too distracting. 3060 * 3061 * <p>In low profile mode, the status bar and/or navigation icons may dim. 3062 * 3063 * @see #setSystemUiVisibility(int) 3064 */ 3065 public static final int SYSTEM_UI_FLAG_LOW_PROFILE = 0x00000001; 3066 3067 /** 3068 * Flag for {@link #setSystemUiVisibility(int)}: View has requested that the 3069 * system navigation be temporarily hidden. 3070 * 3071 * <p>This is an even less obtrusive state than that called for by 3072 * {@link #SYSTEM_UI_FLAG_LOW_PROFILE}; on devices that draw essential navigation controls 3073 * (Home, Back, and the like) on screen, <code>SYSTEM_UI_FLAG_HIDE_NAVIGATION</code> will cause 3074 * those to disappear. This is useful (in conjunction with the 3075 * {@link android.view.WindowManager.LayoutParams#FLAG_FULLSCREEN FLAG_FULLSCREEN} and 3076 * {@link android.view.WindowManager.LayoutParams#FLAG_LAYOUT_IN_SCREEN FLAG_LAYOUT_IN_SCREEN} 3077 * window flags) for displaying content using every last pixel on the display. 3078 * 3079 * <p>There is a limitation: because navigation controls are so important, the least user 3080 * interaction will cause them to reappear immediately. When this happens, both 3081 * this flag and {@link #SYSTEM_UI_FLAG_FULLSCREEN} will be cleared automatically, 3082 * so that both elements reappear at the same time. 3083 * 3084 * @see #setSystemUiVisibility(int) 3085 */ 3086 public static final int SYSTEM_UI_FLAG_HIDE_NAVIGATION = 0x00000002; 3087 3088 /** 3089 * Flag for {@link #setSystemUiVisibility(int)}: View has requested to go 3090 * into the normal fullscreen mode so that its content can take over the screen 3091 * while still allowing the user to interact with the application. 3092 * 3093 * <p>This has the same visual effect as 3094 * {@link android.view.WindowManager.LayoutParams#FLAG_FULLSCREEN 3095 * WindowManager.LayoutParams.FLAG_FULLSCREEN}, 3096 * meaning that non-critical screen decorations (such as the status bar) will be 3097 * hidden while the user is in the View's window, focusing the experience on 3098 * that content. Unlike the window flag, if you are using ActionBar in 3099 * overlay mode with {@link Window#FEATURE_ACTION_BAR_OVERLAY 3100 * Window.FEATURE_ACTION_BAR_OVERLAY}, then enabling this flag will also 3101 * hide the action bar. 3102 * 3103 * <p>This approach to going fullscreen is best used over the window flag when 3104 * it is a transient state -- that is, the application does this at certain 3105 * points in its user interaction where it wants to allow the user to focus 3106 * on content, but not as a continuous state. For situations where the application 3107 * would like to simply stay full screen the entire time (such as a game that 3108 * wants to take over the screen), the 3109 * {@link android.view.WindowManager.LayoutParams#FLAG_FULLSCREEN window flag} 3110 * is usually a better approach. The state set here will be removed by the system 3111 * in various situations (such as the user moving to another application) like 3112 * the other system UI states. 3113 * 3114 * <p>When using this flag, the application should provide some easy facility 3115 * for the user to go out of it. A common example would be in an e-book 3116 * reader, where tapping on the screen brings back whatever screen and UI 3117 * decorations that had been hidden while the user was immersed in reading 3118 * the book. 3119 * 3120 * @see #setSystemUiVisibility(int) 3121 */ 3122 public static final int SYSTEM_UI_FLAG_FULLSCREEN = 0x00000004; 3123 3124 /** 3125 * Flag for {@link #setSystemUiVisibility(int)}: When using other layout 3126 * flags, we would like a stable view of the content insets given to 3127 * {@link #fitSystemWindows(Rect)}. This means that the insets seen there 3128 * will always represent the worst case that the application can expect 3129 * as a continuous state. In the stock Android UI this is the space for 3130 * the system bar, nav bar, and status bar, but not more transient elements 3131 * such as an input method. 3132 * 3133 * The stable layout your UI sees is based on the system UI modes you can 3134 * switch to. That is, if you specify {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN} 3135 * then you will get a stable layout for changes of the 3136 * {@link #SYSTEM_UI_FLAG_FULLSCREEN} mode; if you specify 3137 * {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN} and 3138 * {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION}, then you can transition 3139 * to {@link #SYSTEM_UI_FLAG_FULLSCREEN} and {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION} 3140 * with a stable layout. (Note that you should avoid using 3141 * {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION} by itself.) 3142 * 3143 * If you have set the window flag {@link WindowManager.LayoutParams#FLAG_FULLSCREEN} 3144 * to hide the status bar (instead of using {@link #SYSTEM_UI_FLAG_FULLSCREEN}), 3145 * then a hidden status bar will be considered a "stable" state for purposes 3146 * here. This allows your UI to continually hide the status bar, while still 3147 * using the system UI flags to hide the action bar while still retaining 3148 * a stable layout. Note that changing the window fullscreen flag will never 3149 * provide a stable layout for a clean transition. 3150 * 3151 * <p>If you are using ActionBar in 3152 * overlay mode with {@link Window#FEATURE_ACTION_BAR_OVERLAY 3153 * Window.FEATURE_ACTION_BAR_OVERLAY}, this flag will also impact the 3154 * insets it adds to those given to the application. 3155 */ 3156 public static final int SYSTEM_UI_FLAG_LAYOUT_STABLE = 0x00000100; 3157 3158 /** 3159 * Flag for {@link #setSystemUiVisibility(int)}: View would like its window 3160 * to be laid out as if it has requested 3161 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, even if it currently hasn't. This 3162 * allows it to avoid artifacts when switching in and out of that mode, at 3163 * the expense that some of its user interface may be covered by screen 3164 * decorations when they are shown. You can perform layout of your inner 3165 * UI elements to account for the navigation system UI through the 3166 * {@link #fitSystemWindows(Rect)} method. 3167 */ 3168 public static final int SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION = 0x00000200; 3169 3170 /** 3171 * Flag for {@link #setSystemUiVisibility(int)}: View would like its window 3172 * to be laid out as if it has requested 3173 * {@link #SYSTEM_UI_FLAG_FULLSCREEN}, even if it currently hasn't. This 3174 * allows it to avoid artifacts when switching in and out of that mode, at 3175 * the expense that some of its user interface may be covered by screen 3176 * decorations when they are shown. You can perform layout of your inner 3177 * UI elements to account for non-fullscreen system UI through the 3178 * {@link #fitSystemWindows(Rect)} method. 3179 */ 3180 public static final int SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN = 0x00000400; 3181 3182 /** 3183 * Flag for {@link #setSystemUiVisibility(int)}: View would like to remain interactive when 3184 * hiding the navigation bar with {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}. If this flag is 3185 * not set, {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION} will be force cleared by the system on any 3186 * user interaction. 3187 * <p>Since this flag is a modifier for {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, it only 3188 * has an effect when used in combination with that flag.</p> 3189 */ 3190 public static final int SYSTEM_UI_FLAG_IMMERSIVE = 0x00000800; 3191 3192 /** 3193 * Flag for {@link #setSystemUiVisibility(int)}: View would like to remain interactive when 3194 * hiding the status bar with {@link #SYSTEM_UI_FLAG_FULLSCREEN} and/or hiding the navigation 3195 * bar with {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}. Use this flag to create an immersive 3196 * experience while also hiding the system bars. If this flag is not set, 3197 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION} will be force cleared by the system on any user 3198 * interaction, and {@link #SYSTEM_UI_FLAG_FULLSCREEN} will be force-cleared by the system 3199 * if the user swipes from the top of the screen. 3200 * <p>When system bars are hidden in immersive mode, they can be revealed temporarily with 3201 * system gestures, such as swiping from the top of the screen. These transient system bars 3202 * will overlay app’s content, may have some degree of transparency, and will automatically 3203 * hide after a short timeout. 3204 * </p><p>Since this flag is a modifier for {@link #SYSTEM_UI_FLAG_FULLSCREEN} and 3205 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, it only has an effect when used in combination 3206 * with one or both of those flags.</p> 3207 */ 3208 public static final int SYSTEM_UI_FLAG_IMMERSIVE_STICKY = 0x00001000; 3209 3210 /** 3211 * Flag for {@link #setSystemUiVisibility(int)}: Requests the status bar to draw in a mode that 3212 * is compatible with light status bar backgrounds. 3213 * 3214 * <p>For this to take effect, the window must request 3215 * {@link android.view.WindowManager.LayoutParams#FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS 3216 * FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS} but not 3217 * {@link android.view.WindowManager.LayoutParams#FLAG_TRANSLUCENT_STATUS 3218 * FLAG_TRANSLUCENT_STATUS}. 3219 * 3220 * @see android.R.attr#windowLightStatusBar 3221 */ 3222 public static final int SYSTEM_UI_FLAG_LIGHT_STATUS_BAR = 0x00002000; 3223 3224 /** 3225 * This flag was previously used for a private API. DO NOT reuse it for a public API as it might 3226 * trigger undefined behavior on older platforms with apps compiled against a new SDK. 3227 */ 3228 private static final int SYSTEM_UI_RESERVED_LEGACY1 = 0x00004000; 3229 3230 /** 3231 * This flag was previously used for a private API. DO NOT reuse it for a public API as it might 3232 * trigger undefined behavior on older platforms with apps compiled against a new SDK. 3233 */ 3234 private static final int SYSTEM_UI_RESERVED_LEGACY2 = 0x00010000; 3235 3236 /** 3237 * Flag for {@link #setSystemUiVisibility(int)}: Requests the navigation bar to draw in a mode 3238 * that is compatible with light navigation bar backgrounds. 3239 * 3240 * <p>For this to take effect, the window must request 3241 * {@link android.view.WindowManager.LayoutParams#FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS 3242 * FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS} but not 3243 * {@link android.view.WindowManager.LayoutParams#FLAG_TRANSLUCENT_NAVIGATION 3244 * FLAG_TRANSLUCENT_NAVIGATION}. 3245 */ 3246 public static final int SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR = 0x00000010; 3247 3248 /** 3249 * @deprecated Use {@link #SYSTEM_UI_FLAG_LOW_PROFILE} instead. 3250 */ 3251 @Deprecated 3252 public static final int STATUS_BAR_HIDDEN = SYSTEM_UI_FLAG_LOW_PROFILE; 3253 3254 /** 3255 * @deprecated Use {@link #SYSTEM_UI_FLAG_VISIBLE} instead. 3256 */ 3257 @Deprecated 3258 public static final int STATUS_BAR_VISIBLE = SYSTEM_UI_FLAG_VISIBLE; 3259 3260 /** 3261 * @hide 3262 * 3263 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3264 * out of the public fields to keep the undefined bits out of the developer's way. 3265 * 3266 * Flag to make the status bar not expandable. Unless you also 3267 * set {@link #STATUS_BAR_DISABLE_NOTIFICATION_ICONS}, new notifications will continue to show. 3268 */ 3269 public static final int STATUS_BAR_DISABLE_EXPAND = 0x00010000; 3270 3271 /** 3272 * @hide 3273 * 3274 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3275 * out of the public fields to keep the undefined bits out of the developer's way. 3276 * 3277 * Flag to hide notification icons and scrolling ticker text. 3278 */ 3279 public static final int STATUS_BAR_DISABLE_NOTIFICATION_ICONS = 0x00020000; 3280 3281 /** 3282 * @hide 3283 * 3284 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3285 * out of the public fields to keep the undefined bits out of the developer's way. 3286 * 3287 * Flag to disable incoming notification alerts. This will not block 3288 * icons, but it will block sound, vibrating and other visual or aural notifications. 3289 */ 3290 public static final int STATUS_BAR_DISABLE_NOTIFICATION_ALERTS = 0x00040000; 3291 3292 /** 3293 * @hide 3294 * 3295 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3296 * out of the public fields to keep the undefined bits out of the developer's way. 3297 * 3298 * Flag to hide only the scrolling ticker. Note that 3299 * {@link #STATUS_BAR_DISABLE_NOTIFICATION_ICONS} implies 3300 * {@link #STATUS_BAR_DISABLE_NOTIFICATION_TICKER}. 3301 */ 3302 public static final int STATUS_BAR_DISABLE_NOTIFICATION_TICKER = 0x00080000; 3303 3304 /** 3305 * @hide 3306 * 3307 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3308 * out of the public fields to keep the undefined bits out of the developer's way. 3309 * 3310 * Flag to hide the center system info area. 3311 */ 3312 public static final int STATUS_BAR_DISABLE_SYSTEM_INFO = 0x00100000; 3313 3314 /** 3315 * @hide 3316 * 3317 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3318 * out of the public fields to keep the undefined bits out of the developer's way. 3319 * 3320 * Flag to hide only the home button. Don't use this 3321 * unless you're a special part of the system UI (i.e., setup wizard, keyguard). 3322 */ 3323 public static final int STATUS_BAR_DISABLE_HOME = 0x00200000; 3324 3325 /** 3326 * @hide 3327 * 3328 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3329 * out of the public fields to keep the undefined bits out of the developer's way. 3330 * 3331 * Flag to hide only the back button. Don't use this 3332 * unless you're a special part of the system UI (i.e., setup wizard, keyguard). 3333 */ 3334 public static final int STATUS_BAR_DISABLE_BACK = 0x00400000; 3335 3336 /** 3337 * @hide 3338 * 3339 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3340 * out of the public fields to keep the undefined bits out of the developer's way. 3341 * 3342 * Flag to hide only the clock. You might use this if your activity has 3343 * its own clock making the status bar's clock redundant. 3344 */ 3345 public static final int STATUS_BAR_DISABLE_CLOCK = 0x00800000; 3346 3347 /** 3348 * @hide 3349 * 3350 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3351 * out of the public fields to keep the undefined bits out of the developer's way. 3352 * 3353 * Flag to hide only the recent apps button. Don't use this 3354 * unless you're a special part of the system UI (i.e., setup wizard, keyguard). 3355 */ 3356 public static final int STATUS_BAR_DISABLE_RECENT = 0x01000000; 3357 3358 /** 3359 * @hide 3360 * 3361 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3362 * out of the public fields to keep the undefined bits out of the developer's way. 3363 * 3364 * Flag to disable the global search gesture. Don't use this 3365 * unless you're a special part of the system UI (i.e., setup wizard, keyguard). 3366 */ 3367 public static final int STATUS_BAR_DISABLE_SEARCH = 0x02000000; 3368 3369 /** 3370 * @hide 3371 * 3372 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3373 * out of the public fields to keep the undefined bits out of the developer's way. 3374 * 3375 * Flag to specify that the status bar is displayed in transient mode. 3376 */ 3377 public static final int STATUS_BAR_TRANSIENT = 0x04000000; 3378 3379 /** 3380 * @hide 3381 * 3382 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3383 * out of the public fields to keep the undefined bits out of the developer's way. 3384 * 3385 * Flag to specify that the navigation bar is displayed in transient mode. 3386 */ 3387 public static final int NAVIGATION_BAR_TRANSIENT = 0x08000000; 3388 3389 /** 3390 * @hide 3391 * 3392 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3393 * out of the public fields to keep the undefined bits out of the developer's way. 3394 * 3395 * Flag to specify that the hidden status bar would like to be shown. 3396 */ 3397 public static final int STATUS_BAR_UNHIDE = 0x10000000; 3398 3399 /** 3400 * @hide 3401 * 3402 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3403 * out of the public fields to keep the undefined bits out of the developer's way. 3404 * 3405 * Flag to specify that the hidden navigation bar would like to be shown. 3406 */ 3407 public static final int NAVIGATION_BAR_UNHIDE = 0x20000000; 3408 3409 /** 3410 * @hide 3411 * 3412 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3413 * out of the public fields to keep the undefined bits out of the developer's way. 3414 * 3415 * Flag to specify that the status bar is displayed in translucent mode. 3416 */ 3417 public static final int STATUS_BAR_TRANSLUCENT = 0x40000000; 3418 3419 /** 3420 * @hide 3421 * 3422 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3423 * out of the public fields to keep the undefined bits out of the developer's way. 3424 * 3425 * Flag to specify that the navigation bar is displayed in translucent mode. 3426 */ 3427 public static final int NAVIGATION_BAR_TRANSLUCENT = 0x80000000; 3428 3429 /** 3430 * @hide 3431 * 3432 * Makes navigation bar transparent (but not the status bar). 3433 */ 3434 public static final int NAVIGATION_BAR_TRANSPARENT = 0x00008000; 3435 3436 /** 3437 * @hide 3438 * 3439 * Makes status bar transparent (but not the navigation bar). 3440 */ 3441 public static final int STATUS_BAR_TRANSPARENT = 0x00000008; 3442 3443 /** 3444 * @hide 3445 * 3446 * Makes both status bar and navigation bar transparent. 3447 */ 3448 public static final int SYSTEM_UI_TRANSPARENT = NAVIGATION_BAR_TRANSPARENT 3449 | STATUS_BAR_TRANSPARENT; 3450 3451 /** 3452 * @hide 3453 */ 3454 public static final int PUBLIC_STATUS_BAR_VISIBILITY_MASK = 0x00003FF7; 3455 3456 /** 3457 * These are the system UI flags that can be cleared by events outside 3458 * of an application. Currently this is just the ability to tap on the 3459 * screen while hiding the navigation bar to have it return. 3460 * @hide 3461 */ 3462 public static final int SYSTEM_UI_CLEARABLE_FLAGS = 3463 SYSTEM_UI_FLAG_LOW_PROFILE | SYSTEM_UI_FLAG_HIDE_NAVIGATION 3464 | SYSTEM_UI_FLAG_FULLSCREEN; 3465 3466 /** 3467 * Flags that can impact the layout in relation to system UI. 3468 */ 3469 public static final int SYSTEM_UI_LAYOUT_FLAGS = 3470 SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION 3471 | SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN; 3472 3473 /** @hide */ 3474 @IntDef(flag = true, 3475 value = { FIND_VIEWS_WITH_TEXT, FIND_VIEWS_WITH_CONTENT_DESCRIPTION }) 3476 @Retention(RetentionPolicy.SOURCE) 3477 public @interface FindViewFlags {} 3478 3479 /** 3480 * Find views that render the specified text. 3481 * 3482 * @see #findViewsWithText(ArrayList, CharSequence, int) 3483 */ 3484 public static final int FIND_VIEWS_WITH_TEXT = 0x00000001; 3485 3486 /** 3487 * Find find views that contain the specified content description. 3488 * 3489 * @see #findViewsWithText(ArrayList, CharSequence, int) 3490 */ 3491 public static final int FIND_VIEWS_WITH_CONTENT_DESCRIPTION = 0x00000002; 3492 3493 /** 3494 * Find views that contain {@link AccessibilityNodeProvider}. Such 3495 * a View is a root of virtual view hierarchy and may contain the searched 3496 * text. If this flag is set Views with providers are automatically 3497 * added and it is a responsibility of the client to call the APIs of 3498 * the provider to determine whether the virtual tree rooted at this View 3499 * contains the text, i.e. getting the list of {@link AccessibilityNodeInfo}s 3500 * representing the virtual views with this text. 3501 * 3502 * @see #findViewsWithText(ArrayList, CharSequence, int) 3503 * 3504 * @hide 3505 */ 3506 public static final int FIND_VIEWS_WITH_ACCESSIBILITY_NODE_PROVIDERS = 0x00000004; 3507 3508 /** 3509 * The undefined cursor position. 3510 * 3511 * @hide 3512 */ 3513 public static final int ACCESSIBILITY_CURSOR_POSITION_UNDEFINED = -1; 3514 3515 /** 3516 * Indicates that the screen has changed state and is now off. 3517 * 3518 * @see #onScreenStateChanged(int) 3519 */ 3520 public static final int SCREEN_STATE_OFF = 0x0; 3521 3522 /** 3523 * Indicates that the screen has changed state and is now on. 3524 * 3525 * @see #onScreenStateChanged(int) 3526 */ 3527 public static final int SCREEN_STATE_ON = 0x1; 3528 3529 /** 3530 * Indicates no axis of view scrolling. 3531 */ 3532 public static final int SCROLL_AXIS_NONE = 0; 3533 3534 /** 3535 * Indicates scrolling along the horizontal axis. 3536 */ 3537 public static final int SCROLL_AXIS_HORIZONTAL = 1 << 0; 3538 3539 /** 3540 * Indicates scrolling along the vertical axis. 3541 */ 3542 public static final int SCROLL_AXIS_VERTICAL = 1 << 1; 3543 3544 /** 3545 * Controls the over-scroll mode for this view. 3546 * See {@link #overScrollBy(int, int, int, int, int, int, int, int, boolean)}, 3547 * {@link #OVER_SCROLL_ALWAYS}, {@link #OVER_SCROLL_IF_CONTENT_SCROLLS}, 3548 * and {@link #OVER_SCROLL_NEVER}. 3549 */ 3550 private int mOverScrollMode; 3551 3552 /** 3553 * The parent this view is attached to. 3554 * {@hide} 3555 * 3556 * @see #getParent() 3557 */ 3558 protected ViewParent mParent; 3559 3560 /** 3561 * {@hide} 3562 */ 3563 AttachInfo mAttachInfo; 3564 3565 /** 3566 * {@hide} 3567 */ 3568 @ViewDebug.ExportedProperty(flagMapping = { 3569 @ViewDebug.FlagToString(mask = PFLAG_FORCE_LAYOUT, equals = PFLAG_FORCE_LAYOUT, 3570 name = "FORCE_LAYOUT"), 3571 @ViewDebug.FlagToString(mask = PFLAG_LAYOUT_REQUIRED, equals = PFLAG_LAYOUT_REQUIRED, 3572 name = "LAYOUT_REQUIRED"), 3573 @ViewDebug.FlagToString(mask = PFLAG_DRAWING_CACHE_VALID, equals = PFLAG_DRAWING_CACHE_VALID, 3574 name = "DRAWING_CACHE_INVALID", outputIf = false), 3575 @ViewDebug.FlagToString(mask = PFLAG_DRAWN, equals = PFLAG_DRAWN, name = "DRAWN", outputIf = true), 3576 @ViewDebug.FlagToString(mask = PFLAG_DRAWN, equals = PFLAG_DRAWN, name = "NOT_DRAWN", outputIf = false), 3577 @ViewDebug.FlagToString(mask = PFLAG_DIRTY_MASK, equals = PFLAG_DIRTY_OPAQUE, name = "DIRTY_OPAQUE"), 3578 @ViewDebug.FlagToString(mask = PFLAG_DIRTY_MASK, equals = PFLAG_DIRTY, name = "DIRTY") 3579 }, formatToHexString = true) 3580 3581 /* @hide */ 3582 public int mPrivateFlags; 3583 int mPrivateFlags2; 3584 int mPrivateFlags3; 3585 3586 /** 3587 * This view's request for the visibility of the status bar. 3588 * @hide 3589 */ 3590 @ViewDebug.ExportedProperty(flagMapping = { 3591 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_LOW_PROFILE, 3592 equals = SYSTEM_UI_FLAG_LOW_PROFILE, 3593 name = "SYSTEM_UI_FLAG_LOW_PROFILE", outputIf = true), 3594 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_HIDE_NAVIGATION, 3595 equals = SYSTEM_UI_FLAG_HIDE_NAVIGATION, 3596 name = "SYSTEM_UI_FLAG_HIDE_NAVIGATION", outputIf = true), 3597 @ViewDebug.FlagToString(mask = PUBLIC_STATUS_BAR_VISIBILITY_MASK, 3598 equals = SYSTEM_UI_FLAG_VISIBLE, 3599 name = "SYSTEM_UI_FLAG_VISIBLE", outputIf = true) 3600 }, formatToHexString = true) 3601 int mSystemUiVisibility; 3602 3603 /** 3604 * Reference count for transient state. 3605 * @see #setHasTransientState(boolean) 3606 */ 3607 int mTransientStateCount = 0; 3608 3609 /** 3610 * Count of how many windows this view has been attached to. 3611 */ 3612 int mWindowAttachCount; 3613 3614 /** 3615 * The layout parameters associated with this view and used by the parent 3616 * {@link android.view.ViewGroup} to determine how this view should be 3617 * laid out. 3618 * {@hide} 3619 */ 3620 protected ViewGroup.LayoutParams mLayoutParams; 3621 3622 /** 3623 * The view flags hold various views states. 3624 * {@hide} 3625 */ 3626 @ViewDebug.ExportedProperty(formatToHexString = true) 3627 int mViewFlags; 3628 3629 static class TransformationInfo { 3630 /** 3631 * The transform matrix for the View. This transform is calculated internally 3632 * based on the translation, rotation, and scale properties. 3633 * 3634 * Do *not* use this variable directly; instead call getMatrix(), which will 3635 * load the value from the View's RenderNode. 3636 */ 3637 private final Matrix mMatrix = new Matrix(); 3638 3639 /** 3640 * The inverse transform matrix for the View. This transform is calculated 3641 * internally based on the translation, rotation, and scale properties. 3642 * 3643 * Do *not* use this variable directly; instead call getInverseMatrix(), 3644 * which will load the value from the View's RenderNode. 3645 */ 3646 private Matrix mInverseMatrix; 3647 3648 /** 3649 * The opacity of the View. This is a value from 0 to 1, where 0 means 3650 * completely transparent and 1 means completely opaque. 3651 */ 3652 @ViewDebug.ExportedProperty 3653 float mAlpha = 1f; 3654 3655 /** 3656 * The opacity of the view as manipulated by the Fade transition. This is a hidden 3657 * property only used by transitions, which is composited with the other alpha 3658 * values to calculate the final visual alpha value. 3659 */ 3660 float mTransitionAlpha = 1f; 3661 } 3662 3663 /** @hide */ 3664 public TransformationInfo mTransformationInfo; 3665 3666 /** 3667 * Current clip bounds. to which all drawing of this view are constrained. 3668 */ 3669 Rect mClipBounds = null; 3670 3671 private boolean mLastIsOpaque; 3672 3673 /** 3674 * The distance in pixels from the left edge of this view's parent 3675 * to the left edge of this view. 3676 * {@hide} 3677 */ 3678 @ViewDebug.ExportedProperty(category = "layout") 3679 protected int mLeft; 3680 /** 3681 * The distance in pixels from the left edge of this view's parent 3682 * to the right edge of this view. 3683 * {@hide} 3684 */ 3685 @ViewDebug.ExportedProperty(category = "layout") 3686 protected int mRight; 3687 /** 3688 * The distance in pixels from the top edge of this view's parent 3689 * to the top edge of this view. 3690 * {@hide} 3691 */ 3692 @ViewDebug.ExportedProperty(category = "layout") 3693 protected int mTop; 3694 /** 3695 * The distance in pixels from the top edge of this view's parent 3696 * to the bottom edge of this view. 3697 * {@hide} 3698 */ 3699 @ViewDebug.ExportedProperty(category = "layout") 3700 protected int mBottom; 3701 3702 /** 3703 * The offset, in pixels, by which the content of this view is scrolled 3704 * horizontally. 3705 * {@hide} 3706 */ 3707 @ViewDebug.ExportedProperty(category = "scrolling") 3708 protected int mScrollX; 3709 /** 3710 * The offset, in pixels, by which the content of this view is scrolled 3711 * vertically. 3712 * {@hide} 3713 */ 3714 @ViewDebug.ExportedProperty(category = "scrolling") 3715 protected int mScrollY; 3716 3717 /** 3718 * The left padding in pixels, that is the distance in pixels between the 3719 * left edge of this view and the left edge of its content. 3720 * {@hide} 3721 */ 3722 @ViewDebug.ExportedProperty(category = "padding") 3723 protected int mPaddingLeft = 0; 3724 /** 3725 * The right padding in pixels, that is the distance in pixels between the 3726 * right edge of this view and the right edge of its content. 3727 * {@hide} 3728 */ 3729 @ViewDebug.ExportedProperty(category = "padding") 3730 protected int mPaddingRight = 0; 3731 /** 3732 * The top padding in pixels, that is the distance in pixels between the 3733 * top edge of this view and the top edge of its content. 3734 * {@hide} 3735 */ 3736 @ViewDebug.ExportedProperty(category = "padding") 3737 protected int mPaddingTop; 3738 /** 3739 * The bottom padding in pixels, that is the distance in pixels between the 3740 * bottom edge of this view and the bottom edge of its content. 3741 * {@hide} 3742 */ 3743 @ViewDebug.ExportedProperty(category = "padding") 3744 protected int mPaddingBottom; 3745 3746 /** 3747 * The layout insets in pixels, that is the distance in pixels between the 3748 * visible edges of this view its bounds. 3749 */ 3750 private Insets mLayoutInsets; 3751 3752 /** 3753 * Briefly describes the view and is primarily used for accessibility support. 3754 */ 3755 private CharSequence mContentDescription; 3756 3757 /** 3758 * Specifies the id of a view for which this view serves as a label for 3759 * accessibility purposes. 3760 */ 3761 private int mLabelForId = View.NO_ID; 3762 3763 /** 3764 * Predicate for matching labeled view id with its label for 3765 * accessibility purposes. 3766 */ 3767 private MatchLabelForPredicate mMatchLabelForPredicate; 3768 3769 /** 3770 * Specifies a view before which this one is visited in accessibility traversal. 3771 */ 3772 private int mAccessibilityTraversalBeforeId = NO_ID; 3773 3774 /** 3775 * Specifies a view after which this one is visited in accessibility traversal. 3776 */ 3777 private int mAccessibilityTraversalAfterId = NO_ID; 3778 3779 /** 3780 * Predicate for matching a view by its id. 3781 */ 3782 private MatchIdPredicate mMatchIdPredicate; 3783 3784 /** 3785 * Cache the paddingRight set by the user to append to the scrollbar's size. 3786 * 3787 * @hide 3788 */ 3789 @ViewDebug.ExportedProperty(category = "padding") 3790 protected int mUserPaddingRight; 3791 3792 /** 3793 * Cache the paddingBottom set by the user to append to the scrollbar's size. 3794 * 3795 * @hide 3796 */ 3797 @ViewDebug.ExportedProperty(category = "padding") 3798 protected int mUserPaddingBottom; 3799 3800 /** 3801 * Cache the paddingLeft set by the user to append to the scrollbar's size. 3802 * 3803 * @hide 3804 */ 3805 @ViewDebug.ExportedProperty(category = "padding") 3806 protected int mUserPaddingLeft; 3807 3808 /** 3809 * Cache the paddingStart set by the user to append to the scrollbar's size. 3810 * 3811 */ 3812 @ViewDebug.ExportedProperty(category = "padding") 3813 int mUserPaddingStart; 3814 3815 /** 3816 * Cache the paddingEnd set by the user to append to the scrollbar's size. 3817 * 3818 */ 3819 @ViewDebug.ExportedProperty(category = "padding") 3820 int mUserPaddingEnd; 3821 3822 /** 3823 * Cache initial left padding. 3824 * 3825 * @hide 3826 */ 3827 int mUserPaddingLeftInitial; 3828 3829 /** 3830 * Cache initial right padding. 3831 * 3832 * @hide 3833 */ 3834 int mUserPaddingRightInitial; 3835 3836 /** 3837 * Default undefined padding 3838 */ 3839 private static final int UNDEFINED_PADDING = Integer.MIN_VALUE; 3840 3841 /** 3842 * Cache if a left padding has been defined 3843 */ 3844 private boolean mLeftPaddingDefined = false; 3845 3846 /** 3847 * Cache if a right padding has been defined 3848 */ 3849 private boolean mRightPaddingDefined = false; 3850 3851 /** 3852 * @hide 3853 */ 3854 int mOldWidthMeasureSpec = Integer.MIN_VALUE; 3855 /** 3856 * @hide 3857 */ 3858 int mOldHeightMeasureSpec = Integer.MIN_VALUE; 3859 3860 private LongSparseLongArray mMeasureCache; 3861 3862 @ViewDebug.ExportedProperty(deepExport = true, prefix = "bg_") 3863 private Drawable mBackground; 3864 private TintInfo mBackgroundTint; 3865 3866 @ViewDebug.ExportedProperty(deepExport = true, prefix = "fg_") 3867 private ForegroundInfo mForegroundInfo; 3868 3869 private Drawable mScrollIndicatorDrawable; 3870 3871 /** 3872 * RenderNode used for backgrounds. 3873 * <p> 3874 * When non-null and valid, this is expected to contain an up-to-date copy 3875 * of the background drawable. It is cleared on temporary detach, and reset 3876 * on cleanup. 3877 */ 3878 private RenderNode mBackgroundRenderNode; 3879 3880 private int mBackgroundResource; 3881 private boolean mBackgroundSizeChanged; 3882 3883 /** The default focus highlight. 3884 * @see #mDefaultFocusHighlightEnabled 3885 * @see Drawable#hasFocusStateSpecified() 3886 */ 3887 private Drawable mDefaultFocusHighlight; 3888 private Drawable mDefaultFocusHighlightCache; 3889 private boolean mDefaultFocusHighlightSizeChanged; 3890 /** 3891 * True if the default focus highlight is needed on the target device. 3892 */ 3893 private static boolean sUseDefaultFocusHighlight; 3894 3895 private String mTransitionName; 3896 3897 static class TintInfo { 3898 ColorStateList mTintList; 3899 PorterDuff.Mode mTintMode; 3900 boolean mHasTintMode; 3901 boolean mHasTintList; 3902 } 3903 3904 private static class ForegroundInfo { 3905 private Drawable mDrawable; 3906 private TintInfo mTintInfo; 3907 private int mGravity = Gravity.FILL; 3908 private boolean mInsidePadding = true; 3909 private boolean mBoundsChanged = true; 3910 private final Rect mSelfBounds = new Rect(); 3911 private final Rect mOverlayBounds = new Rect(); 3912 } 3913 3914 static class ListenerInfo { 3915 /** 3916 * Listener used to dispatch focus change events. 3917 * This field should be made private, so it is hidden from the SDK. 3918 * {@hide} 3919 */ 3920 protected OnFocusChangeListener mOnFocusChangeListener; 3921 3922 /** 3923 * Listeners for layout change events. 3924 */ 3925 private ArrayList<OnLayoutChangeListener> mOnLayoutChangeListeners; 3926 3927 protected OnScrollChangeListener mOnScrollChangeListener; 3928 3929 /** 3930 * Listeners for attach events. 3931 */ 3932 private CopyOnWriteArrayList<OnAttachStateChangeListener> mOnAttachStateChangeListeners; 3933 3934 /** 3935 * Listener used to dispatch click events. 3936 * This field should be made private, so it is hidden from the SDK. 3937 * {@hide} 3938 */ 3939 public OnClickListener mOnClickListener; 3940 3941 /** 3942 * Listener used to dispatch long click events. 3943 * This field should be made private, so it is hidden from the SDK. 3944 * {@hide} 3945 */ 3946 protected OnLongClickListener mOnLongClickListener; 3947 3948 /** 3949 * Listener used to dispatch context click events. This field should be made private, so it 3950 * is hidden from the SDK. 3951 * {@hide} 3952 */ 3953 protected OnContextClickListener mOnContextClickListener; 3954 3955 /** 3956 * Listener used to build the context menu. 3957 * This field should be made private, so it is hidden from the SDK. 3958 * {@hide} 3959 */ 3960 protected OnCreateContextMenuListener mOnCreateContextMenuListener; 3961 3962 private OnKeyListener mOnKeyListener; 3963 3964 private OnTouchListener mOnTouchListener; 3965 3966 private OnHoverListener mOnHoverListener; 3967 3968 private OnGenericMotionListener mOnGenericMotionListener; 3969 3970 private OnDragListener mOnDragListener; 3971 3972 private OnSystemUiVisibilityChangeListener mOnSystemUiVisibilityChangeListener; 3973 3974 OnApplyWindowInsetsListener mOnApplyWindowInsetsListener; 3975 3976 OnCapturedPointerListener mOnCapturedPointerListener; 3977 } 3978 3979 ListenerInfo mListenerInfo; 3980 3981 private static class TooltipInfo { 3982 /** 3983 * Text to be displayed in a tooltip popup. 3984 */ 3985 @Nullable 3986 CharSequence mTooltipText; 3987 3988 /** 3989 * View-relative position of the tooltip anchor point. 3990 */ 3991 int mAnchorX; 3992 int mAnchorY; 3993 3994 /** 3995 * The tooltip popup. 3996 */ 3997 @Nullable 3998 TooltipPopup mTooltipPopup; 3999 4000 /** 4001 * Set to true if the tooltip was shown as a result of a long click. 4002 */ 4003 boolean mTooltipFromLongClick; 4004 4005 /** 4006 * Keep these Runnables so that they can be used to reschedule. 4007 */ 4008 Runnable mShowTooltipRunnable; 4009 Runnable mHideTooltipRunnable; 4010 } 4011 4012 TooltipInfo mTooltipInfo; 4013 4014 // Temporary values used to hold (x,y) coordinates when delegating from the 4015 // two-arg performLongClick() method to the legacy no-arg version. 4016 private float mLongClickX = Float.NaN; 4017 private float mLongClickY = Float.NaN; 4018 4019 /** 4020 * The application environment this view lives in. 4021 * This field should be made private, so it is hidden from the SDK. 4022 * {@hide} 4023 */ 4024 @ViewDebug.ExportedProperty(deepExport = true) 4025 protected Context mContext; 4026 4027 private final Resources mResources; 4028 4029 private ScrollabilityCache mScrollCache; 4030 4031 private int[] mDrawableState = null; 4032 4033 ViewOutlineProvider mOutlineProvider = ViewOutlineProvider.BACKGROUND; 4034 4035 /** 4036 * Animator that automatically runs based on state changes. 4037 */ 4038 private StateListAnimator mStateListAnimator; 4039 4040 /** 4041 * When this view has focus and the next focus is {@link #FOCUS_LEFT}, 4042 * the user may specify which view to go to next. 4043 */ 4044 private int mNextFocusLeftId = View.NO_ID; 4045 4046 /** 4047 * When this view has focus and the next focus is {@link #FOCUS_RIGHT}, 4048 * the user may specify which view to go to next. 4049 */ 4050 private int mNextFocusRightId = View.NO_ID; 4051 4052 /** 4053 * When this view has focus and the next focus is {@link #FOCUS_UP}, 4054 * the user may specify which view to go to next. 4055 */ 4056 private int mNextFocusUpId = View.NO_ID; 4057 4058 /** 4059 * When this view has focus and the next focus is {@link #FOCUS_DOWN}, 4060 * the user may specify which view to go to next. 4061 */ 4062 private int mNextFocusDownId = View.NO_ID; 4063 4064 /** 4065 * When this view has focus and the next focus is {@link #FOCUS_FORWARD}, 4066 * the user may specify which view to go to next. 4067 */ 4068 int mNextFocusForwardId = View.NO_ID; 4069 4070 /** 4071 * User-specified next keyboard navigation cluster in the {@link #FOCUS_FORWARD} direction. 4072 * 4073 * @see #findUserSetNextKeyboardNavigationCluster(View, int) 4074 */ 4075 int mNextClusterForwardId = View.NO_ID; 4076 4077 /** 4078 * Whether this View should use a default focus highlight when it gets focused but doesn't 4079 * have {@link android.R.attr#state_focused} defined in its background. 4080 */ 4081 boolean mDefaultFocusHighlightEnabled = true; 4082 4083 private CheckForLongPress mPendingCheckForLongPress; 4084 private CheckForTap mPendingCheckForTap = null; 4085 private PerformClick mPerformClick; 4086 private SendViewScrolledAccessibilityEvent mSendViewScrolledAccessibilityEvent; 4087 4088 private UnsetPressedState mUnsetPressedState; 4089 4090 /** 4091 * Whether the long press's action has been invoked. The tap's action is invoked on the 4092 * up event while a long press is invoked as soon as the long press duration is reached, so 4093 * a long press could be performed before the tap is checked, in which case the tap's action 4094 * should not be invoked. 4095 */ 4096 private boolean mHasPerformedLongPress; 4097 4098 /** 4099 * Whether a context click button is currently pressed down. This is true when the stylus is 4100 * touching the screen and the primary button has been pressed, or if a mouse's right button is 4101 * pressed. This is false once the button is released or if the stylus has been lifted. 4102 */ 4103 private boolean mInContextButtonPress; 4104 4105 /** 4106 * Whether the next up event should be ignored for the purposes of gesture recognition. This is 4107 * true after a stylus button press has occured, when the next up event should not be recognized 4108 * as a tap. 4109 */ 4110 private boolean mIgnoreNextUpEvent; 4111 4112 /** 4113 * The minimum height of the view. We'll try our best to have the height 4114 * of this view to at least this amount. 4115 */ 4116 @ViewDebug.ExportedProperty(category = "measurement") 4117 private int mMinHeight; 4118 4119 /** 4120 * The minimum width of the view. We'll try our best to have the width 4121 * of this view to at least this amount. 4122 */ 4123 @ViewDebug.ExportedProperty(category = "measurement") 4124 private int mMinWidth; 4125 4126 /** 4127 * The delegate to handle touch events that are physically in this view 4128 * but should be handled by another view. 4129 */ 4130 private TouchDelegate mTouchDelegate = null; 4131 4132 /** 4133 * Solid color to use as a background when creating the drawing cache. Enables 4134 * the cache to use 16 bit bitmaps instead of 32 bit. 4135 */ 4136 private int mDrawingCacheBackgroundColor = 0; 4137 4138 /** 4139 * Special tree observer used when mAttachInfo is null. 4140 */ 4141 private ViewTreeObserver mFloatingTreeObserver; 4142 4143 /** 4144 * Cache the touch slop from the context that created the view. 4145 */ 4146 private int mTouchSlop; 4147 4148 /** 4149 * Object that handles automatic animation of view properties. 4150 */ 4151 private ViewPropertyAnimator mAnimator = null; 4152 4153 /** 4154 * List of registered FrameMetricsObservers. 4155 */ 4156 private ArrayList<FrameMetricsObserver> mFrameMetricsObservers; 4157 4158 /** 4159 * Flag indicating that a drag can cross window boundaries. When 4160 * {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, int)} is called 4161 * with this flag set, all visible applications with targetSdkVersion >= 4162 * {@link android.os.Build.VERSION_CODES#N API 24} will be able to participate 4163 * in the drag operation and receive the dragged content. 4164 * 4165 * <p>If this is the only flag set, then the drag recipient will only have access to text data 4166 * and intents contained in the {@link ClipData} object. Access to URIs contained in the 4167 * {@link ClipData} is determined by other DRAG_FLAG_GLOBAL_* flags</p> 4168 */ 4169 public static final int DRAG_FLAG_GLOBAL = 1 << 8; // 256 4170 4171 /** 4172 * When this flag is used with {@link #DRAG_FLAG_GLOBAL}, the drag recipient will be able to 4173 * request read access to the content URI(s) contained in the {@link ClipData} object. 4174 * @see android.content.Intent#FLAG_GRANT_READ_URI_PERMISSION 4175 */ 4176 public static final int DRAG_FLAG_GLOBAL_URI_READ = Intent.FLAG_GRANT_READ_URI_PERMISSION; 4177 4178 /** 4179 * When this flag is used with {@link #DRAG_FLAG_GLOBAL}, the drag recipient will be able to 4180 * request write access to the content URI(s) contained in the {@link ClipData} object. 4181 * @see android.content.Intent#FLAG_GRANT_WRITE_URI_PERMISSION 4182 */ 4183 public static final int DRAG_FLAG_GLOBAL_URI_WRITE = Intent.FLAG_GRANT_WRITE_URI_PERMISSION; 4184 4185 /** 4186 * When this flag is used with {@link #DRAG_FLAG_GLOBAL_URI_READ} and/or {@link 4187 * #DRAG_FLAG_GLOBAL_URI_WRITE}, the URI permission grant can be persisted across device 4188 * reboots until explicitly revoked with 4189 * {@link android.content.Context#revokeUriPermission(Uri, int)} Context.revokeUriPermission}. 4190 * @see android.content.Intent#FLAG_GRANT_PERSISTABLE_URI_PERMISSION 4191 */ 4192 public static final int DRAG_FLAG_GLOBAL_PERSISTABLE_URI_PERMISSION = 4193 Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION; 4194 4195 /** 4196 * When this flag is used with {@link #DRAG_FLAG_GLOBAL_URI_READ} and/or {@link 4197 * #DRAG_FLAG_GLOBAL_URI_WRITE}, the URI permission grant applies to any URI that is a prefix 4198 * match against the original granted URI. 4199 * @see android.content.Intent#FLAG_GRANT_PREFIX_URI_PERMISSION 4200 */ 4201 public static final int DRAG_FLAG_GLOBAL_PREFIX_URI_PERMISSION = 4202 Intent.FLAG_GRANT_PREFIX_URI_PERMISSION; 4203 4204 /** 4205 * Flag indicating that the drag shadow will be opaque. When 4206 * {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, int)} is called 4207 * with this flag set, the drag shadow will be opaque, otherwise, it will be semitransparent. 4208 */ 4209 public static final int DRAG_FLAG_OPAQUE = 1 << 9; 4210 4211 /** 4212 * Vertical scroll factor cached by {@link #getVerticalScrollFactor}. 4213 */ 4214 private float mVerticalScrollFactor; 4215 4216 /** 4217 * Position of the vertical scroll bar. 4218 */ 4219 private int mVerticalScrollbarPosition; 4220 4221 /** 4222 * Position the scroll bar at the default position as determined by the system. 4223 */ 4224 public static final int SCROLLBAR_POSITION_DEFAULT = 0; 4225 4226 /** 4227 * Position the scroll bar along the left edge. 4228 */ 4229 public static final int SCROLLBAR_POSITION_LEFT = 1; 4230 4231 /** 4232 * Position the scroll bar along the right edge. 4233 */ 4234 public static final int SCROLLBAR_POSITION_RIGHT = 2; 4235 4236 /** 4237 * Indicates that the view does not have a layer. 4238 * 4239 * @see #getLayerType() 4240 * @see #setLayerType(int, android.graphics.Paint) 4241 * @see #LAYER_TYPE_SOFTWARE 4242 * @see #LAYER_TYPE_HARDWARE 4243 */ 4244 public static final int LAYER_TYPE_NONE = 0; 4245 4246 /** 4247 * <p>Indicates that the view has a software layer. A software layer is backed 4248 * by a bitmap and causes the view to be rendered using Android's software 4249 * rendering pipeline, even if hardware acceleration is enabled.</p> 4250 * 4251 * <p>Software layers have various usages:</p> 4252 * <p>When the application is not using hardware acceleration, a software layer 4253 * is useful to apply a specific color filter and/or blending mode and/or 4254 * translucency to a view and all its children.</p> 4255 * <p>When the application is using hardware acceleration, a software layer 4256 * is useful to render drawing primitives not supported by the hardware 4257 * accelerated pipeline. It can also be used to cache a complex view tree 4258 * into a texture and reduce the complexity of drawing operations. For instance, 4259 * when animating a complex view tree with a translation, a software layer can 4260 * be used to render the view tree only once.</p> 4261 * <p>Software layers should be avoided when the affected view tree updates 4262 * often. Every update will require to re-render the software layer, which can 4263 * potentially be slow (particularly when hardware acceleration is turned on 4264 * since the layer will have to be uploaded into a hardware texture after every 4265 * update.)</p> 4266 * 4267 * @see #getLayerType() 4268 * @see #setLayerType(int, android.graphics.Paint) 4269 * @see #LAYER_TYPE_NONE 4270 * @see #LAYER_TYPE_HARDWARE 4271 */ 4272 public static final int LAYER_TYPE_SOFTWARE = 1; 4273 4274 /** 4275 * <p>Indicates that the view has a hardware layer. A hardware layer is backed 4276 * by a hardware specific texture (generally Frame Buffer Objects or FBO on 4277 * OpenGL hardware) and causes the view to be rendered using Android's hardware 4278 * rendering pipeline, but only if hardware acceleration is turned on for the 4279 * view hierarchy. When hardware acceleration is turned off, hardware layers 4280 * behave exactly as {@link #LAYER_TYPE_SOFTWARE software layers}.</p> 4281 * 4282 * <p>A hardware layer is useful to apply a specific color filter and/or 4283 * blending mode and/or translucency to a view and all its children.</p> 4284 * <p>A hardware layer can be used to cache a complex view tree into a 4285 * texture and reduce the complexity of drawing operations. For instance, 4286 * when animating a complex view tree with a translation, a hardware layer can 4287 * be used to render the view tree only once.</p> 4288 * <p>A hardware layer can also be used to increase the rendering quality when 4289 * rotation transformations are applied on a view. It can also be used to 4290 * prevent potential clipping issues when applying 3D transforms on a view.</p> 4291 * 4292 * @see #getLayerType() 4293 * @see #setLayerType(int, android.graphics.Paint) 4294 * @see #LAYER_TYPE_NONE 4295 * @see #LAYER_TYPE_SOFTWARE 4296 */ 4297 public static final int LAYER_TYPE_HARDWARE = 2; 4298 4299 @ViewDebug.ExportedProperty(category = "drawing", mapping = { 4300 @ViewDebug.IntToString(from = LAYER_TYPE_NONE, to = "NONE"), 4301 @ViewDebug.IntToString(from = LAYER_TYPE_SOFTWARE, to = "SOFTWARE"), 4302 @ViewDebug.IntToString(from = LAYER_TYPE_HARDWARE, to = "HARDWARE") 4303 }) 4304 int mLayerType = LAYER_TYPE_NONE; 4305 Paint mLayerPaint; 4306 4307 /** 4308 * Set to true when drawing cache is enabled and cannot be created. 4309 * 4310 * @hide 4311 */ 4312 public boolean mCachingFailed; 4313 private Bitmap mDrawingCache; 4314 private Bitmap mUnscaledDrawingCache; 4315 4316 /** 4317 * RenderNode holding View properties, potentially holding a DisplayList of View content. 4318 * <p> 4319 * When non-null and valid, this is expected to contain an up-to-date copy 4320 * of the View content. Its DisplayList content is cleared on temporary detach and reset on 4321 * cleanup. 4322 */ 4323 final RenderNode mRenderNode; 4324 4325 /** 4326 * Set to true when the view is sending hover accessibility events because it 4327 * is the innermost hovered view. 4328 */ 4329 private boolean mSendingHoverAccessibilityEvents; 4330 4331 /** 4332 * Delegate for injecting accessibility functionality. 4333 */ 4334 AccessibilityDelegate mAccessibilityDelegate; 4335 4336 /** 4337 * The view's overlay layer. Developers get a reference to the overlay via getOverlay() 4338 * and add/remove objects to/from the overlay directly through the Overlay methods. 4339 */ 4340 ViewOverlay mOverlay; 4341 4342 /** 4343 * The currently active parent view for receiving delegated nested scrolling events. 4344 * This is set by {@link #startNestedScroll(int)} during a touch interaction and cleared 4345 * by {@link #stopNestedScroll()} at the same point where we clear 4346 * requestDisallowInterceptTouchEvent. 4347 */ 4348 private ViewParent mNestedScrollingParent; 4349 4350 /** 4351 * Consistency verifier for debugging purposes. 4352 * @hide 4353 */ 4354 protected final InputEventConsistencyVerifier mInputEventConsistencyVerifier = 4355 InputEventConsistencyVerifier.isInstrumentationEnabled() ? 4356 new InputEventConsistencyVerifier(this, 0) : null; 4357 4358 private static final AtomicInteger sNextGeneratedId = new AtomicInteger(1); 4359 4360 private int[] mTempNestedScrollConsumed; 4361 4362 /** 4363 * An overlay is going to draw this View instead of being drawn as part of this 4364 * View's parent. mGhostView is the View in the Overlay that must be invalidated 4365 * when this view is invalidated. 4366 */ 4367 GhostView mGhostView; 4368 4369 /** 4370 * Holds pairs of adjacent attribute data: attribute name followed by its value. 4371 * @hide 4372 */ 4373 @ViewDebug.ExportedProperty(category = "attributes", hasAdjacentMapping = true) 4374 public String[] mAttributes; 4375 4376 /** 4377 * Maps a Resource id to its name. 4378 */ 4379 private static SparseArray<String> mAttributeMap; 4380 4381 /** 4382 * Queue of pending runnables. Used to postpone calls to post() until this 4383 * view is attached and has a handler. 4384 */ 4385 private HandlerActionQueue mRunQueue; 4386 4387 /** 4388 * The pointer icon when the mouse hovers on this view. The default is null. 4389 */ 4390 private PointerIcon mPointerIcon; 4391 4392 /** 4393 * @hide 4394 */ 4395 String mStartActivityRequestWho; 4396 4397 @Nullable 4398 private RoundScrollbarRenderer mRoundScrollbarRenderer; 4399 4400 /** Used to delay visibility updates sent to the autofill manager */ 4401 private Handler mVisibilityChangeForAutofillHandler; 4402 4403 /** 4404 * Simple constructor to use when creating a view from code. 4405 * 4406 * @param context The Context the view is running in, through which it can 4407 * access the current theme, resources, etc. 4408 */ 4409 public View(Context context) { 4410 mContext = context; 4411 mResources = context != null ? context.getResources() : null; 4412 mViewFlags = SOUND_EFFECTS_ENABLED | HAPTIC_FEEDBACK_ENABLED | FOCUSABLE_AUTO; 4413 // Set some flags defaults 4414 mPrivateFlags2 = 4415 (LAYOUT_DIRECTION_DEFAULT << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT) | 4416 (TEXT_DIRECTION_DEFAULT << PFLAG2_TEXT_DIRECTION_MASK_SHIFT) | 4417 (PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT) | 4418 (TEXT_ALIGNMENT_DEFAULT << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT) | 4419 (PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT) | 4420 (IMPORTANT_FOR_ACCESSIBILITY_DEFAULT << PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT); 4421 mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); 4422 setOverScrollMode(OVER_SCROLL_IF_CONTENT_SCROLLS); 4423 mUserPaddingStart = UNDEFINED_PADDING; 4424 mUserPaddingEnd = UNDEFINED_PADDING; 4425 mRenderNode = RenderNode.create(getClass().getName(), this); 4426 4427 if (!sCompatibilityDone && context != null) { 4428 final int targetSdkVersion = context.getApplicationInfo().targetSdkVersion; 4429 4430 // Older apps may need this compatibility hack for measurement. 4431 sUseBrokenMakeMeasureSpec = targetSdkVersion <= Build.VERSION_CODES.JELLY_BEAN_MR1; 4432 4433 // Older apps expect onMeasure() to always be called on a layout pass, regardless 4434 // of whether a layout was requested on that View. 4435 sIgnoreMeasureCache = targetSdkVersion < Build.VERSION_CODES.KITKAT; 4436 4437 Canvas.sCompatibilityRestore = targetSdkVersion < Build.VERSION_CODES.M; 4438 4439 // In M and newer, our widgets can pass a "hint" value in the size 4440 // for UNSPECIFIED MeasureSpecs. This lets child views of scrolling containers 4441 // know what the expected parent size is going to be, so e.g. list items can size 4442 // themselves at 1/3 the size of their container. It breaks older apps though, 4443 // specifically apps that use some popular open source libraries. 4444 sUseZeroUnspecifiedMeasureSpec = targetSdkVersion < Build.VERSION_CODES.M; 4445 4446 // Old versions of the platform would give different results from 4447 // LinearLayout measurement passes using EXACTLY and non-EXACTLY 4448 // modes, so we always need to run an additional EXACTLY pass. 4449 sAlwaysRemeasureExactly = targetSdkVersion <= Build.VERSION_CODES.M; 4450 4451 // Prior to N, layout params could change without requiring a 4452 // subsequent call to setLayoutParams() and they would usually 4453 // work. Partial layout breaks this assumption. 4454 sLayoutParamsAlwaysChanged = targetSdkVersion <= Build.VERSION_CODES.M; 4455 4456 // Prior to N, TextureView would silently ignore calls to setBackground/setForeground. 4457 // On N+, we throw, but that breaks compatibility with apps that use these methods. 4458 sTextureViewIgnoresDrawableSetters = targetSdkVersion <= Build.VERSION_CODES.M; 4459 4460 // Prior to N, we would drop margins in LayoutParam conversions. The fix triggers bugs 4461 // in apps so we target check it to avoid breaking existing apps. 4462 sPreserveMarginParamsInLayoutParamConversion = 4463 targetSdkVersion >= Build.VERSION_CODES.N; 4464 4465 sCascadedDragDrop = targetSdkVersion < Build.VERSION_CODES.N; 4466 4467 sHasFocusableExcludeAutoFocusable = targetSdkVersion < Build.VERSION_CODES.O; 4468 4469 sAutoFocusableOffUIThreadWontNotifyParents = targetSdkVersion < Build.VERSION_CODES.O; 4470 4471 sUseDefaultFocusHighlight = context.getResources().getBoolean( 4472 com.android.internal.R.bool.config_useDefaultFocusHighlight); 4473 4474 sCompatibilityDone = true; 4475 } 4476 } 4477 4478 /** 4479 * Constructor that is called when inflating a view from XML. This is called 4480 * when a view is being constructed from an XML file, supplying attributes 4481 * that were specified in the XML file. This version uses a default style of 4482 * 0, so the only attribute values applied are those in the Context's Theme 4483 * and the given AttributeSet. 4484 * 4485 * <p> 4486 * The method onFinishInflate() will be called after all children have been 4487 * added. 4488 * 4489 * @param context The Context the view is running in, through which it can 4490 * access the current theme, resources, etc. 4491 * @param attrs The attributes of the XML tag that is inflating the view. 4492 * @see #View(Context, AttributeSet, int) 4493 */ 4494 public View(Context context, @Nullable AttributeSet attrs) { 4495 this(context, attrs, 0); 4496 } 4497 4498 /** 4499 * Perform inflation from XML and apply a class-specific base style from a 4500 * theme attribute. This constructor of View allows subclasses to use their 4501 * own base style when they are inflating. For example, a Button class's 4502 * constructor would call this version of the super class constructor and 4503 * supply <code>R.attr.buttonStyle</code> for <var>defStyleAttr</var>; this 4504 * allows the theme's button style to modify all of the base view attributes 4505 * (in particular its background) as well as the Button class's attributes. 4506 * 4507 * @param context The Context the view is running in, through which it can 4508 * access the current theme, resources, etc. 4509 * @param attrs The attributes of the XML tag that is inflating the view. 4510 * @param defStyleAttr An attribute in the current theme that contains a 4511 * reference to a style resource that supplies default values for 4512 * the view. Can be 0 to not look for defaults. 4513 * @see #View(Context, AttributeSet) 4514 */ 4515 public View(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { 4516 this(context, attrs, defStyleAttr, 0); 4517 } 4518 4519 /** 4520 * Perform inflation from XML and apply a class-specific base style from a 4521 * theme attribute or style resource. This constructor of View allows 4522 * subclasses to use their own base style when they are inflating. 4523 * <p> 4524 * When determining the final value of a particular attribute, there are 4525 * four inputs that come into play: 4526 * <ol> 4527 * <li>Any attribute values in the given AttributeSet. 4528 * <li>The style resource specified in the AttributeSet (named "style"). 4529 * <li>The default style specified by <var>defStyleAttr</var>. 4530 * <li>The default style specified by <var>defStyleRes</var>. 4531 * <li>The base values in this theme. 4532 * </ol> 4533 * <p> 4534 * Each of these inputs is considered in-order, with the first listed taking 4535 * precedence over the following ones. In other words, if in the 4536 * AttributeSet you have supplied <code><Button * textColor="#ff000000"></code> 4537 * , then the button's text will <em>always</em> be black, regardless of 4538 * what is specified in any of the styles. 4539 * 4540 * @param context The Context the view is running in, through which it can 4541 * access the current theme, resources, etc. 4542 * @param attrs The attributes of the XML tag that is inflating the view. 4543 * @param defStyleAttr An attribute in the current theme that contains a 4544 * reference to a style resource that supplies default values for 4545 * the view. Can be 0 to not look for defaults. 4546 * @param defStyleRes A resource identifier of a style resource that 4547 * supplies default values for the view, used only if 4548 * defStyleAttr is 0 or can not be found in the theme. Can be 0 4549 * to not look for defaults. 4550 * @see #View(Context, AttributeSet, int) 4551 */ 4552 public View(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) { 4553 this(context); 4554 4555 final TypedArray a = context.obtainStyledAttributes( 4556 attrs, com.android.internal.R.styleable.View, defStyleAttr, defStyleRes); 4557 4558 if (mDebugViewAttributes) { 4559 saveAttributeData(attrs, a); 4560 } 4561 4562 Drawable background = null; 4563 4564 int leftPadding = -1; 4565 int topPadding = -1; 4566 int rightPadding = -1; 4567 int bottomPadding = -1; 4568 int startPadding = UNDEFINED_PADDING; 4569 int endPadding = UNDEFINED_PADDING; 4570 4571 int padding = -1; 4572 int paddingHorizontal = -1; 4573 int paddingVertical = -1; 4574 4575 int viewFlagValues = 0; 4576 int viewFlagMasks = 0; 4577 4578 boolean setScrollContainer = false; 4579 4580 int x = 0; 4581 int y = 0; 4582 4583 float tx = 0; 4584 float ty = 0; 4585 float tz = 0; 4586 float elevation = 0; 4587 float rotation = 0; 4588 float rotationX = 0; 4589 float rotationY = 0; 4590 float sx = 1f; 4591 float sy = 1f; 4592 boolean transformSet = false; 4593 4594 int scrollbarStyle = SCROLLBARS_INSIDE_OVERLAY; 4595 int overScrollMode = mOverScrollMode; 4596 boolean initializeScrollbars = false; 4597 boolean initializeScrollIndicators = false; 4598 4599 boolean startPaddingDefined = false; 4600 boolean endPaddingDefined = false; 4601 boolean leftPaddingDefined = false; 4602 boolean rightPaddingDefined = false; 4603 4604 final int targetSdkVersion = context.getApplicationInfo().targetSdkVersion; 4605 4606 // Set default values. 4607 viewFlagValues |= FOCUSABLE_AUTO; 4608 viewFlagMasks |= FOCUSABLE_AUTO; 4609 4610 final int N = a.getIndexCount(); 4611 for (int i = 0; i < N; i++) { 4612 int attr = a.getIndex(i); 4613 switch (attr) { 4614 case com.android.internal.R.styleable.View_background: 4615 background = a.getDrawable(attr); 4616 break; 4617 case com.android.internal.R.styleable.View_padding: 4618 padding = a.getDimensionPixelSize(attr, -1); 4619 mUserPaddingLeftInitial = padding; 4620 mUserPaddingRightInitial = padding; 4621 leftPaddingDefined = true; 4622 rightPaddingDefined = true; 4623 break; 4624 case com.android.internal.R.styleable.View_paddingHorizontal: 4625 paddingHorizontal = a.getDimensionPixelSize(attr, -1); 4626 mUserPaddingLeftInitial = paddingHorizontal; 4627 mUserPaddingRightInitial = paddingHorizontal; 4628 leftPaddingDefined = true; 4629 rightPaddingDefined = true; 4630 break; 4631 case com.android.internal.R.styleable.View_paddingVertical: 4632 paddingVertical = a.getDimensionPixelSize(attr, -1); 4633 break; 4634 case com.android.internal.R.styleable.View_paddingLeft: 4635 leftPadding = a.getDimensionPixelSize(attr, -1); 4636 mUserPaddingLeftInitial = leftPadding; 4637 leftPaddingDefined = true; 4638 break; 4639 case com.android.internal.R.styleable.View_paddingTop: 4640 topPadding = a.getDimensionPixelSize(attr, -1); 4641 break; 4642 case com.android.internal.R.styleable.View_paddingRight: 4643 rightPadding = a.getDimensionPixelSize(attr, -1); 4644 mUserPaddingRightInitial = rightPadding; 4645 rightPaddingDefined = true; 4646 break; 4647 case com.android.internal.R.styleable.View_paddingBottom: 4648 bottomPadding = a.getDimensionPixelSize(attr, -1); 4649 break; 4650 case com.android.internal.R.styleable.View_paddingStart: 4651 startPadding = a.getDimensionPixelSize(attr, UNDEFINED_PADDING); 4652 startPaddingDefined = (startPadding != UNDEFINED_PADDING); 4653 break; 4654 case com.android.internal.R.styleable.View_paddingEnd: 4655 endPadding = a.getDimensionPixelSize(attr, UNDEFINED_PADDING); 4656 endPaddingDefined = (endPadding != UNDEFINED_PADDING); 4657 break; 4658 case com.android.internal.R.styleable.View_scrollX: 4659 x = a.getDimensionPixelOffset(attr, 0); 4660 break; 4661 case com.android.internal.R.styleable.View_scrollY: 4662 y = a.getDimensionPixelOffset(attr, 0); 4663 break; 4664 case com.android.internal.R.styleable.View_alpha: 4665 setAlpha(a.getFloat(attr, 1f)); 4666 break; 4667 case com.android.internal.R.styleable.View_transformPivotX: 4668 setPivotX(a.getDimension(attr, 0)); 4669 break; 4670 case com.android.internal.R.styleable.View_transformPivotY: 4671 setPivotY(a.getDimension(attr, 0)); 4672 break; 4673 case com.android.internal.R.styleable.View_translationX: 4674 tx = a.getDimension(attr, 0); 4675 transformSet = true; 4676 break; 4677 case com.android.internal.R.styleable.View_translationY: 4678 ty = a.getDimension(attr, 0); 4679 transformSet = true; 4680 break; 4681 case com.android.internal.R.styleable.View_translationZ: 4682 tz = a.getDimension(attr, 0); 4683 transformSet = true; 4684 break; 4685 case com.android.internal.R.styleable.View_elevation: 4686 elevation = a.getDimension(attr, 0); 4687 transformSet = true; 4688 break; 4689 case com.android.internal.R.styleable.View_rotation: 4690 rotation = a.getFloat(attr, 0); 4691 transformSet = true; 4692 break; 4693 case com.android.internal.R.styleable.View_rotationX: 4694 rotationX = a.getFloat(attr, 0); 4695 transformSet = true; 4696 break; 4697 case com.android.internal.R.styleable.View_rotationY: 4698 rotationY = a.getFloat(attr, 0); 4699 transformSet = true; 4700 break; 4701 case com.android.internal.R.styleable.View_scaleX: 4702 sx = a.getFloat(attr, 1f); 4703 transformSet = true; 4704 break; 4705 case com.android.internal.R.styleable.View_scaleY: 4706 sy = a.getFloat(attr, 1f); 4707 transformSet = true; 4708 break; 4709 case com.android.internal.R.styleable.View_id: 4710 mID = a.getResourceId(attr, NO_ID); 4711 break; 4712 case com.android.internal.R.styleable.View_tag: 4713 mTag = a.getText(attr); 4714 break; 4715 case com.android.internal.R.styleable.View_fitsSystemWindows: 4716 if (a.getBoolean(attr, false)) { 4717 viewFlagValues |= FITS_SYSTEM_WINDOWS; 4718 viewFlagMasks |= FITS_SYSTEM_WINDOWS; 4719 } 4720 break; 4721 case com.android.internal.R.styleable.View_focusable: 4722 viewFlagValues = (viewFlagValues & ~FOCUSABLE_MASK) | getFocusableAttribute(a); 4723 if ((viewFlagValues & FOCUSABLE_AUTO) == 0) { 4724 viewFlagMasks |= FOCUSABLE_MASK; 4725 } 4726 break; 4727 case com.android.internal.R.styleable.View_focusableInTouchMode: 4728 if (a.getBoolean(attr, false)) { 4729 // unset auto focus since focusableInTouchMode implies explicit focusable 4730 viewFlagValues &= ~FOCUSABLE_AUTO; 4731 viewFlagValues |= FOCUSABLE_IN_TOUCH_MODE | FOCUSABLE; 4732 viewFlagMasks |= FOCUSABLE_IN_TOUCH_MODE | FOCUSABLE_MASK; 4733 } 4734 break; 4735 case com.android.internal.R.styleable.View_clickable: 4736 if (a.getBoolean(attr, false)) { 4737 viewFlagValues |= CLICKABLE; 4738 viewFlagMasks |= CLICKABLE; 4739 } 4740 break; 4741 case com.android.internal.R.styleable.View_longClickable: 4742 if (a.getBoolean(attr, false)) { 4743 viewFlagValues |= LONG_CLICKABLE; 4744 viewFlagMasks |= LONG_CLICKABLE; 4745 } 4746 break; 4747 case com.android.internal.R.styleable.View_contextClickable: 4748 if (a.getBoolean(attr, false)) { 4749 viewFlagValues |= CONTEXT_CLICKABLE; 4750 viewFlagMasks |= CONTEXT_CLICKABLE; 4751 } 4752 break; 4753 case com.android.internal.R.styleable.View_saveEnabled: 4754 if (!a.getBoolean(attr, true)) { 4755 viewFlagValues |= SAVE_DISABLED; 4756 viewFlagMasks |= SAVE_DISABLED_MASK; 4757 } 4758 break; 4759 case com.android.internal.R.styleable.View_duplicateParentState: 4760 if (a.getBoolean(attr, false)) { 4761 viewFlagValues |= DUPLICATE_PARENT_STATE; 4762 viewFlagMasks |= DUPLICATE_PARENT_STATE; 4763 } 4764 break; 4765 case com.android.internal.R.styleable.View_visibility: 4766 final int visibility = a.getInt(attr, 0); 4767 if (visibility != 0) { 4768 viewFlagValues |= VISIBILITY_FLAGS[visibility]; 4769 viewFlagMasks |= VISIBILITY_MASK; 4770 } 4771 break; 4772 case com.android.internal.R.styleable.View_layoutDirection: 4773 // Clear any layout direction flags (included resolved bits) already set 4774 mPrivateFlags2 &= 4775 ~(PFLAG2_LAYOUT_DIRECTION_MASK | PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK); 4776 // Set the layout direction flags depending on the value of the attribute 4777 final int layoutDirection = a.getInt(attr, -1); 4778 final int value = (layoutDirection != -1) ? 4779 LAYOUT_DIRECTION_FLAGS[layoutDirection] : LAYOUT_DIRECTION_DEFAULT; 4780 mPrivateFlags2 |= (value << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT); 4781 break; 4782 case com.android.internal.R.styleable.View_drawingCacheQuality: 4783 final int cacheQuality = a.getInt(attr, 0); 4784 if (cacheQuality != 0) { 4785 viewFlagValues |= DRAWING_CACHE_QUALITY_FLAGS[cacheQuality]; 4786 viewFlagMasks |= DRAWING_CACHE_QUALITY_MASK; 4787 } 4788 break; 4789 case com.android.internal.R.styleable.View_contentDescription: 4790 setContentDescription(a.getString(attr)); 4791 break; 4792 case com.android.internal.R.styleable.View_accessibilityTraversalBefore: 4793 setAccessibilityTraversalBefore(a.getResourceId(attr, NO_ID)); 4794 break; 4795 case com.android.internal.R.styleable.View_accessibilityTraversalAfter: 4796 setAccessibilityTraversalAfter(a.getResourceId(attr, NO_ID)); 4797 break; 4798 case com.android.internal.R.styleable.View_labelFor: 4799 setLabelFor(a.getResourceId(attr, NO_ID)); 4800 break; 4801 case com.android.internal.R.styleable.View_soundEffectsEnabled: 4802 if (!a.getBoolean(attr, true)) { 4803 viewFlagValues &= ~SOUND_EFFECTS_ENABLED; 4804 viewFlagMasks |= SOUND_EFFECTS_ENABLED; 4805 } 4806 break; 4807 case com.android.internal.R.styleable.View_hapticFeedbackEnabled: 4808 if (!a.getBoolean(attr, true)) { 4809 viewFlagValues &= ~HAPTIC_FEEDBACK_ENABLED; 4810 viewFlagMasks |= HAPTIC_FEEDBACK_ENABLED; 4811 } 4812 break; 4813 case R.styleable.View_scrollbars: 4814 final int scrollbars = a.getInt(attr, SCROLLBARS_NONE); 4815 if (scrollbars != SCROLLBARS_NONE) { 4816 viewFlagValues |= scrollbars; 4817 viewFlagMasks |= SCROLLBARS_MASK; 4818 initializeScrollbars = true; 4819 } 4820 break; 4821 //noinspection deprecation 4822 case R.styleable.View_fadingEdge: 4823 if (targetSdkVersion >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { 4824 // Ignore the attribute starting with ICS 4825 break; 4826 } 4827 // With builds < ICS, fall through and apply fading edges 4828 case R.styleable.View_requiresFadingEdge: 4829 final int fadingEdge = a.getInt(attr, FADING_EDGE_NONE); 4830 if (fadingEdge != FADING_EDGE_NONE) { 4831 viewFlagValues |= fadingEdge; 4832 viewFlagMasks |= FADING_EDGE_MASK; 4833 initializeFadingEdgeInternal(a); 4834 } 4835 break; 4836 case R.styleable.View_scrollbarStyle: 4837 scrollbarStyle = a.getInt(attr, SCROLLBARS_INSIDE_OVERLAY); 4838 if (scrollbarStyle != SCROLLBARS_INSIDE_OVERLAY) { 4839 viewFlagValues |= scrollbarStyle & SCROLLBARS_STYLE_MASK; 4840 viewFlagMasks |= SCROLLBARS_STYLE_MASK; 4841 } 4842 break; 4843 case R.styleable.View_isScrollContainer: 4844 setScrollContainer = true; 4845 if (a.getBoolean(attr, false)) { 4846 setScrollContainer(true); 4847 } 4848 break; 4849 case com.android.internal.R.styleable.View_keepScreenOn: 4850 if (a.getBoolean(attr, false)) { 4851 viewFlagValues |= KEEP_SCREEN_ON; 4852 viewFlagMasks |= KEEP_SCREEN_ON; 4853 } 4854 break; 4855 case R.styleable.View_filterTouchesWhenObscured: 4856 if (a.getBoolean(attr, false)) { 4857 viewFlagValues |= FILTER_TOUCHES_WHEN_OBSCURED; 4858 viewFlagMasks |= FILTER_TOUCHES_WHEN_OBSCURED; 4859 } 4860 break; 4861 case R.styleable.View_nextFocusLeft: 4862 mNextFocusLeftId = a.getResourceId(attr, View.NO_ID); 4863 break; 4864 case R.styleable.View_nextFocusRight: 4865 mNextFocusRightId = a.getResourceId(attr, View.NO_ID); 4866 break; 4867 case R.styleable.View_nextFocusUp: 4868 mNextFocusUpId = a.getResourceId(attr, View.NO_ID); 4869 break; 4870 case R.styleable.View_nextFocusDown: 4871 mNextFocusDownId = a.getResourceId(attr, View.NO_ID); 4872 break; 4873 case R.styleable.View_nextFocusForward: 4874 mNextFocusForwardId = a.getResourceId(attr, View.NO_ID); 4875 break; 4876 case R.styleable.View_nextClusterForward: 4877 mNextClusterForwardId = a.getResourceId(attr, View.NO_ID); 4878 break; 4879 case R.styleable.View_minWidth: 4880 mMinWidth = a.getDimensionPixelSize(attr, 0); 4881 break; 4882 case R.styleable.View_minHeight: 4883 mMinHeight = a.getDimensionPixelSize(attr, 0); 4884 break; 4885 case R.styleable.View_onClick: 4886 if (context.isRestricted()) { 4887 throw new IllegalStateException("The android:onClick attribute cannot " 4888 + "be used within a restricted context"); 4889 } 4890 4891 final String handlerName = a.getString(attr); 4892 if (handlerName != null) { 4893 setOnClickListener(new DeclaredOnClickListener(this, handlerName)); 4894 } 4895 break; 4896 case R.styleable.View_overScrollMode: 4897 overScrollMode = a.getInt(attr, OVER_SCROLL_IF_CONTENT_SCROLLS); 4898 break; 4899 case R.styleable.View_verticalScrollbarPosition: 4900 mVerticalScrollbarPosition = a.getInt(attr, SCROLLBAR_POSITION_DEFAULT); 4901 break; 4902 case R.styleable.View_layerType: 4903 setLayerType(a.getInt(attr, LAYER_TYPE_NONE), null); 4904 break; 4905 case R.styleable.View_textDirection: 4906 // Clear any text direction flag already set 4907 mPrivateFlags2 &= ~PFLAG2_TEXT_DIRECTION_MASK; 4908 // Set the text direction flags depending on the value of the attribute 4909 final int textDirection = a.getInt(attr, -1); 4910 if (textDirection != -1) { 4911 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_FLAGS[textDirection]; 4912 } 4913 break; 4914 case R.styleable.View_textAlignment: 4915 // Clear any text alignment flag already set 4916 mPrivateFlags2 &= ~PFLAG2_TEXT_ALIGNMENT_MASK; 4917 // Set the text alignment flag depending on the value of the attribute 4918 final int textAlignment = a.getInt(attr, TEXT_ALIGNMENT_DEFAULT); 4919 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_FLAGS[textAlignment]; 4920 break; 4921 case R.styleable.View_importantForAccessibility: 4922 setImportantForAccessibility(a.getInt(attr, 4923 IMPORTANT_FOR_ACCESSIBILITY_DEFAULT)); 4924 break; 4925 case R.styleable.View_accessibilityLiveRegion: 4926 setAccessibilityLiveRegion(a.getInt(attr, ACCESSIBILITY_LIVE_REGION_DEFAULT)); 4927 break; 4928 case R.styleable.View_transitionName: 4929 setTransitionName(a.getString(attr)); 4930 break; 4931 case R.styleable.View_nestedScrollingEnabled: 4932 setNestedScrollingEnabled(a.getBoolean(attr, false)); 4933 break; 4934 case R.styleable.View_stateListAnimator: 4935 setStateListAnimator(AnimatorInflater.loadStateListAnimator(context, 4936 a.getResourceId(attr, 0))); 4937 break; 4938 case R.styleable.View_backgroundTint: 4939 // This will get applied later during setBackground(). 4940 if (mBackgroundTint == null) { 4941 mBackgroundTint = new TintInfo(); 4942 } 4943 mBackgroundTint.mTintList = a.getColorStateList( 4944 R.styleable.View_backgroundTint); 4945 mBackgroundTint.mHasTintList = true; 4946 break; 4947 case R.styleable.View_backgroundTintMode: 4948 // This will get applied later during setBackground(). 4949 if (mBackgroundTint == null) { 4950 mBackgroundTint = new TintInfo(); 4951 } 4952 mBackgroundTint.mTintMode = Drawable.parseTintMode(a.getInt( 4953 R.styleable.View_backgroundTintMode, -1), null); 4954 mBackgroundTint.mHasTintMode = true; 4955 break; 4956 case R.styleable.View_outlineProvider: 4957 setOutlineProviderFromAttribute(a.getInt(R.styleable.View_outlineProvider, 4958 PROVIDER_BACKGROUND)); 4959 break; 4960 case R.styleable.View_foreground: 4961 if (targetSdkVersion >= Build.VERSION_CODES.M || this instanceof FrameLayout) { 4962 setForeground(a.getDrawable(attr)); 4963 } 4964 break; 4965 case R.styleable.View_foregroundGravity: 4966 if (targetSdkVersion >= Build.VERSION_CODES.M || this instanceof FrameLayout) { 4967 setForegroundGravity(a.getInt(attr, Gravity.NO_GRAVITY)); 4968 } 4969 break; 4970 case R.styleable.View_foregroundTintMode: 4971 if (targetSdkVersion >= Build.VERSION_CODES.M || this instanceof FrameLayout) { 4972 setForegroundTintMode(Drawable.parseTintMode(a.getInt(attr, -1), null)); 4973 } 4974 break; 4975 case R.styleable.View_foregroundTint: 4976 if (targetSdkVersion >= Build.VERSION_CODES.M || this instanceof FrameLayout) { 4977 setForegroundTintList(a.getColorStateList(attr)); 4978 } 4979 break; 4980 case R.styleable.View_foregroundInsidePadding: 4981 if (targetSdkVersion >= Build.VERSION_CODES.M || this instanceof FrameLayout) { 4982 if (mForegroundInfo == null) { 4983 mForegroundInfo = new ForegroundInfo(); 4984 } 4985 mForegroundInfo.mInsidePadding = a.getBoolean(attr, 4986 mForegroundInfo.mInsidePadding); 4987 } 4988 break; 4989 case R.styleable.View_scrollIndicators: 4990 final int scrollIndicators = 4991 (a.getInt(attr, 0) << SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT) 4992 & SCROLL_INDICATORS_PFLAG3_MASK; 4993 if (scrollIndicators != 0) { 4994 mPrivateFlags3 |= scrollIndicators; 4995 initializeScrollIndicators = true; 4996 } 4997 break; 4998 case R.styleable.View_pointerIcon: 4999 final int resourceId = a.getResourceId(attr, 0); 5000 if (resourceId != 0) { 5001 setPointerIcon(PointerIcon.load( 5002 context.getResources(), resourceId)); 5003 } else { 5004 final int pointerType = a.getInt(attr, PointerIcon.TYPE_NOT_SPECIFIED); 5005 if (pointerType != PointerIcon.TYPE_NOT_SPECIFIED) { 5006 setPointerIcon(PointerIcon.getSystemIcon(context, pointerType)); 5007 } 5008 } 5009 break; 5010 case R.styleable.View_forceHasOverlappingRendering: 5011 if (a.peekValue(attr) != null) { 5012 forceHasOverlappingRendering(a.getBoolean(attr, true)); 5013 } 5014 break; 5015 case R.styleable.View_tooltipText: 5016 setTooltipText(a.getText(attr)); 5017 break; 5018 case R.styleable.View_keyboardNavigationCluster: 5019 if (a.peekValue(attr) != null) { 5020 setKeyboardNavigationCluster(a.getBoolean(attr, true)); 5021 } 5022 break; 5023 case R.styleable.View_focusedByDefault: 5024 if (a.peekValue(attr) != null) { 5025 setFocusedByDefault(a.getBoolean(attr, true)); 5026 } 5027 break; 5028 case R.styleable.View_autofillHints: 5029 if (a.peekValue(attr) != null) { 5030 CharSequence[] rawHints = null; 5031 String rawString = null; 5032 5033 if (a.getType(attr) == TypedValue.TYPE_REFERENCE) { 5034 int resId = a.getResourceId(attr, 0); 5035 5036 try { 5037 rawHints = a.getTextArray(attr); 5038 } catch (Resources.NotFoundException e) { 5039 rawString = getResources().getString(resId); 5040 } 5041 } else { 5042 rawString = a.getString(attr); 5043 } 5044 5045 if (rawHints == null) { 5046 if (rawString == null) { 5047 throw new IllegalArgumentException( 5048 "Could not resolve autofillHints"); 5049 } else { 5050 rawHints = rawString.split(","); 5051 } 5052 } 5053 5054 String[] hints = new String[rawHints.length]; 5055 5056 int numHints = rawHints.length; 5057 for (int rawHintNum = 0; rawHintNum < numHints; rawHintNum++) { 5058 hints[rawHintNum] = rawHints[rawHintNum].toString().trim(); 5059 } 5060 setAutofillHints(hints); 5061 } 5062 break; 5063 case R.styleable.View_importantForAutofill: 5064 if (a.peekValue(attr) != null) { 5065 setImportantForAutofill(a.getInt(attr, IMPORTANT_FOR_AUTOFILL_AUTO)); 5066 } 5067 break; 5068 case R.styleable.View_defaultFocusHighlightEnabled: 5069 if (a.peekValue(attr) != null) { 5070 setDefaultFocusHighlightEnabled(a.getBoolean(attr, true)); 5071 } 5072 break; 5073 } 5074 } 5075 5076 setOverScrollMode(overScrollMode); 5077 5078 // Cache start/end user padding as we cannot fully resolve padding here (we dont have yet 5079 // the resolved layout direction). Those cached values will be used later during padding 5080 // resolution. 5081 mUserPaddingStart = startPadding; 5082 mUserPaddingEnd = endPadding; 5083 5084 if (background != null) { 5085 setBackground(background); 5086 } 5087 5088 // setBackground above will record that padding is currently provided by the background. 5089 // If we have padding specified via xml, record that here instead and use it. 5090 mLeftPaddingDefined = leftPaddingDefined; 5091 mRightPaddingDefined = rightPaddingDefined; 5092 5093 if (padding >= 0) { 5094 leftPadding = padding; 5095 topPadding = padding; 5096 rightPadding = padding; 5097 bottomPadding = padding; 5098 mUserPaddingLeftInitial = padding; 5099 mUserPaddingRightInitial = padding; 5100 } else { 5101 if (paddingHorizontal >= 0) { 5102 leftPadding = paddingHorizontal; 5103 rightPadding = paddingHorizontal; 5104 mUserPaddingLeftInitial = paddingHorizontal; 5105 mUserPaddingRightInitial = paddingHorizontal; 5106 } 5107 if (paddingVertical >= 0) { 5108 topPadding = paddingVertical; 5109 bottomPadding = paddingVertical; 5110 } 5111 } 5112 5113 if (isRtlCompatibilityMode()) { 5114 // RTL compatibility mode: pre Jelly Bean MR1 case OR no RTL support case. 5115 // left / right padding are used if defined (meaning here nothing to do). If they are not 5116 // defined and start / end padding are defined (e.g. in Frameworks resources), then we use 5117 // start / end and resolve them as left / right (layout direction is not taken into account). 5118 // Padding from the background drawable is stored at this point in mUserPaddingLeftInitial 5119 // and mUserPaddingRightInitial) so drawable padding will be used as ultimate default if 5120 // defined. 5121 if (!mLeftPaddingDefined && startPaddingDefined) { 5122 leftPadding = startPadding; 5123 } 5124 mUserPaddingLeftInitial = (leftPadding >= 0) ? leftPadding : mUserPaddingLeftInitial; 5125 if (!mRightPaddingDefined && endPaddingDefined) { 5126 rightPadding = endPadding; 5127 } 5128 mUserPaddingRightInitial = (rightPadding >= 0) ? rightPadding : mUserPaddingRightInitial; 5129 } else { 5130 // Jelly Bean MR1 and after case: if start/end defined, they will override any left/right 5131 // values defined. Otherwise, left /right values are used. 5132 // Padding from the background drawable is stored at this point in mUserPaddingLeftInitial 5133 // and mUserPaddingRightInitial) so drawable padding will be used as ultimate default if 5134 // defined. 5135 final boolean hasRelativePadding = startPaddingDefined || endPaddingDefined; 5136 5137 if (mLeftPaddingDefined && !hasRelativePadding) { 5138 mUserPaddingLeftInitial = leftPadding; 5139 } 5140 if (mRightPaddingDefined && !hasRelativePadding) { 5141 mUserPaddingRightInitial = rightPadding; 5142 } 5143 } 5144 5145 internalSetPadding( 5146 mUserPaddingLeftInitial, 5147 topPadding >= 0 ? topPadding : mPaddingTop, 5148 mUserPaddingRightInitial, 5149 bottomPadding >= 0 ? bottomPadding : mPaddingBottom); 5150 5151 if (viewFlagMasks != 0) { 5152 setFlags(viewFlagValues, viewFlagMasks); 5153 } 5154 5155 if (initializeScrollbars) { 5156 initializeScrollbarsInternal(a); 5157 } 5158 5159 if (initializeScrollIndicators) { 5160 initializeScrollIndicatorsInternal(); 5161 } 5162 5163 a.recycle(); 5164 5165 // Needs to be called after mViewFlags is set 5166 if (scrollbarStyle != SCROLLBARS_INSIDE_OVERLAY) { 5167 recomputePadding(); 5168 } 5169 5170 if (x != 0 || y != 0) { 5171 scrollTo(x, y); 5172 } 5173 5174 if (transformSet) { 5175 setTranslationX(tx); 5176 setTranslationY(ty); 5177 setTranslationZ(tz); 5178 setElevation(elevation); 5179 setRotation(rotation); 5180 setRotationX(rotationX); 5181 setRotationY(rotationY); 5182 setScaleX(sx); 5183 setScaleY(sy); 5184 } 5185 5186 if (!setScrollContainer && (viewFlagValues&SCROLLBARS_VERTICAL) != 0) { 5187 setScrollContainer(true); 5188 } 5189 5190 computeOpaqueFlags(); 5191 } 5192 5193 /** 5194 * An implementation of OnClickListener that attempts to lazily load a 5195 * named click handling method from a parent or ancestor context. 5196 */ 5197 private static class DeclaredOnClickListener implements OnClickListener { 5198 private final View mHostView; 5199 private final String mMethodName; 5200 5201 private Method mResolvedMethod; 5202 private Context mResolvedContext; 5203 5204 public DeclaredOnClickListener(@NonNull View hostView, @NonNull String methodName) { 5205 mHostView = hostView; 5206 mMethodName = methodName; 5207 } 5208 5209 @Override 5210 public void onClick(@NonNull View v) { 5211 if (mResolvedMethod == null) { 5212 resolveMethod(mHostView.getContext(), mMethodName); 5213 } 5214 5215 try { 5216 mResolvedMethod.invoke(mResolvedContext, v); 5217 } catch (IllegalAccessException e) { 5218 throw new IllegalStateException( 5219 "Could not execute non-public method for android:onClick", e); 5220 } catch (InvocationTargetException e) { 5221 throw new IllegalStateException( 5222 "Could not execute method for android:onClick", e); 5223 } 5224 } 5225 5226 @NonNull 5227 private void resolveMethod(@Nullable Context context, @NonNull String name) { 5228 while (context != null) { 5229 try { 5230 if (!context.isRestricted()) { 5231 final Method method = context.getClass().getMethod(mMethodName, View.class); 5232 if (method != null) { 5233 mResolvedMethod = method; 5234 mResolvedContext = context; 5235 return; 5236 } 5237 } 5238 } catch (NoSuchMethodException e) { 5239 // Failed to find method, keep searching up the hierarchy. 5240 } 5241 5242 if (context instanceof ContextWrapper) { 5243 context = ((ContextWrapper) context).getBaseContext(); 5244 } else { 5245 // Can't search up the hierarchy, null out and fail. 5246 context = null; 5247 } 5248 } 5249 5250 final int id = mHostView.getId(); 5251 final String idText = id == NO_ID ? "" : " with id '" 5252 + mHostView.getContext().getResources().getResourceEntryName(id) + "'"; 5253 throw new IllegalStateException("Could not find method " + mMethodName 5254 + "(View) in a parent or ancestor Context for android:onClick " 5255 + "attribute defined on view " + mHostView.getClass() + idText); 5256 } 5257 } 5258 5259 /** 5260 * Non-public constructor for use in testing 5261 */ 5262 View() { 5263 mResources = null; 5264 mRenderNode = RenderNode.create(getClass().getName(), this); 5265 } 5266 5267 final boolean debugDraw() { 5268 return DEBUG_DRAW || mAttachInfo != null && mAttachInfo.mDebugLayout; 5269 } 5270 5271 private static SparseArray<String> getAttributeMap() { 5272 if (mAttributeMap == null) { 5273 mAttributeMap = new SparseArray<>(); 5274 } 5275 return mAttributeMap; 5276 } 5277 5278 private void saveAttributeData(@Nullable AttributeSet attrs, @NonNull TypedArray t) { 5279 final int attrsCount = attrs == null ? 0 : attrs.getAttributeCount(); 5280 final int indexCount = t.getIndexCount(); 5281 final String[] attributes = new String[(attrsCount + indexCount) * 2]; 5282 5283 int i = 0; 5284 5285 // Store raw XML attributes. 5286 for (int j = 0; j < attrsCount; ++j) { 5287 attributes[i] = attrs.getAttributeName(j); 5288 attributes[i + 1] = attrs.getAttributeValue(j); 5289 i += 2; 5290 } 5291 5292 // Store resolved styleable attributes. 5293 final Resources res = t.getResources(); 5294 final SparseArray<String> attributeMap = getAttributeMap(); 5295 for (int j = 0; j < indexCount; ++j) { 5296 final int index = t.getIndex(j); 5297 if (!t.hasValueOrEmpty(index)) { 5298 // Value is undefined. Skip it. 5299 continue; 5300 } 5301 5302 final int resourceId = t.getResourceId(index, 0); 5303 if (resourceId == 0) { 5304 // Value is not a reference. Skip it. 5305 continue; 5306 } 5307 5308 String resourceName = attributeMap.get(resourceId); 5309 if (resourceName == null) { 5310 try { 5311 resourceName = res.getResourceName(resourceId); 5312 } catch (Resources.NotFoundException e) { 5313 resourceName = "0x" + Integer.toHexString(resourceId); 5314 } 5315 attributeMap.put(resourceId, resourceName); 5316 } 5317 5318 attributes[i] = resourceName; 5319 attributes[i + 1] = t.getString(index); 5320 i += 2; 5321 } 5322 5323 // Trim to fit contents. 5324 final String[] trimmed = new String[i]; 5325 System.arraycopy(attributes, 0, trimmed, 0, i); 5326 mAttributes = trimmed; 5327 } 5328 5329 public String toString() { 5330 StringBuilder out = new StringBuilder(128); 5331 out.append(getClass().getName()); 5332 out.append('{'); 5333 out.append(Integer.toHexString(System.identityHashCode(this))); 5334 out.append(' '); 5335 switch (mViewFlags&VISIBILITY_MASK) { 5336 case VISIBLE: out.append('V'); break; 5337 case INVISIBLE: out.append('I'); break; 5338 case GONE: out.append('G'); break; 5339 default: out.append('.'); break; 5340 } 5341 out.append((mViewFlags & FOCUSABLE) == FOCUSABLE ? 'F' : '.'); 5342 out.append((mViewFlags&ENABLED_MASK) == ENABLED ? 'E' : '.'); 5343 out.append((mViewFlags&DRAW_MASK) == WILL_NOT_DRAW ? '.' : 'D'); 5344 out.append((mViewFlags&SCROLLBARS_HORIZONTAL) != 0 ? 'H' : '.'); 5345 out.append((mViewFlags&SCROLLBARS_VERTICAL) != 0 ? 'V' : '.'); 5346 out.append((mViewFlags&CLICKABLE) != 0 ? 'C' : '.'); 5347 out.append((mViewFlags&LONG_CLICKABLE) != 0 ? 'L' : '.'); 5348 out.append((mViewFlags&CONTEXT_CLICKABLE) != 0 ? 'X' : '.'); 5349 out.append(' '); 5350 out.append((mPrivateFlags&PFLAG_IS_ROOT_NAMESPACE) != 0 ? 'R' : '.'); 5351 out.append((mPrivateFlags&PFLAG_FOCUSED) != 0 ? 'F' : '.'); 5352 out.append((mPrivateFlags&PFLAG_SELECTED) != 0 ? 'S' : '.'); 5353 if ((mPrivateFlags&PFLAG_PREPRESSED) != 0) { 5354 out.append('p'); 5355 } else { 5356 out.append((mPrivateFlags&PFLAG_PRESSED) != 0 ? 'P' : '.'); 5357 } 5358 out.append((mPrivateFlags&PFLAG_HOVERED) != 0 ? 'H' : '.'); 5359 out.append((mPrivateFlags&PFLAG_ACTIVATED) != 0 ? 'A' : '.'); 5360 out.append((mPrivateFlags&PFLAG_INVALIDATED) != 0 ? 'I' : '.'); 5361 out.append((mPrivateFlags&PFLAG_DIRTY_MASK) != 0 ? 'D' : '.'); 5362 out.append(' '); 5363 out.append(mLeft); 5364 out.append(','); 5365 out.append(mTop); 5366 out.append('-'); 5367 out.append(mRight); 5368 out.append(','); 5369 out.append(mBottom); 5370 final int id = getId(); 5371 if (id != NO_ID) { 5372 out.append(" #"); 5373 out.append(Integer.toHexString(id)); 5374 final Resources r = mResources; 5375 if (id > 0 && Resources.resourceHasPackage(id) && r != null) { 5376 try { 5377 String pkgname; 5378 switch (id&0xff000000) { 5379 case 0x7f000000: 5380 pkgname="app"; 5381 break; 5382 case 0x01000000: 5383 pkgname="android"; 5384 break; 5385 default: 5386 pkgname = r.getResourcePackageName(id); 5387 break; 5388 } 5389 String typename = r.getResourceTypeName(id); 5390 String entryname = r.getResourceEntryName(id); 5391 out.append(" "); 5392 out.append(pkgname); 5393 out.append(":"); 5394 out.append(typename); 5395 out.append("/"); 5396 out.append(entryname); 5397 } catch (Resources.NotFoundException e) { 5398 } 5399 } 5400 } 5401 out.append("}"); 5402 return out.toString(); 5403 } 5404 5405 /** 5406 * <p> 5407 * Initializes the fading edges from a given set of styled attributes. This 5408 * method should be called by subclasses that need fading edges and when an 5409 * instance of these subclasses is created programmatically rather than 5410 * being inflated from XML. This method is automatically called when the XML 5411 * is inflated. 5412 * </p> 5413 * 5414 * @param a the styled attributes set to initialize the fading edges from 5415 * 5416 * @removed 5417 */ 5418 protected void initializeFadingEdge(TypedArray a) { 5419 // This method probably shouldn't have been included in the SDK to begin with. 5420 // It relies on 'a' having been initialized using an attribute filter array that is 5421 // not publicly available to the SDK. The old method has been renamed 5422 // to initializeFadingEdgeInternal and hidden for framework use only; 5423 // this one initializes using defaults to make it safe to call for apps. 5424 5425 TypedArray arr = mContext.obtainStyledAttributes(com.android.internal.R.styleable.View); 5426 5427 initializeFadingEdgeInternal(arr); 5428 5429 arr.recycle(); 5430 } 5431 5432 /** 5433 * <p> 5434 * Initializes the fading edges from a given set of styled attributes. This 5435 * method should be called by subclasses that need fading edges and when an 5436 * instance of these subclasses is created programmatically rather than 5437 * being inflated from XML. This method is automatically called when the XML 5438 * is inflated. 5439 * </p> 5440 * 5441 * @param a the styled attributes set to initialize the fading edges from 5442 * @hide This is the real method; the public one is shimmed to be safe to call from apps. 5443 */ 5444 protected void initializeFadingEdgeInternal(TypedArray a) { 5445 initScrollCache(); 5446 5447 mScrollCache.fadingEdgeLength = a.getDimensionPixelSize( 5448 R.styleable.View_fadingEdgeLength, 5449 ViewConfiguration.get(mContext).getScaledFadingEdgeLength()); 5450 } 5451 5452 /** 5453 * Returns the size of the vertical faded edges used to indicate that more 5454 * content in this view is visible. 5455 * 5456 * @return The size in pixels of the vertical faded edge or 0 if vertical 5457 * faded edges are not enabled for this view. 5458 * @attr ref android.R.styleable#View_fadingEdgeLength 5459 */ 5460 public int getVerticalFadingEdgeLength() { 5461 if (isVerticalFadingEdgeEnabled()) { 5462 ScrollabilityCache cache = mScrollCache; 5463 if (cache != null) { 5464 return cache.fadingEdgeLength; 5465 } 5466 } 5467 return 0; 5468 } 5469 5470 /** 5471 * Set the size of the faded edge used to indicate that more content in this 5472 * view is available. Will not change whether the fading edge is enabled; use 5473 * {@link #setVerticalFadingEdgeEnabled(boolean)} or 5474 * {@link #setHorizontalFadingEdgeEnabled(boolean)} to enable the fading edge 5475 * for the vertical or horizontal fading edges. 5476 * 5477 * @param length The size in pixels of the faded edge used to indicate that more 5478 * content in this view is visible. 5479 */ 5480 public void setFadingEdgeLength(int length) { 5481 initScrollCache(); 5482 mScrollCache.fadingEdgeLength = length; 5483 } 5484 5485 /** 5486 * Returns the size of the horizontal faded edges used to indicate that more 5487 * content in this view is visible. 5488 * 5489 * @return The size in pixels of the horizontal faded edge or 0 if horizontal 5490 * faded edges are not enabled for this view. 5491 * @attr ref android.R.styleable#View_fadingEdgeLength 5492 */ 5493 public int getHorizontalFadingEdgeLength() { 5494 if (isHorizontalFadingEdgeEnabled()) { 5495 ScrollabilityCache cache = mScrollCache; 5496 if (cache != null) { 5497 return cache.fadingEdgeLength; 5498 } 5499 } 5500 return 0; 5501 } 5502 5503 /** 5504 * Returns the width of the vertical scrollbar. 5505 * 5506 * @return The width in pixels of the vertical scrollbar or 0 if there 5507 * is no vertical scrollbar. 5508 */ 5509 public int getVerticalScrollbarWidth() { 5510 ScrollabilityCache cache = mScrollCache; 5511 if (cache != null) { 5512 ScrollBarDrawable scrollBar = cache.scrollBar; 5513 if (scrollBar != null) { 5514 int size = scrollBar.getSize(true); 5515 if (size <= 0) { 5516 size = cache.scrollBarSize; 5517 } 5518 return size; 5519 } 5520 return 0; 5521 } 5522 return 0; 5523 } 5524 5525 /** 5526 * Returns the height of the horizontal scrollbar. 5527 * 5528 * @return The height in pixels of the horizontal scrollbar or 0 if 5529 * there is no horizontal scrollbar. 5530 */ 5531 protected int getHorizontalScrollbarHeight() { 5532 ScrollabilityCache cache = mScrollCache; 5533 if (cache != null) { 5534 ScrollBarDrawable scrollBar = cache.scrollBar; 5535 if (scrollBar != null) { 5536 int size = scrollBar.getSize(false); 5537 if (size <= 0) { 5538 size = cache.scrollBarSize; 5539 } 5540 return size; 5541 } 5542 return 0; 5543 } 5544 return 0; 5545 } 5546 5547 /** 5548 * <p> 5549 * Initializes the scrollbars from a given set of styled attributes. This 5550 * method should be called by subclasses that need scrollbars and when an 5551 * instance of these subclasses is created programmatically rather than 5552 * being inflated from XML. This method is automatically called when the XML 5553 * is inflated. 5554 * </p> 5555 * 5556 * @param a the styled attributes set to initialize the scrollbars from 5557 * 5558 * @removed 5559 */ 5560 protected void initializeScrollbars(TypedArray a) { 5561 // It's not safe to use this method from apps. The parameter 'a' must have been obtained 5562 // using the View filter array which is not available to the SDK. As such, internal 5563 // framework usage now uses initializeScrollbarsInternal and we grab a default 5564 // TypedArray with the right filter instead here. 5565 TypedArray arr = mContext.obtainStyledAttributes(com.android.internal.R.styleable.View); 5566 5567 initializeScrollbarsInternal(arr); 5568 5569 // We ignored the method parameter. Recycle the one we actually did use. 5570 arr.recycle(); 5571 } 5572 5573 /** 5574 * <p> 5575 * Initializes the scrollbars from a given set of styled attributes. This 5576 * method should be called by subclasses that need scrollbars and when an 5577 * instance of these subclasses is created programmatically rather than 5578 * being inflated from XML. This method is automatically called when the XML 5579 * is inflated. 5580 * </p> 5581 * 5582 * @param a the styled attributes set to initialize the scrollbars from 5583 * @hide 5584 */ 5585 protected void initializeScrollbarsInternal(TypedArray a) { 5586 initScrollCache(); 5587 5588 final ScrollabilityCache scrollabilityCache = mScrollCache; 5589 5590 if (scrollabilityCache.scrollBar == null) { 5591 scrollabilityCache.scrollBar = new ScrollBarDrawable(); 5592 scrollabilityCache.scrollBar.setState(getDrawableState()); 5593 scrollabilityCache.scrollBar.setCallback(this); 5594 } 5595 5596 final boolean fadeScrollbars = a.getBoolean(R.styleable.View_fadeScrollbars, true); 5597 5598 if (!fadeScrollbars) { 5599 scrollabilityCache.state = ScrollabilityCache.ON; 5600 } 5601 scrollabilityCache.fadeScrollBars = fadeScrollbars; 5602 5603 5604 scrollabilityCache.scrollBarFadeDuration = a.getInt( 5605 R.styleable.View_scrollbarFadeDuration, ViewConfiguration 5606 .getScrollBarFadeDuration()); 5607 scrollabilityCache.scrollBarDefaultDelayBeforeFade = a.getInt( 5608 R.styleable.View_scrollbarDefaultDelayBeforeFade, 5609 ViewConfiguration.getScrollDefaultDelay()); 5610 5611 5612 scrollabilityCache.scrollBarSize = a.getDimensionPixelSize( 5613 com.android.internal.R.styleable.View_scrollbarSize, 5614 ViewConfiguration.get(mContext).getScaledScrollBarSize()); 5615 5616 Drawable track = a.getDrawable(R.styleable.View_scrollbarTrackHorizontal); 5617 scrollabilityCache.scrollBar.setHorizontalTrackDrawable(track); 5618 5619 Drawable thumb = a.getDrawable(R.styleable.View_scrollbarThumbHorizontal); 5620 if (thumb != null) { 5621 scrollabilityCache.scrollBar.setHorizontalThumbDrawable(thumb); 5622 } 5623 5624 boolean alwaysDraw = a.getBoolean(R.styleable.View_scrollbarAlwaysDrawHorizontalTrack, 5625 false); 5626 if (alwaysDraw) { 5627 scrollabilityCache.scrollBar.setAlwaysDrawHorizontalTrack(true); 5628 } 5629 5630 track = a.getDrawable(R.styleable.View_scrollbarTrackVertical); 5631 scrollabilityCache.scrollBar.setVerticalTrackDrawable(track); 5632 5633 thumb = a.getDrawable(R.styleable.View_scrollbarThumbVertical); 5634 if (thumb != null) { 5635 scrollabilityCache.scrollBar.setVerticalThumbDrawable(thumb); 5636 } 5637 5638 alwaysDraw = a.getBoolean(R.styleable.View_scrollbarAlwaysDrawVerticalTrack, 5639 false); 5640 if (alwaysDraw) { 5641 scrollabilityCache.scrollBar.setAlwaysDrawVerticalTrack(true); 5642 } 5643 5644 // Apply layout direction to the new Drawables if needed 5645 final int layoutDirection = getLayoutDirection(); 5646 if (track != null) { 5647 track.setLayoutDirection(layoutDirection); 5648 } 5649 if (thumb != null) { 5650 thumb.setLayoutDirection(layoutDirection); 5651 } 5652 5653 // Re-apply user/background padding so that scrollbar(s) get added 5654 resolvePadding(); 5655 } 5656 5657 private void initializeScrollIndicatorsInternal() { 5658 // Some day maybe we'll break this into top/left/start/etc. and let the 5659 // client control it. Until then, you can have any scroll indicator you 5660 // want as long as it's a 1dp foreground-colored rectangle. 5661 if (mScrollIndicatorDrawable == null) { 5662 mScrollIndicatorDrawable = mContext.getDrawable(R.drawable.scroll_indicator_material); 5663 } 5664 } 5665 5666 /** 5667 * <p> 5668 * Initalizes the scrollability cache if necessary. 5669 * </p> 5670 */ 5671 private void initScrollCache() { 5672 if (mScrollCache == null) { 5673 mScrollCache = new ScrollabilityCache(ViewConfiguration.get(mContext), this); 5674 } 5675 } 5676 5677 private ScrollabilityCache getScrollCache() { 5678 initScrollCache(); 5679 return mScrollCache; 5680 } 5681 5682 /** 5683 * Set the position of the vertical scroll bar. Should be one of 5684 * {@link #SCROLLBAR_POSITION_DEFAULT}, {@link #SCROLLBAR_POSITION_LEFT} or 5685 * {@link #SCROLLBAR_POSITION_RIGHT}. 5686 * 5687 * @param position Where the vertical scroll bar should be positioned. 5688 */ 5689 public void setVerticalScrollbarPosition(int position) { 5690 if (mVerticalScrollbarPosition != position) { 5691 mVerticalScrollbarPosition = position; 5692 computeOpaqueFlags(); 5693 resolvePadding(); 5694 } 5695 } 5696 5697 /** 5698 * @return The position where the vertical scroll bar will show, if applicable. 5699 * @see #setVerticalScrollbarPosition(int) 5700 */ 5701 public int getVerticalScrollbarPosition() { 5702 return mVerticalScrollbarPosition; 5703 } 5704 5705 boolean isOnScrollbar(float x, float y) { 5706 if (mScrollCache == null) { 5707 return false; 5708 } 5709 x += getScrollX(); 5710 y += getScrollY(); 5711 if (isVerticalScrollBarEnabled() && !isVerticalScrollBarHidden()) { 5712 final Rect touchBounds = mScrollCache.mScrollBarTouchBounds; 5713 getVerticalScrollBarBounds(null, touchBounds); 5714 if (touchBounds.contains((int) x, (int) y)) { 5715 return true; 5716 } 5717 } 5718 if (isHorizontalScrollBarEnabled()) { 5719 final Rect touchBounds = mScrollCache.mScrollBarTouchBounds; 5720 getHorizontalScrollBarBounds(null, touchBounds); 5721 if (touchBounds.contains((int) x, (int) y)) { 5722 return true; 5723 } 5724 } 5725 return false; 5726 } 5727 5728 boolean isOnScrollbarThumb(float x, float y) { 5729 return isOnVerticalScrollbarThumb(x, y) || isOnHorizontalScrollbarThumb(x, y); 5730 } 5731 5732 private boolean isOnVerticalScrollbarThumb(float x, float y) { 5733 if (mScrollCache == null) { 5734 return false; 5735 } 5736 if (isVerticalScrollBarEnabled() && !isVerticalScrollBarHidden()) { 5737 x += getScrollX(); 5738 y += getScrollY(); 5739 final Rect bounds = mScrollCache.mScrollBarBounds; 5740 final Rect touchBounds = mScrollCache.mScrollBarTouchBounds; 5741 getVerticalScrollBarBounds(bounds, touchBounds); 5742 final int range = computeVerticalScrollRange(); 5743 final int offset = computeVerticalScrollOffset(); 5744 final int extent = computeVerticalScrollExtent(); 5745 final int thumbLength = ScrollBarUtils.getThumbLength(bounds.height(), bounds.width(), 5746 extent, range); 5747 final int thumbOffset = ScrollBarUtils.getThumbOffset(bounds.height(), thumbLength, 5748 extent, range, offset); 5749 final int thumbTop = bounds.top + thumbOffset; 5750 final int adjust = Math.max(mScrollCache.scrollBarMinTouchTarget - thumbLength, 0) / 2; 5751 if (x >= touchBounds.left && x <= touchBounds.right 5752 && y >= thumbTop - adjust && y <= thumbTop + thumbLength + adjust) { 5753 return true; 5754 } 5755 } 5756 return false; 5757 } 5758 5759 private boolean isOnHorizontalScrollbarThumb(float x, float y) { 5760 if (mScrollCache == null) { 5761 return false; 5762 } 5763 if (isHorizontalScrollBarEnabled()) { 5764 x += getScrollX(); 5765 y += getScrollY(); 5766 final Rect bounds = mScrollCache.mScrollBarBounds; 5767 final Rect touchBounds = mScrollCache.mScrollBarTouchBounds; 5768 getHorizontalScrollBarBounds(bounds, touchBounds); 5769 final int range = computeHorizontalScrollRange(); 5770 final int offset = computeHorizontalScrollOffset(); 5771 final int extent = computeHorizontalScrollExtent(); 5772 final int thumbLength = ScrollBarUtils.getThumbLength(bounds.width(), bounds.height(), 5773 extent, range); 5774 final int thumbOffset = ScrollBarUtils.getThumbOffset(bounds.width(), thumbLength, 5775 extent, range, offset); 5776 final int thumbLeft = bounds.left + thumbOffset; 5777 final int adjust = Math.max(mScrollCache.scrollBarMinTouchTarget - thumbLength, 0) / 2; 5778 if (x >= thumbLeft - adjust && x <= thumbLeft + thumbLength + adjust 5779 && y >= touchBounds.top && y <= touchBounds.bottom) { 5780 return true; 5781 } 5782 } 5783 return false; 5784 } 5785 5786 boolean isDraggingScrollBar() { 5787 return mScrollCache != null 5788 && mScrollCache.mScrollBarDraggingState != ScrollabilityCache.NOT_DRAGGING; 5789 } 5790 5791 /** 5792 * Sets the state of all scroll indicators. 5793 * <p> 5794 * See {@link #setScrollIndicators(int, int)} for usage information. 5795 * 5796 * @param indicators a bitmask of indicators that should be enabled, or 5797 * {@code 0} to disable all indicators 5798 * @see #setScrollIndicators(int, int) 5799 * @see #getScrollIndicators() 5800 * @attr ref android.R.styleable#View_scrollIndicators 5801 */ 5802 public void setScrollIndicators(@ScrollIndicators int indicators) { 5803 setScrollIndicators(indicators, 5804 SCROLL_INDICATORS_PFLAG3_MASK >>> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT); 5805 } 5806 5807 /** 5808 * Sets the state of the scroll indicators specified by the mask. To change 5809 * all scroll indicators at once, see {@link #setScrollIndicators(int)}. 5810 * <p> 5811 * When a scroll indicator is enabled, it will be displayed if the view 5812 * can scroll in the direction of the indicator. 5813 * <p> 5814 * Multiple indicator types may be enabled or disabled by passing the 5815 * logical OR of the desired types. If multiple types are specified, they 5816 * will all be set to the same enabled state. 5817 * <p> 5818 * For example, to enable the top scroll indicatorExample: {@code setScrollIndicators 5819 * 5820 * @param indicators the indicator direction, or the logical OR of multiple 5821 * indicator directions. One or more of: 5822 * <ul> 5823 * <li>{@link #SCROLL_INDICATOR_TOP}</li> 5824 * <li>{@link #SCROLL_INDICATOR_BOTTOM}</li> 5825 * <li>{@link #SCROLL_INDICATOR_LEFT}</li> 5826 * <li>{@link #SCROLL_INDICATOR_RIGHT}</li> 5827 * <li>{@link #SCROLL_INDICATOR_START}</li> 5828 * <li>{@link #SCROLL_INDICATOR_END}</li> 5829 * </ul> 5830 * @see #setScrollIndicators(int) 5831 * @see #getScrollIndicators() 5832 * @attr ref android.R.styleable#View_scrollIndicators 5833 */ 5834 public void setScrollIndicators(@ScrollIndicators int indicators, @ScrollIndicators int mask) { 5835 // Shift and sanitize mask. 5836 mask <<= SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 5837 mask &= SCROLL_INDICATORS_PFLAG3_MASK; 5838 5839 // Shift and mask indicators. 5840 indicators <<= SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 5841 indicators &= mask; 5842 5843 // Merge with non-masked flags. 5844 final int updatedFlags = indicators | (mPrivateFlags3 & ~mask); 5845 5846 if (mPrivateFlags3 != updatedFlags) { 5847 mPrivateFlags3 = updatedFlags; 5848 5849 if (indicators != 0) { 5850 initializeScrollIndicatorsInternal(); 5851 } 5852 invalidate(); 5853 } 5854 } 5855 5856 /** 5857 * Returns a bitmask representing the enabled scroll indicators. 5858 * <p> 5859 * For example, if the top and left scroll indicators are enabled and all 5860 * other indicators are disabled, the return value will be 5861 * {@code View.SCROLL_INDICATOR_TOP | View.SCROLL_INDICATOR_LEFT}. 5862 * <p> 5863 * To check whether the bottom scroll indicator is enabled, use the value 5864 * of {@code (getScrollIndicators() & View.SCROLL_INDICATOR_BOTTOM) != 0}. 5865 * 5866 * @return a bitmask representing the enabled scroll indicators 5867 */ 5868 @ScrollIndicators 5869 public int getScrollIndicators() { 5870 return (mPrivateFlags3 & SCROLL_INDICATORS_PFLAG3_MASK) 5871 >>> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 5872 } 5873 5874 ListenerInfo getListenerInfo() { 5875 if (mListenerInfo != null) { 5876 return mListenerInfo; 5877 } 5878 mListenerInfo = new ListenerInfo(); 5879 return mListenerInfo; 5880 } 5881 5882 /** 5883 * Register a callback to be invoked when the scroll X or Y positions of 5884 * this view change. 5885 * <p> 5886 * <b>Note:</b> Some views handle scrolling independently from View and may 5887 * have their own separate listeners for scroll-type events. For example, 5888 * {@link android.widget.ListView ListView} allows clients to register an 5889 * {@link android.widget.ListView#setOnScrollListener(android.widget.AbsListView.OnScrollListener) AbsListView.OnScrollListener} 5890 * to listen for changes in list scroll position. 5891 * 5892 * @param l The listener to notify when the scroll X or Y position changes. 5893 * @see android.view.View#getScrollX() 5894 * @see android.view.View#getScrollY() 5895 */ 5896 public void setOnScrollChangeListener(OnScrollChangeListener l) { 5897 getListenerInfo().mOnScrollChangeListener = l; 5898 } 5899 5900 /** 5901 * Register a callback to be invoked when focus of this view changed. 5902 * 5903 * @param l The callback that will run. 5904 */ 5905 public void setOnFocusChangeListener(OnFocusChangeListener l) { 5906 getListenerInfo().mOnFocusChangeListener = l; 5907 } 5908 5909 /** 5910 * Add a listener that will be called when the bounds of the view change due to 5911 * layout processing. 5912 * 5913 * @param listener The listener that will be called when layout bounds change. 5914 */ 5915 public void addOnLayoutChangeListener(OnLayoutChangeListener listener) { 5916 ListenerInfo li = getListenerInfo(); 5917 if (li.mOnLayoutChangeListeners == null) { 5918 li.mOnLayoutChangeListeners = new ArrayList<OnLayoutChangeListener>(); 5919 } 5920 if (!li.mOnLayoutChangeListeners.contains(listener)) { 5921 li.mOnLayoutChangeListeners.add(listener); 5922 } 5923 } 5924 5925 /** 5926 * Remove a listener for layout changes. 5927 * 5928 * @param listener The listener for layout bounds change. 5929 */ 5930 public void removeOnLayoutChangeListener(OnLayoutChangeListener listener) { 5931 ListenerInfo li = mListenerInfo; 5932 if (li == null || li.mOnLayoutChangeListeners == null) { 5933 return; 5934 } 5935 li.mOnLayoutChangeListeners.remove(listener); 5936 } 5937 5938 /** 5939 * Add a listener for attach state changes. 5940 * 5941 * This listener will be called whenever this view is attached or detached 5942 * from a window. Remove the listener using 5943 * {@link #removeOnAttachStateChangeListener(OnAttachStateChangeListener)}. 5944 * 5945 * @param listener Listener to attach 5946 * @see #removeOnAttachStateChangeListener(OnAttachStateChangeListener) 5947 */ 5948 public void addOnAttachStateChangeListener(OnAttachStateChangeListener listener) { 5949 ListenerInfo li = getListenerInfo(); 5950 if (li.mOnAttachStateChangeListeners == null) { 5951 li.mOnAttachStateChangeListeners 5952 = new CopyOnWriteArrayList<OnAttachStateChangeListener>(); 5953 } 5954 li.mOnAttachStateChangeListeners.add(listener); 5955 } 5956 5957 /** 5958 * Remove a listener for attach state changes. The listener will receive no further 5959 * notification of window attach/detach events. 5960 * 5961 * @param listener Listener to remove 5962 * @see #addOnAttachStateChangeListener(OnAttachStateChangeListener) 5963 */ 5964 public void removeOnAttachStateChangeListener(OnAttachStateChangeListener listener) { 5965 ListenerInfo li = mListenerInfo; 5966 if (li == null || li.mOnAttachStateChangeListeners == null) { 5967 return; 5968 } 5969 li.mOnAttachStateChangeListeners.remove(listener); 5970 } 5971 5972 /** 5973 * Returns the focus-change callback registered for this view. 5974 * 5975 * @return The callback, or null if one is not registered. 5976 */ 5977 public OnFocusChangeListener getOnFocusChangeListener() { 5978 ListenerInfo li = mListenerInfo; 5979 return li != null ? li.mOnFocusChangeListener : null; 5980 } 5981 5982 /** 5983 * Register a callback to be invoked when this view is clicked. If this view is not 5984 * clickable, it becomes clickable. 5985 * 5986 * @param l The callback that will run 5987 * 5988 * @see #setClickable(boolean) 5989 */ 5990 public void setOnClickListener(@Nullable OnClickListener l) { 5991 if (!isClickable()) { 5992 setClickable(true); 5993 } 5994 getListenerInfo().mOnClickListener = l; 5995 } 5996 5997 /** 5998 * Return whether this view has an attached OnClickListener. Returns 5999 * true if there is a listener, false if there is none. 6000 */ 6001 public boolean hasOnClickListeners() { 6002 ListenerInfo li = mListenerInfo; 6003 return (li != null && li.mOnClickListener != null); 6004 } 6005 6006 /** 6007 * Register a callback to be invoked when this view is clicked and held. If this view is not 6008 * long clickable, it becomes long clickable. 6009 * 6010 * @param l The callback that will run 6011 * 6012 * @see #setLongClickable(boolean) 6013 */ 6014 public void setOnLongClickListener(@Nullable OnLongClickListener l) { 6015 if (!isLongClickable()) { 6016 setLongClickable(true); 6017 } 6018 getListenerInfo().mOnLongClickListener = l; 6019 } 6020 6021 /** 6022 * Register a callback to be invoked when this view is context clicked. If the view is not 6023 * context clickable, it becomes context clickable. 6024 * 6025 * @param l The callback that will run 6026 * @see #setContextClickable(boolean) 6027 */ 6028 public void setOnContextClickListener(@Nullable OnContextClickListener l) { 6029 if (!isContextClickable()) { 6030 setContextClickable(true); 6031 } 6032 getListenerInfo().mOnContextClickListener = l; 6033 } 6034 6035 /** 6036 * Register a callback to be invoked when the context menu for this view is 6037 * being built. If this view is not long clickable, it becomes long clickable. 6038 * 6039 * @param l The callback that will run 6040 * 6041 */ 6042 public void setOnCreateContextMenuListener(OnCreateContextMenuListener l) { 6043 if (!isLongClickable()) { 6044 setLongClickable(true); 6045 } 6046 getListenerInfo().mOnCreateContextMenuListener = l; 6047 } 6048 6049 /** 6050 * Set an observer to collect stats for each frame rendered for this view. 6051 * 6052 * @hide 6053 */ 6054 public void addFrameMetricsListener(Window window, 6055 Window.OnFrameMetricsAvailableListener listener, 6056 Handler handler) { 6057 if (mAttachInfo != null) { 6058 if (mAttachInfo.mThreadedRenderer != null) { 6059 if (mFrameMetricsObservers == null) { 6060 mFrameMetricsObservers = new ArrayList<>(); 6061 } 6062 6063 FrameMetricsObserver fmo = new FrameMetricsObserver(window, 6064 handler.getLooper(), listener); 6065 mFrameMetricsObservers.add(fmo); 6066 mAttachInfo.mThreadedRenderer.addFrameMetricsObserver(fmo); 6067 } else { 6068 Log.w(VIEW_LOG_TAG, "View not hardware-accelerated. Unable to observe frame stats"); 6069 } 6070 } else { 6071 if (mFrameMetricsObservers == null) { 6072 mFrameMetricsObservers = new ArrayList<>(); 6073 } 6074 6075 FrameMetricsObserver fmo = new FrameMetricsObserver(window, 6076 handler.getLooper(), listener); 6077 mFrameMetricsObservers.add(fmo); 6078 } 6079 } 6080 6081 /** 6082 * Remove observer configured to collect frame stats for this view. 6083 * 6084 * @hide 6085 */ 6086 public void removeFrameMetricsListener( 6087 Window.OnFrameMetricsAvailableListener listener) { 6088 ThreadedRenderer renderer = getThreadedRenderer(); 6089 FrameMetricsObserver fmo = findFrameMetricsObserver(listener); 6090 if (fmo == null) { 6091 throw new IllegalArgumentException( 6092 "attempt to remove OnFrameMetricsAvailableListener that was never added"); 6093 } 6094 6095 if (mFrameMetricsObservers != null) { 6096 mFrameMetricsObservers.remove(fmo); 6097 if (renderer != null) { 6098 renderer.removeFrameMetricsObserver(fmo); 6099 } 6100 } 6101 } 6102 6103 private void registerPendingFrameMetricsObservers() { 6104 if (mFrameMetricsObservers != null) { 6105 ThreadedRenderer renderer = getThreadedRenderer(); 6106 if (renderer != null) { 6107 for (FrameMetricsObserver fmo : mFrameMetricsObservers) { 6108 renderer.addFrameMetricsObserver(fmo); 6109 } 6110 } else { 6111 Log.w(VIEW_LOG_TAG, "View not hardware-accelerated. Unable to observe frame stats"); 6112 } 6113 } 6114 } 6115 6116 private FrameMetricsObserver findFrameMetricsObserver( 6117 Window.OnFrameMetricsAvailableListener listener) { 6118 for (int i = 0; i < mFrameMetricsObservers.size(); i++) { 6119 FrameMetricsObserver observer = mFrameMetricsObservers.get(i); 6120 if (observer.mListener == listener) { 6121 return observer; 6122 } 6123 } 6124 6125 return null; 6126 } 6127 6128 /** 6129 * Call this view's OnClickListener, if it is defined. Performs all normal 6130 * actions associated with clicking: reporting accessibility event, playing 6131 * a sound, etc. 6132 * 6133 * @return True there was an assigned OnClickListener that was called, false 6134 * otherwise is returned. 6135 */ 6136 public boolean performClick() { 6137 final boolean result; 6138 final ListenerInfo li = mListenerInfo; 6139 if (li != null && li.mOnClickListener != null) { 6140 playSoundEffect(SoundEffectConstants.CLICK); 6141 li.mOnClickListener.onClick(this); 6142 result = true; 6143 } else { 6144 result = false; 6145 } 6146 6147 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED); 6148 6149 notifyEnterOrExitForAutoFillIfNeeded(true); 6150 6151 return result; 6152 } 6153 6154 /** 6155 * Directly call any attached OnClickListener. Unlike {@link #performClick()}, 6156 * this only calls the listener, and does not do any associated clicking 6157 * actions like reporting an accessibility event. 6158 * 6159 * @return True there was an assigned OnClickListener that was called, false 6160 * otherwise is returned. 6161 */ 6162 public boolean callOnClick() { 6163 ListenerInfo li = mListenerInfo; 6164 if (li != null && li.mOnClickListener != null) { 6165 li.mOnClickListener.onClick(this); 6166 return true; 6167 } 6168 return false; 6169 } 6170 6171 /** 6172 * Calls this view's OnLongClickListener, if it is defined. Invokes the 6173 * context menu if the OnLongClickListener did not consume the event. 6174 * 6175 * @return {@code true} if one of the above receivers consumed the event, 6176 * {@code false} otherwise 6177 */ 6178 public boolean performLongClick() { 6179 return performLongClickInternal(mLongClickX, mLongClickY); 6180 } 6181 6182 /** 6183 * Calls this view's OnLongClickListener, if it is defined. Invokes the 6184 * context menu if the OnLongClickListener did not consume the event, 6185 * anchoring it to an (x,y) coordinate. 6186 * 6187 * @param x x coordinate of the anchoring touch event, or {@link Float#NaN} 6188 * to disable anchoring 6189 * @param y y coordinate of the anchoring touch event, or {@link Float#NaN} 6190 * to disable anchoring 6191 * @return {@code true} if one of the above receivers consumed the event, 6192 * {@code false} otherwise 6193 */ 6194 public boolean performLongClick(float x, float y) { 6195 mLongClickX = x; 6196 mLongClickY = y; 6197 final boolean handled = performLongClick(); 6198 mLongClickX = Float.NaN; 6199 mLongClickY = Float.NaN; 6200 return handled; 6201 } 6202 6203 /** 6204 * Calls this view's OnLongClickListener, if it is defined. Invokes the 6205 * context menu if the OnLongClickListener did not consume the event, 6206 * optionally anchoring it to an (x,y) coordinate. 6207 * 6208 * @param x x coordinate of the anchoring touch event, or {@link Float#NaN} 6209 * to disable anchoring 6210 * @param y y coordinate of the anchoring touch event, or {@link Float#NaN} 6211 * to disable anchoring 6212 * @return {@code true} if one of the above receivers consumed the event, 6213 * {@code false} otherwise 6214 */ 6215 private boolean performLongClickInternal(float x, float y) { 6216 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_LONG_CLICKED); 6217 6218 boolean handled = false; 6219 final ListenerInfo li = mListenerInfo; 6220 if (li != null && li.mOnLongClickListener != null) { 6221 handled = li.mOnLongClickListener.onLongClick(View.this); 6222 } 6223 if (!handled) { 6224 final boolean isAnchored = !Float.isNaN(x) && !Float.isNaN(y); 6225 handled = isAnchored ? showContextMenu(x, y) : showContextMenu(); 6226 } 6227 if ((mViewFlags & TOOLTIP) == TOOLTIP) { 6228 if (!handled) { 6229 handled = showLongClickTooltip((int) x, (int) y); 6230 } 6231 } 6232 if (handled) { 6233 performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); 6234 } 6235 return handled; 6236 } 6237 6238 /** 6239 * Call this view's OnContextClickListener, if it is defined. 6240 * 6241 * @param x the x coordinate of the context click 6242 * @param y the y coordinate of the context click 6243 * @return True if there was an assigned OnContextClickListener that consumed the event, false 6244 * otherwise. 6245 */ 6246 public boolean performContextClick(float x, float y) { 6247 return performContextClick(); 6248 } 6249 6250 /** 6251 * Call this view's OnContextClickListener, if it is defined. 6252 * 6253 * @return True if there was an assigned OnContextClickListener that consumed the event, false 6254 * otherwise. 6255 */ 6256 public boolean performContextClick() { 6257 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CONTEXT_CLICKED); 6258 6259 boolean handled = false; 6260 ListenerInfo li = mListenerInfo; 6261 if (li != null && li.mOnContextClickListener != null) { 6262 handled = li.mOnContextClickListener.onContextClick(View.this); 6263 } 6264 if (handled) { 6265 performHapticFeedback(HapticFeedbackConstants.CONTEXT_CLICK); 6266 } 6267 return handled; 6268 } 6269 6270 /** 6271 * Performs button-related actions during a touch down event. 6272 * 6273 * @param event The event. 6274 * @return True if the down was consumed. 6275 * 6276 * @hide 6277 */ 6278 protected boolean performButtonActionOnTouchDown(MotionEvent event) { 6279 if (event.isFromSource(InputDevice.SOURCE_MOUSE) && 6280 (event.getButtonState() & MotionEvent.BUTTON_SECONDARY) != 0) { 6281 showContextMenu(event.getX(), event.getY()); 6282 mPrivateFlags |= PFLAG_CANCEL_NEXT_UP_EVENT; 6283 return true; 6284 } 6285 return false; 6286 } 6287 6288 /** 6289 * Shows the context menu for this view. 6290 * 6291 * @return {@code true} if the context menu was shown, {@code false} 6292 * otherwise 6293 * @see #showContextMenu(float, float) 6294 */ 6295 public boolean showContextMenu() { 6296 return getParent().showContextMenuForChild(this); 6297 } 6298 6299 /** 6300 * Shows the context menu for this view anchored to the specified 6301 * view-relative coordinate. 6302 * 6303 * @param x the X coordinate in pixels relative to the view to which the 6304 * menu should be anchored, or {@link Float#NaN} to disable anchoring 6305 * @param y the Y coordinate in pixels relative to the view to which the 6306 * menu should be anchored, or {@link Float#NaN} to disable anchoring 6307 * @return {@code true} if the context menu was shown, {@code false} 6308 * otherwise 6309 */ 6310 public boolean showContextMenu(float x, float y) { 6311 return getParent().showContextMenuForChild(this, x, y); 6312 } 6313 6314 /** 6315 * Start an action mode with the default type {@link ActionMode#TYPE_PRIMARY}. 6316 * 6317 * @param callback Callback that will control the lifecycle of the action mode 6318 * @return The new action mode if it is started, null otherwise 6319 * 6320 * @see ActionMode 6321 * @see #startActionMode(android.view.ActionMode.Callback, int) 6322 */ 6323 public ActionMode startActionMode(ActionMode.Callback callback) { 6324 return startActionMode(callback, ActionMode.TYPE_PRIMARY); 6325 } 6326 6327 /** 6328 * Start an action mode with the given type. 6329 * 6330 * @param callback Callback that will control the lifecycle of the action mode 6331 * @param type One of {@link ActionMode#TYPE_PRIMARY} or {@link ActionMode#TYPE_FLOATING}. 6332 * @return The new action mode if it is started, null otherwise 6333 * 6334 * @see ActionMode 6335 */ 6336 public ActionMode startActionMode(ActionMode.Callback callback, int type) { 6337 ViewParent parent = getParent(); 6338 if (parent == null) return null; 6339 try { 6340 return parent.startActionModeForChild(this, callback, type); 6341 } catch (AbstractMethodError ame) { 6342 // Older implementations of custom views might not implement this. 6343 return parent.startActionModeForChild(this, callback); 6344 } 6345 } 6346 6347 /** 6348 * Call {@link Context#startActivityForResult(String, Intent, int, Bundle)} for the View's 6349 * Context, creating a unique View identifier to retrieve the result. 6350 * 6351 * @param intent The Intent to be started. 6352 * @param requestCode The request code to use. 6353 * @hide 6354 */ 6355 public void startActivityForResult(Intent intent, int requestCode) { 6356 mStartActivityRequestWho = "@android:view:" + System.identityHashCode(this); 6357 getContext().startActivityForResult(mStartActivityRequestWho, intent, requestCode, null); 6358 } 6359 6360 /** 6361 * If this View corresponds to the calling who, dispatches the activity result. 6362 * @param who The identifier for the targeted View to receive the result. 6363 * @param requestCode The integer request code originally supplied to 6364 * startActivityForResult(), allowing you to identify who this 6365 * result came from. 6366 * @param resultCode The integer result code returned by the child activity 6367 * through its setResult(). 6368 * @param data An Intent, which can return result data to the caller 6369 * (various data can be attached to Intent "extras"). 6370 * @return {@code true} if the activity result was dispatched. 6371 * @hide 6372 */ 6373 public boolean dispatchActivityResult( 6374 String who, int requestCode, int resultCode, Intent data) { 6375 if (mStartActivityRequestWho != null && mStartActivityRequestWho.equals(who)) { 6376 onActivityResult(requestCode, resultCode, data); 6377 mStartActivityRequestWho = null; 6378 return true; 6379 } 6380 return false; 6381 } 6382 6383 /** 6384 * Receive the result from a previous call to {@link #startActivityForResult(Intent, int)}. 6385 * 6386 * @param requestCode The integer request code originally supplied to 6387 * startActivityForResult(), allowing you to identify who this 6388 * result came from. 6389 * @param resultCode The integer result code returned by the child activity 6390 * through its setResult(). 6391 * @param data An Intent, which can return result data to the caller 6392 * (various data can be attached to Intent "extras"). 6393 * @hide 6394 */ 6395 public void onActivityResult(int requestCode, int resultCode, Intent data) { 6396 // Do nothing. 6397 } 6398 6399 /** 6400 * Register a callback to be invoked when a hardware key is pressed in this view. 6401 * Key presses in software input methods will generally not trigger the methods of 6402 * this listener. 6403 * @param l the key listener to attach to this view 6404 */ 6405 public void setOnKeyListener(OnKeyListener l) { 6406 getListenerInfo().mOnKeyListener = l; 6407 } 6408 6409 /** 6410 * Register a callback to be invoked when a touch event is sent to this view. 6411 * @param l the touch listener to attach to this view 6412 */ 6413 public void setOnTouchListener(OnTouchListener l) { 6414 getListenerInfo().mOnTouchListener = l; 6415 } 6416 6417 /** 6418 * Register a callback to be invoked when a generic motion event is sent to this view. 6419 * @param l the generic motion listener to attach to this view 6420 */ 6421 public void setOnGenericMotionListener(OnGenericMotionListener l) { 6422 getListenerInfo().mOnGenericMotionListener = l; 6423 } 6424 6425 /** 6426 * Register a callback to be invoked when a hover event is sent to this view. 6427 * @param l the hover listener to attach to this view 6428 */ 6429 public void setOnHoverListener(OnHoverListener l) { 6430 getListenerInfo().mOnHoverListener = l; 6431 } 6432 6433 /** 6434 * Register a drag event listener callback object for this View. The parameter is 6435 * an implementation of {@link android.view.View.OnDragListener}. To send a drag event to a 6436 * View, the system calls the 6437 * {@link android.view.View.OnDragListener#onDrag(View,DragEvent)} method. 6438 * @param l An implementation of {@link android.view.View.OnDragListener}. 6439 */ 6440 public void setOnDragListener(OnDragListener l) { 6441 getListenerInfo().mOnDragListener = l; 6442 } 6443 6444 /** 6445 * Give this view focus. This will cause 6446 * {@link #onFocusChanged(boolean, int, android.graphics.Rect)} to be called. 6447 * 6448 * Note: this does not check whether this {@link View} should get focus, it just 6449 * gives it focus no matter what. It should only be called internally by framework 6450 * code that knows what it is doing, namely {@link #requestFocus(int, Rect)}. 6451 * 6452 * @param direction values are {@link View#FOCUS_UP}, {@link View#FOCUS_DOWN}, 6453 * {@link View#FOCUS_LEFT} or {@link View#FOCUS_RIGHT}. This is the direction which 6454 * focus moved when requestFocus() is called. It may not always 6455 * apply, in which case use the default View.FOCUS_DOWN. 6456 * @param previouslyFocusedRect The rectangle of the view that had focus 6457 * prior in this View's coordinate system. 6458 */ 6459 void handleFocusGainInternal(@FocusRealDirection int direction, Rect previouslyFocusedRect) { 6460 if (DBG) { 6461 System.out.println(this + " requestFocus()"); 6462 } 6463 6464 if ((mPrivateFlags & PFLAG_FOCUSED) == 0) { 6465 mPrivateFlags |= PFLAG_FOCUSED; 6466 6467 View oldFocus = (mAttachInfo != null) ? getRootView().findFocus() : null; 6468 6469 if (mParent != null) { 6470 mParent.requestChildFocus(this, this); 6471 setFocusedInCluster(); 6472 } 6473 6474 if (mAttachInfo != null) { 6475 mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(oldFocus, this); 6476 } 6477 6478 onFocusChanged(true, direction, previouslyFocusedRect); 6479 refreshDrawableState(); 6480 } 6481 } 6482 6483 /** 6484 * Sets this view's preference for reveal behavior when it gains focus. 6485 * 6486 * <p>When set to true, this is a signal to ancestor views in the hierarchy that 6487 * this view would prefer to be brought fully into view when it gains focus. 6488 * For example, a text field that a user is meant to type into. Other views such 6489 * as scrolling containers may prefer to opt-out of this behavior.</p> 6490 * 6491 * <p>The default value for views is true, though subclasses may change this 6492 * based on their preferred behavior.</p> 6493 * 6494 * @param revealOnFocus true to request reveal on focus in ancestors, false otherwise 6495 * 6496 * @see #getRevealOnFocusHint() 6497 */ 6498 public final void setRevealOnFocusHint(boolean revealOnFocus) { 6499 if (revealOnFocus) { 6500 mPrivateFlags3 &= ~PFLAG3_NO_REVEAL_ON_FOCUS; 6501 } else { 6502 mPrivateFlags3 |= PFLAG3_NO_REVEAL_ON_FOCUS; 6503 } 6504 } 6505 6506 /** 6507 * Returns this view's preference for reveal behavior when it gains focus. 6508 * 6509 * <p>When this method returns true for a child view requesting focus, ancestor 6510 * views responding to a focus change in {@link ViewParent#requestChildFocus(View, View)} 6511 * should make a best effort to make the newly focused child fully visible to the user. 6512 * When it returns false, ancestor views should preferably not disrupt scroll positioning or 6513 * other properties affecting visibility to the user as part of the focus change.</p> 6514 * 6515 * @return true if this view would prefer to become fully visible when it gains focus, 6516 * false if it would prefer not to disrupt scroll positioning 6517 * 6518 * @see #setRevealOnFocusHint(boolean) 6519 */ 6520 public final boolean getRevealOnFocusHint() { 6521 return (mPrivateFlags3 & PFLAG3_NO_REVEAL_ON_FOCUS) == 0; 6522 } 6523 6524 /** 6525 * Populates <code>outRect</code> with the hotspot bounds. By default, 6526 * the hotspot bounds are identical to the screen bounds. 6527 * 6528 * @param outRect rect to populate with hotspot bounds 6529 * @hide Only for internal use by views and widgets. 6530 */ 6531 public void getHotspotBounds(Rect outRect) { 6532 final Drawable background = getBackground(); 6533 if (background != null) { 6534 background.getHotspotBounds(outRect); 6535 } else { 6536 getBoundsOnScreen(outRect); 6537 } 6538 } 6539 6540 /** 6541 * Request that a rectangle of this view be visible on the screen, 6542 * scrolling if necessary just enough. 6543 * 6544 * <p>A View should call this if it maintains some notion of which part 6545 * of its content is interesting. For example, a text editing view 6546 * should call this when its cursor moves. 6547 * <p>The Rectangle passed into this method should be in the View's content coordinate space. 6548 * It should not be affected by which part of the View is currently visible or its scroll 6549 * position. 6550 * 6551 * @param rectangle The rectangle in the View's content coordinate space 6552 * @return Whether any parent scrolled. 6553 */ 6554 public boolean requestRectangleOnScreen(Rect rectangle) { 6555 return requestRectangleOnScreen(rectangle, false); 6556 } 6557 6558 /** 6559 * Request that a rectangle of this view be visible on the screen, 6560 * scrolling if necessary just enough. 6561 * 6562 * <p>A View should call this if it maintains some notion of which part 6563 * of its content is interesting. For example, a text editing view 6564 * should call this when its cursor moves. 6565 * <p>The Rectangle passed into this method should be in the View's content coordinate space. 6566 * It should not be affected by which part of the View is currently visible or its scroll 6567 * position. 6568 * <p>When <code>immediate</code> is set to true, scrolling will not be 6569 * animated. 6570 * 6571 * @param rectangle The rectangle in the View's content coordinate space 6572 * @param immediate True to forbid animated scrolling, false otherwise 6573 * @return Whether any parent scrolled. 6574 */ 6575 public boolean requestRectangleOnScreen(Rect rectangle, boolean immediate) { 6576 if (mParent == null) { 6577 return false; 6578 } 6579 6580 View child = this; 6581 6582 RectF position = (mAttachInfo != null) ? mAttachInfo.mTmpTransformRect : new RectF(); 6583 position.set(rectangle); 6584 6585 ViewParent parent = mParent; 6586 boolean scrolled = false; 6587 while (parent != null) { 6588 rectangle.set((int) position.left, (int) position.top, 6589 (int) position.right, (int) position.bottom); 6590 6591 scrolled |= parent.requestChildRectangleOnScreen(child, rectangle, immediate); 6592 6593 if (!(parent instanceof View)) { 6594 break; 6595 } 6596 6597 // move it from child's content coordinate space to parent's content coordinate space 6598 position.offset(child.mLeft - child.getScrollX(), child.mTop -child.getScrollY()); 6599 6600 child = (View) parent; 6601 parent = child.getParent(); 6602 } 6603 6604 return scrolled; 6605 } 6606 6607 /** 6608 * Called when this view wants to give up focus. If focus is cleared 6609 * {@link #onFocusChanged(boolean, int, android.graphics.Rect)} is called. 6610 * <p> 6611 * <strong>Note:</strong> When a View clears focus the framework is trying 6612 * to give focus to the first focusable View from the top. Hence, if this 6613 * View is the first from the top that can take focus, then all callbacks 6614 * related to clearing focus will be invoked after which the framework will 6615 * give focus to this view. 6616 * </p> 6617 */ 6618 public void clearFocus() { 6619 if (DBG) { 6620 System.out.println(this + " clearFocus()"); 6621 } 6622 6623 clearFocusInternal(null, true, true); 6624 } 6625 6626 /** 6627 * Clears focus from the view, optionally propagating the change up through 6628 * the parent hierarchy and requesting that the root view place new focus. 6629 * 6630 * @param propagate whether to propagate the change up through the parent 6631 * hierarchy 6632 * @param refocus when propagate is true, specifies whether to request the 6633 * root view place new focus 6634 */ 6635 void clearFocusInternal(View focused, boolean propagate, boolean refocus) { 6636 if ((mPrivateFlags & PFLAG_FOCUSED) != 0) { 6637 mPrivateFlags &= ~PFLAG_FOCUSED; 6638 6639 if (propagate && mParent != null) { 6640 mParent.clearChildFocus(this); 6641 } 6642 6643 onFocusChanged(false, 0, null); 6644 refreshDrawableState(); 6645 6646 if (propagate && (!refocus || !rootViewRequestFocus())) { 6647 notifyGlobalFocusCleared(this); 6648 } 6649 } 6650 } 6651 6652 void notifyGlobalFocusCleared(View oldFocus) { 6653 if (oldFocus != null && mAttachInfo != null) { 6654 mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(oldFocus, null); 6655 } 6656 } 6657 6658 boolean rootViewRequestFocus() { 6659 final View root = getRootView(); 6660 return root != null && root.requestFocus(); 6661 } 6662 6663 /** 6664 * Called internally by the view system when a new view is getting focus. 6665 * This is what clears the old focus. 6666 * <p> 6667 * <b>NOTE:</b> The parent view's focused child must be updated manually 6668 * after calling this method. Otherwise, the view hierarchy may be left in 6669 * an inconstent state. 6670 */ 6671 void unFocus(View focused) { 6672 if (DBG) { 6673 System.out.println(this + " unFocus()"); 6674 } 6675 6676 clearFocusInternal(focused, false, false); 6677 } 6678 6679 /** 6680 * Returns true if this view has focus itself, or is the ancestor of the 6681 * view that has focus. 6682 * 6683 * @return True if this view has or contains focus, false otherwise. 6684 */ 6685 @ViewDebug.ExportedProperty(category = "focus") 6686 public boolean hasFocus() { 6687 return (mPrivateFlags & PFLAG_FOCUSED) != 0; 6688 } 6689 6690 /** 6691 * Returns true if this view is focusable or if it contains a reachable View 6692 * for which {@link #hasFocusable()} returns {@code true}. A "reachable hasFocusable()" 6693 * is a view whose parents do not block descendants focus. 6694 * Only {@link #VISIBLE} views are considered focusable. 6695 * 6696 * <p>As of {@link Build.VERSION_CODES#O} views that are determined to be focusable 6697 * through {@link #FOCUSABLE_AUTO} will also cause this method to return {@code true}. 6698 * Apps that declare a {@link android.content.pm.ApplicationInfo#targetSdkVersion} of 6699 * earlier than {@link Build.VERSION_CODES#O} will continue to see this method return 6700 * {@code false} for views not explicitly marked as focusable. 6701 * Use {@link #hasExplicitFocusable()} if you require the pre-{@link Build.VERSION_CODES#O} 6702 * behavior.</p> 6703 * 6704 * @return {@code true} if the view is focusable or if the view contains a focusable 6705 * view, {@code false} otherwise 6706 * 6707 * @see ViewGroup#FOCUS_BLOCK_DESCENDANTS 6708 * @see ViewGroup#getTouchscreenBlocksFocus() 6709 * @see #hasExplicitFocusable() 6710 */ 6711 public boolean hasFocusable() { 6712 return hasFocusable(!sHasFocusableExcludeAutoFocusable, false); 6713 } 6714 6715 /** 6716 * Returns true if this view is focusable or if it contains a reachable View 6717 * for which {@link #hasExplicitFocusable()} returns {@code true}. 6718 * A "reachable hasExplicitFocusable()" is a view whose parents do not block descendants focus. 6719 * Only {@link #VISIBLE} views for which {@link #getFocusable()} would return 6720 * {@link #FOCUSABLE} are considered focusable. 6721 * 6722 * <p>This method preserves the pre-{@link Build.VERSION_CODES#O} behavior of 6723 * {@link #hasFocusable()} in that only views explicitly set focusable will cause 6724 * this method to return true. A view set to {@link #FOCUSABLE_AUTO} that resolves 6725 * to focusable will not.</p> 6726 * 6727 * @return {@code true} if the view is focusable or if the view contains a focusable 6728 * view, {@code false} otherwise 6729 * 6730 * @see #hasFocusable() 6731 */ 6732 public boolean hasExplicitFocusable() { 6733 return hasFocusable(false, true); 6734 } 6735 6736 boolean hasFocusable(boolean allowAutoFocus, boolean dispatchExplicit) { 6737 if (!isFocusableInTouchMode()) { 6738 for (ViewParent p = mParent; p instanceof ViewGroup; p = p.getParent()) { 6739 final ViewGroup g = (ViewGroup) p; 6740 if (g.shouldBlockFocusForTouchscreen()) { 6741 return false; 6742 } 6743 } 6744 } 6745 6746 // Invisible and gone views are never focusable. 6747 if ((mViewFlags & VISIBILITY_MASK) != VISIBLE) { 6748 return false; 6749 } 6750 6751 // Only use effective focusable value when allowed. 6752 if ((allowAutoFocus || getFocusable() != FOCUSABLE_AUTO) && isFocusable()) { 6753 return true; 6754 } 6755 6756 return false; 6757 } 6758 6759 /** 6760 * Called by the view system when the focus state of this view changes. 6761 * When the focus change event is caused by directional navigation, direction 6762 * and previouslyFocusedRect provide insight into where the focus is coming from. 6763 * When overriding, be sure to call up through to the super class so that 6764 * the standard focus handling will occur. 6765 * 6766 * @param gainFocus True if the View has focus; false otherwise. 6767 * @param direction The direction focus has moved when requestFocus() 6768 * is called to give this view focus. Values are 6769 * {@link #FOCUS_UP}, {@link #FOCUS_DOWN}, {@link #FOCUS_LEFT}, 6770 * {@link #FOCUS_RIGHT}, {@link #FOCUS_FORWARD}, or {@link #FOCUS_BACKWARD}. 6771 * It may not always apply, in which case use the default. 6772 * @param previouslyFocusedRect The rectangle, in this view's coordinate 6773 * system, of the previously focused view. If applicable, this will be 6774 * passed in as finer grained information about where the focus is coming 6775 * from (in addition to direction). Will be <code>null</code> otherwise. 6776 */ 6777 @CallSuper 6778 protected void onFocusChanged(boolean gainFocus, @FocusDirection int direction, 6779 @Nullable Rect previouslyFocusedRect) { 6780 if (gainFocus) { 6781 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED); 6782 } else { 6783 notifyViewAccessibilityStateChangedIfNeeded( 6784 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 6785 } 6786 6787 // Here we check whether we still need the default focus highlight, and switch it on/off. 6788 switchDefaultFocusHighlight(); 6789 6790 InputMethodManager imm = InputMethodManager.peekInstance(); 6791 if (!gainFocus) { 6792 if (isPressed()) { 6793 setPressed(false); 6794 } 6795 if (imm != null && mAttachInfo != null && mAttachInfo.mHasWindowFocus) { 6796 imm.focusOut(this); 6797 } 6798 onFocusLost(); 6799 } else if (imm != null && mAttachInfo != null && mAttachInfo.mHasWindowFocus) { 6800 imm.focusIn(this); 6801 } 6802 6803 invalidate(true); 6804 ListenerInfo li = mListenerInfo; 6805 if (li != null && li.mOnFocusChangeListener != null) { 6806 li.mOnFocusChangeListener.onFocusChange(this, gainFocus); 6807 } 6808 6809 if (mAttachInfo != null) { 6810 mAttachInfo.mKeyDispatchState.reset(this); 6811 } 6812 6813 notifyEnterOrExitForAutoFillIfNeeded(gainFocus); 6814 } 6815 6816 private void notifyEnterOrExitForAutoFillIfNeeded(boolean enter) { 6817 if (isAutofillable() && isAttachedToWindow()) { 6818 AutofillManager afm = getAutofillManager(); 6819 if (afm != null) { 6820 if (enter && hasWindowFocus() && isFocused()) { 6821 afm.notifyViewEntered(this); 6822 } else if (!hasWindowFocus() || !isFocused()) { 6823 afm.notifyViewExited(this); 6824 } 6825 } 6826 } 6827 } 6828 6829 /** 6830 * Sends an accessibility event of the given type. If accessibility is 6831 * not enabled this method has no effect. The default implementation calls 6832 * {@link #onInitializeAccessibilityEvent(AccessibilityEvent)} first 6833 * to populate information about the event source (this View), then calls 6834 * {@link #dispatchPopulateAccessibilityEvent(AccessibilityEvent)} to 6835 * populate the text content of the event source including its descendants, 6836 * and last calls 6837 * {@link ViewParent#requestSendAccessibilityEvent(View, AccessibilityEvent)} 6838 * on its parent to request sending of the event to interested parties. 6839 * <p> 6840 * If an {@link AccessibilityDelegate} has been specified via calling 6841 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 6842 * {@link AccessibilityDelegate#sendAccessibilityEvent(View, int)} is 6843 * responsible for handling this call. 6844 * </p> 6845 * 6846 * @param eventType The type of the event to send, as defined by several types from 6847 * {@link android.view.accessibility.AccessibilityEvent}, such as 6848 * {@link android.view.accessibility.AccessibilityEvent#TYPE_VIEW_CLICKED} or 6849 * {@link android.view.accessibility.AccessibilityEvent#TYPE_VIEW_HOVER_ENTER}. 6850 * 6851 * @see #onInitializeAccessibilityEvent(AccessibilityEvent) 6852 * @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent) 6853 * @see ViewParent#requestSendAccessibilityEvent(View, AccessibilityEvent) 6854 * @see AccessibilityDelegate 6855 */ 6856 public void sendAccessibilityEvent(int eventType) { 6857 if (mAccessibilityDelegate != null) { 6858 mAccessibilityDelegate.sendAccessibilityEvent(this, eventType); 6859 } else { 6860 sendAccessibilityEventInternal(eventType); 6861 } 6862 } 6863 6864 /** 6865 * Convenience method for sending a {@link AccessibilityEvent#TYPE_ANNOUNCEMENT} 6866 * {@link AccessibilityEvent} to make an announcement which is related to some 6867 * sort of a context change for which none of the events representing UI transitions 6868 * is a good fit. For example, announcing a new page in a book. If accessibility 6869 * is not enabled this method does nothing. 6870 * 6871 * @param text The announcement text. 6872 */ 6873 public void announceForAccessibility(CharSequence text) { 6874 if (AccessibilityManager.getInstance(mContext).isEnabled() && mParent != null) { 6875 AccessibilityEvent event = AccessibilityEvent.obtain( 6876 AccessibilityEvent.TYPE_ANNOUNCEMENT); 6877 onInitializeAccessibilityEvent(event); 6878 event.getText().add(text); 6879 event.setContentDescription(null); 6880 mParent.requestSendAccessibilityEvent(this, event); 6881 } 6882 } 6883 6884 /** 6885 * @see #sendAccessibilityEvent(int) 6886 * 6887 * Note: Called from the default {@link AccessibilityDelegate}. 6888 * 6889 * @hide 6890 */ 6891 public void sendAccessibilityEventInternal(int eventType) { 6892 if (AccessibilityManager.getInstance(mContext).isEnabled()) { 6893 sendAccessibilityEventUnchecked(AccessibilityEvent.obtain(eventType)); 6894 } 6895 } 6896 6897 /** 6898 * This method behaves exactly as {@link #sendAccessibilityEvent(int)} but 6899 * takes as an argument an empty {@link AccessibilityEvent} and does not 6900 * perform a check whether accessibility is enabled. 6901 * <p> 6902 * If an {@link AccessibilityDelegate} has been specified via calling 6903 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 6904 * {@link AccessibilityDelegate#sendAccessibilityEventUnchecked(View, AccessibilityEvent)} 6905 * is responsible for handling this call. 6906 * </p> 6907 * 6908 * @param event The event to send. 6909 * 6910 * @see #sendAccessibilityEvent(int) 6911 */ 6912 public void sendAccessibilityEventUnchecked(AccessibilityEvent event) { 6913 if (mAccessibilityDelegate != null) { 6914 mAccessibilityDelegate.sendAccessibilityEventUnchecked(this, event); 6915 } else { 6916 sendAccessibilityEventUncheckedInternal(event); 6917 } 6918 } 6919 6920 /** 6921 * @see #sendAccessibilityEventUnchecked(AccessibilityEvent) 6922 * 6923 * Note: Called from the default {@link AccessibilityDelegate}. 6924 * 6925 * @hide 6926 */ 6927 public void sendAccessibilityEventUncheckedInternal(AccessibilityEvent event) { 6928 if (!isShown()) { 6929 return; 6930 } 6931 onInitializeAccessibilityEvent(event); 6932 // Only a subset of accessibility events populates text content. 6933 if ((event.getEventType() & POPULATING_ACCESSIBILITY_EVENT_TYPES) != 0) { 6934 dispatchPopulateAccessibilityEvent(event); 6935 } 6936 // In the beginning we called #isShown(), so we know that getParent() is not null. 6937 ViewParent parent = getParent(); 6938 if (parent != null) { 6939 getParent().requestSendAccessibilityEvent(this, event); 6940 } 6941 } 6942 6943 /** 6944 * Dispatches an {@link AccessibilityEvent} to the {@link View} first and then 6945 * to its children for adding their text content to the event. Note that the 6946 * event text is populated in a separate dispatch path since we add to the 6947 * event not only the text of the source but also the text of all its descendants. 6948 * A typical implementation will call 6949 * {@link #onPopulateAccessibilityEvent(AccessibilityEvent)} on the this view 6950 * and then call the {@link #dispatchPopulateAccessibilityEvent(AccessibilityEvent)} 6951 * on each child. Override this method if custom population of the event text 6952 * content is required. 6953 * <p> 6954 * If an {@link AccessibilityDelegate} has been specified via calling 6955 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 6956 * {@link AccessibilityDelegate#dispatchPopulateAccessibilityEvent(View, AccessibilityEvent)} 6957 * is responsible for handling this call. 6958 * </p> 6959 * <p> 6960 * <em>Note:</em> Accessibility events of certain types are not dispatched for 6961 * populating the event text via this method. For details refer to {@link AccessibilityEvent}. 6962 * </p> 6963 * 6964 * @param event The event. 6965 * 6966 * @return True if the event population was completed. 6967 */ 6968 public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) { 6969 if (mAccessibilityDelegate != null) { 6970 return mAccessibilityDelegate.dispatchPopulateAccessibilityEvent(this, event); 6971 } else { 6972 return dispatchPopulateAccessibilityEventInternal(event); 6973 } 6974 } 6975 6976 /** 6977 * @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent) 6978 * 6979 * Note: Called from the default {@link AccessibilityDelegate}. 6980 * 6981 * @hide 6982 */ 6983 public boolean dispatchPopulateAccessibilityEventInternal(AccessibilityEvent event) { 6984 onPopulateAccessibilityEvent(event); 6985 return false; 6986 } 6987 6988 /** 6989 * Called from {@link #dispatchPopulateAccessibilityEvent(AccessibilityEvent)} 6990 * giving a chance to this View to populate the accessibility event with its 6991 * text content. While this method is free to modify event 6992 * attributes other than text content, doing so should normally be performed in 6993 * {@link #onInitializeAccessibilityEvent(AccessibilityEvent)}. 6994 * <p> 6995 * Example: Adding formatted date string to an accessibility event in addition 6996 * to the text added by the super implementation: 6997 * <pre> public void onPopulateAccessibilityEvent(AccessibilityEvent event) { 6998 * super.onPopulateAccessibilityEvent(event); 6999 * final int flags = DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_WEEKDAY; 7000 * String selectedDateUtterance = DateUtils.formatDateTime(mContext, 7001 * mCurrentDate.getTimeInMillis(), flags); 7002 * event.getText().add(selectedDateUtterance); 7003 * }</pre> 7004 * <p> 7005 * If an {@link AccessibilityDelegate} has been specified via calling 7006 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 7007 * {@link AccessibilityDelegate#onPopulateAccessibilityEvent(View, AccessibilityEvent)} 7008 * is responsible for handling this call. 7009 * </p> 7010 * <p class="note"><strong>Note:</strong> Always call the super implementation before adding 7011 * information to the event, in case the default implementation has basic information to add. 7012 * </p> 7013 * 7014 * @param event The accessibility event which to populate. 7015 * 7016 * @see #sendAccessibilityEvent(int) 7017 * @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent) 7018 */ 7019 @CallSuper 7020 public void onPopulateAccessibilityEvent(AccessibilityEvent event) { 7021 if (mAccessibilityDelegate != null) { 7022 mAccessibilityDelegate.onPopulateAccessibilityEvent(this, event); 7023 } else { 7024 onPopulateAccessibilityEventInternal(event); 7025 } 7026 } 7027 7028 /** 7029 * @see #onPopulateAccessibilityEvent(AccessibilityEvent) 7030 * 7031 * Note: Called from the default {@link AccessibilityDelegate}. 7032 * 7033 * @hide 7034 */ 7035 public void onPopulateAccessibilityEventInternal(AccessibilityEvent event) { 7036 } 7037 7038 /** 7039 * Initializes an {@link AccessibilityEvent} with information about 7040 * this View which is the event source. In other words, the source of 7041 * an accessibility event is the view whose state change triggered firing 7042 * the event. 7043 * <p> 7044 * Example: Setting the password property of an event in addition 7045 * to properties set by the super implementation: 7046 * <pre> public void onInitializeAccessibilityEvent(AccessibilityEvent event) { 7047 * super.onInitializeAccessibilityEvent(event); 7048 * event.setPassword(true); 7049 * }</pre> 7050 * <p> 7051 * If an {@link AccessibilityDelegate} has been specified via calling 7052 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 7053 * {@link AccessibilityDelegate#onInitializeAccessibilityEvent(View, AccessibilityEvent)} 7054 * is responsible for handling this call. 7055 * </p> 7056 * <p class="note"><strong>Note:</strong> Always call the super implementation before adding 7057 * information to the event, in case the default implementation has basic information to add. 7058 * </p> 7059 * @param event The event to initialize. 7060 * 7061 * @see #sendAccessibilityEvent(int) 7062 * @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent) 7063 */ 7064 @CallSuper 7065 public void onInitializeAccessibilityEvent(AccessibilityEvent event) { 7066 if (mAccessibilityDelegate != null) { 7067 mAccessibilityDelegate.onInitializeAccessibilityEvent(this, event); 7068 } else { 7069 onInitializeAccessibilityEventInternal(event); 7070 } 7071 } 7072 7073 /** 7074 * @see #onInitializeAccessibilityEvent(AccessibilityEvent) 7075 * 7076 * Note: Called from the default {@link AccessibilityDelegate}. 7077 * 7078 * @hide 7079 */ 7080 public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) { 7081 event.setSource(this); 7082 event.setClassName(getAccessibilityClassName()); 7083 event.setPackageName(getContext().getPackageName()); 7084 event.setEnabled(isEnabled()); 7085 event.setContentDescription(mContentDescription); 7086 7087 switch (event.getEventType()) { 7088 case AccessibilityEvent.TYPE_VIEW_FOCUSED: { 7089 ArrayList<View> focusablesTempList = (mAttachInfo != null) 7090 ? mAttachInfo.mTempArrayList : new ArrayList<View>(); 7091 getRootView().addFocusables(focusablesTempList, View.FOCUS_FORWARD, FOCUSABLES_ALL); 7092 event.setItemCount(focusablesTempList.size()); 7093 event.setCurrentItemIndex(focusablesTempList.indexOf(this)); 7094 if (mAttachInfo != null) { 7095 focusablesTempList.clear(); 7096 } 7097 } break; 7098 case AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED: { 7099 CharSequence text = getIterableTextForAccessibility(); 7100 if (text != null && text.length() > 0) { 7101 event.setFromIndex(getAccessibilitySelectionStart()); 7102 event.setToIndex(getAccessibilitySelectionEnd()); 7103 event.setItemCount(text.length()); 7104 } 7105 } break; 7106 } 7107 } 7108 7109 /** 7110 * Returns an {@link AccessibilityNodeInfo} representing this view from the 7111 * point of view of an {@link android.accessibilityservice.AccessibilityService}. 7112 * This method is responsible for obtaining an accessibility node info from a 7113 * pool of reusable instances and calling 7114 * {@link #onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} on this view to 7115 * initialize the former. 7116 * <p> 7117 * Note: The client is responsible for recycling the obtained instance by calling 7118 * {@link AccessibilityNodeInfo#recycle()} to minimize object creation. 7119 * </p> 7120 * 7121 * @return A populated {@link AccessibilityNodeInfo}. 7122 * 7123 * @see AccessibilityNodeInfo 7124 */ 7125 public AccessibilityNodeInfo createAccessibilityNodeInfo() { 7126 if (mAccessibilityDelegate != null) { 7127 return mAccessibilityDelegate.createAccessibilityNodeInfo(this); 7128 } else { 7129 return createAccessibilityNodeInfoInternal(); 7130 } 7131 } 7132 7133 /** 7134 * @see #createAccessibilityNodeInfo() 7135 * 7136 * @hide 7137 */ 7138 public AccessibilityNodeInfo createAccessibilityNodeInfoInternal() { 7139 AccessibilityNodeProvider provider = getAccessibilityNodeProvider(); 7140 if (provider != null) { 7141 return provider.createAccessibilityNodeInfo(AccessibilityNodeProvider.HOST_VIEW_ID); 7142 } else { 7143 AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain(this); 7144 onInitializeAccessibilityNodeInfo(info); 7145 return info; 7146 } 7147 } 7148 7149 /** 7150 * Initializes an {@link AccessibilityNodeInfo} with information about this view. 7151 * The base implementation sets: 7152 * <ul> 7153 * <li>{@link AccessibilityNodeInfo#setParent(View)},</li> 7154 * <li>{@link AccessibilityNodeInfo#setBoundsInParent(Rect)},</li> 7155 * <li>{@link AccessibilityNodeInfo#setBoundsInScreen(Rect)},</li> 7156 * <li>{@link AccessibilityNodeInfo#setPackageName(CharSequence)},</li> 7157 * <li>{@link AccessibilityNodeInfo#setClassName(CharSequence)},</li> 7158 * <li>{@link AccessibilityNodeInfo#setContentDescription(CharSequence)},</li> 7159 * <li>{@link AccessibilityNodeInfo#setEnabled(boolean)},</li> 7160 * <li>{@link AccessibilityNodeInfo#setClickable(boolean)},</li> 7161 * <li>{@link AccessibilityNodeInfo#setFocusable(boolean)},</li> 7162 * <li>{@link AccessibilityNodeInfo#setFocused(boolean)},</li> 7163 * <li>{@link AccessibilityNodeInfo#setLongClickable(boolean)},</li> 7164 * <li>{@link AccessibilityNodeInfo#setSelected(boolean)},</li> 7165 * <li>{@link AccessibilityNodeInfo#setContextClickable(boolean)}</li> 7166 * </ul> 7167 * <p> 7168 * Subclasses should override this method, call the super implementation, 7169 * and set additional attributes. 7170 * </p> 7171 * <p> 7172 * If an {@link AccessibilityDelegate} has been specified via calling 7173 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 7174 * {@link AccessibilityDelegate#onInitializeAccessibilityNodeInfo(View, AccessibilityNodeInfo)} 7175 * is responsible for handling this call. 7176 * </p> 7177 * 7178 * @param info The instance to initialize. 7179 */ 7180 @CallSuper 7181 public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { 7182 if (mAccessibilityDelegate != null) { 7183 mAccessibilityDelegate.onInitializeAccessibilityNodeInfo(this, info); 7184 } else { 7185 onInitializeAccessibilityNodeInfoInternal(info); 7186 } 7187 } 7188 7189 /** 7190 * Gets the location of this view in screen coordinates. 7191 * 7192 * @param outRect The output location 7193 * @hide 7194 */ 7195 public void getBoundsOnScreen(Rect outRect) { 7196 getBoundsOnScreen(outRect, false); 7197 } 7198 7199 /** 7200 * Gets the location of this view in screen coordinates. 7201 * 7202 * @param outRect The output location 7203 * @param clipToParent Whether to clip child bounds to the parent ones. 7204 * @hide 7205 */ 7206 public void getBoundsOnScreen(Rect outRect, boolean clipToParent) { 7207 if (mAttachInfo == null) { 7208 return; 7209 } 7210 7211 RectF position = mAttachInfo.mTmpTransformRect; 7212 position.set(0, 0, mRight - mLeft, mBottom - mTop); 7213 7214 if (!hasIdentityMatrix()) { 7215 getMatrix().mapRect(position); 7216 } 7217 7218 position.offset(mLeft, mTop); 7219 7220 ViewParent parent = mParent; 7221 while (parent instanceof View) { 7222 View parentView = (View) parent; 7223 7224 position.offset(-parentView.mScrollX, -parentView.mScrollY); 7225 7226 if (clipToParent) { 7227 position.left = Math.max(position.left, 0); 7228 position.top = Math.max(position.top, 0); 7229 position.right = Math.min(position.right, parentView.getWidth()); 7230 position.bottom = Math.min(position.bottom, parentView.getHeight()); 7231 } 7232 7233 if (!parentView.hasIdentityMatrix()) { 7234 parentView.getMatrix().mapRect(position); 7235 } 7236 7237 position.offset(parentView.mLeft, parentView.mTop); 7238 7239 parent = parentView.mParent; 7240 } 7241 7242 if (parent instanceof ViewRootImpl) { 7243 ViewRootImpl viewRootImpl = (ViewRootImpl) parent; 7244 position.offset(0, -viewRootImpl.mCurScrollY); 7245 } 7246 7247 position.offset(mAttachInfo.mWindowLeft, mAttachInfo.mWindowTop); 7248 7249 outRect.set(Math.round(position.left), Math.round(position.top), 7250 Math.round(position.right), Math.round(position.bottom)); 7251 } 7252 7253 /** 7254 * Return the class name of this object to be used for accessibility purposes. 7255 * Subclasses should only override this if they are implementing something that 7256 * should be seen as a completely new class of view when used by accessibility, 7257 * unrelated to the class it is deriving from. This is used to fill in 7258 * {@link AccessibilityNodeInfo#setClassName AccessibilityNodeInfo.setClassName}. 7259 */ 7260 public CharSequence getAccessibilityClassName() { 7261 return View.class.getName(); 7262 } 7263 7264 /** 7265 * Called when assist structure is being retrieved from a view as part of 7266 * {@link android.app.Activity#onProvideAssistData Activity.onProvideAssistData}. 7267 * @param structure Fill in with structured view data. The default implementation 7268 * fills in all data that can be inferred from the view itself. 7269 */ 7270 public void onProvideStructure(ViewStructure structure) { 7271 onProvideStructureForAssistOrAutofill(structure, false); 7272 } 7273 7274 /** 7275 * Called when assist structure is being retrieved from a view as part of an autofill request. 7276 * 7277 * <p>This method already provides most of what's needed for autofill, but should be overridden 7278 * when: 7279 * <ol> 7280 * <li>The view contents does not include PII (Personally Identifiable Information), so it 7281 * can call {@link ViewStructure#setDataIsSensitive(boolean)} passing {@code false}. 7282 * <li>It must set fields such {@link ViewStructure#setText(CharSequence)}, 7283 * {@link ViewStructure#setAutofillOptions(CharSequence[])}, 7284 * or {@link ViewStructure#setUrl(String)}. 7285 * </ol> 7286 * 7287 * @param structure Fill in with structured view data. The default implementation 7288 * fills in all data that can be inferred from the view itself. 7289 * @param flags optional flags (currently {@code 0}). 7290 */ 7291 public void onProvideAutofillStructure(ViewStructure structure, int flags) { 7292 onProvideStructureForAssistOrAutofill(structure, true); 7293 } 7294 7295 private void setAutofillId(ViewStructure structure) { 7296 // The autofill id needs to be unique, but its value doesn't matter, 7297 // so it's better to reuse the accessibility id to save space. 7298 structure.setAutofillId(getAccessibilityViewId()); 7299 } 7300 7301 private void onProvideStructureForAssistOrAutofill(ViewStructure structure, 7302 boolean forAutofill) { 7303 final int id = mID; 7304 if (id != NO_ID && !isViewIdGenerated(id)) { 7305 String pkg, type, entry; 7306 try { 7307 final Resources res = getResources(); 7308 entry = res.getResourceEntryName(id); 7309 type = res.getResourceTypeName(id); 7310 pkg = res.getResourcePackageName(id); 7311 } catch (Resources.NotFoundException e) { 7312 entry = type = pkg = null; 7313 } 7314 structure.setId(id, pkg, type, entry); 7315 } else { 7316 structure.setId(id, null, null, null); 7317 } 7318 7319 if (forAutofill) { 7320 setAutofillId(structure); 7321 final @AutofillType int autofillType = getAutofillType(); 7322 // Don't need to fill autofill info if view does not support it. 7323 // For example, only TextViews that are editable support autofill 7324 if (autofillType != AUTOFILL_TYPE_NONE) { 7325 structure.setAutofillType(autofillType); 7326 structure.setAutofillHints(getAutofillHints()); 7327 structure.setAutofillValue(getAutofillValue()); 7328 } 7329 } 7330 7331 structure.setDimens(mLeft, mTop, mScrollX, mScrollY, mRight - mLeft, mBottom - mTop); 7332 if (!hasIdentityMatrix()) { 7333 structure.setTransformation(getMatrix()); 7334 } 7335 structure.setElevation(getZ()); 7336 structure.setVisibility(getVisibility()); 7337 structure.setEnabled(isEnabled()); 7338 if (isClickable()) { 7339 structure.setClickable(true); 7340 } 7341 if (isFocusable()) { 7342 structure.setFocusable(true); 7343 } 7344 if (isFocused()) { 7345 structure.setFocused(true); 7346 } 7347 if (isAccessibilityFocused()) { 7348 structure.setAccessibilityFocused(true); 7349 } 7350 if (isSelected()) { 7351 structure.setSelected(true); 7352 } 7353 if (isActivated()) { 7354 structure.setActivated(true); 7355 } 7356 if (isLongClickable()) { 7357 structure.setLongClickable(true); 7358 } 7359 if (this instanceof Checkable) { 7360 structure.setCheckable(true); 7361 if (((Checkable)this).isChecked()) { 7362 structure.setChecked(true); 7363 } 7364 } 7365 if (isOpaque()) { 7366 structure.setOpaque(true); 7367 } 7368 if (isContextClickable()) { 7369 structure.setContextClickable(true); 7370 } 7371 structure.setClassName(getAccessibilityClassName().toString()); 7372 structure.setContentDescription(getContentDescription()); 7373 } 7374 7375 /** 7376 * Called when assist structure is being retrieved from a view as part of 7377 * {@link android.app.Activity#onProvideAssistData Activity.onProvideAssistData} to 7378 * generate additional virtual structure under this view. The defaullt implementation 7379 * uses {@link #getAccessibilityNodeProvider()} to try to generate this from the 7380 * view's virtual accessibility nodes, if any. You can override this for a more 7381 * optimal implementation providing this data. 7382 */ 7383 public void onProvideVirtualStructure(ViewStructure structure) { 7384 AccessibilityNodeProvider provider = getAccessibilityNodeProvider(); 7385 if (provider != null) { 7386 AccessibilityNodeInfo info = createAccessibilityNodeInfo(); 7387 structure.setChildCount(1); 7388 ViewStructure root = structure.newChild(0); 7389 populateVirtualStructure(root, provider, info); 7390 info.recycle(); 7391 } 7392 } 7393 7394 /** 7395 * Called when assist structure is being retrieved from a view as part of an autofill request 7396 * to generate additional virtual structure under this view. 7397 * 7398 * <p>When implementing this method, subclasses must follow the rules below: 7399 * 7400 * <ol> 7401 * <li>Also implement {@link #autofill(SparseArray)} to autofill the virtual 7402 * children. 7403 * <li>Call 7404 * {@link android.view.autofill.AutofillManager#notifyViewEntered} and 7405 * {@link android.view.autofill.AutofillManager#notifyViewExited(View, int)} 7406 * when the focus inside the view changed. 7407 * <li>Call {@link android.view.autofill.AutofillManager#notifyValueChanged(View, int, 7408 * AutofillValue)} when the value of a child changed. 7409 * <li>Call {@link AutofillManager#commit()} when the autofill context 7410 * of the view structure changed and you want the current autofill interaction if such 7411 * to be commited. 7412 * <li>Call {@link AutofillManager#cancel()} ()} when the autofill context 7413 * of the view structure changed and you want the current autofill interaction if such 7414 * to be cancelled. 7415 * </ol> 7416 * 7417 * @param structure Fill in with structured view data. 7418 * @param flags optional flags (currently {@code 0}). 7419 */ 7420 public void onProvideAutofillVirtualStructure(ViewStructure structure, int flags) { 7421 // TODO(b/36171235): need a way to let apps set the ViewStructure without forcing them 7422 // to call super() (in case they override both this method and dispatchProvide.... 7423 // Perhaps the best solution would simply make setAutofillId(ViewStructure) public. 7424 setAutofillId(structure); 7425 } 7426 7427 /** 7428 * Automatically fills the content of this view with the {@code value}. 7429 * 7430 * <p>By default does nothing, but views should override it (and {@link #getAutofillType()}, 7431 * {@link #getAutofillValue()}, and {@link #onProvideAutofillStructure(ViewStructure, int)} 7432 * to support the Autofill Framework. 7433 * 7434 * <p>Typically, it is implemented by: 7435 * 7436 * <ol> 7437 * <li>Calling the proper getter method on {@link AutofillValue} to fetch the actual value. 7438 * <li>Passing the actual value to the equivalent setter in the view. 7439 * </ol> 7440 * 7441 * <p>For example, a text-field view would call: 7442 * <pre class="prettyprint"> 7443 * CharSequence text = value.getTextValue(); 7444 * if (text != null) { 7445 * setText(text); 7446 * } 7447 * </pre> 7448 * 7449 * <p>If the value is updated asyncronously the next call to 7450 * {@link AutofillManager#notifyValueChanged(View)} must happen <u>after</u> the value was 7451 * changed to the autofilled value. If not, the view will not be considered autofilled. 7452 * 7453 * @param value value to be autofilled. 7454 */ 7455 public void autofill(@SuppressWarnings("unused") AutofillValue value) { 7456 } 7457 7458 /** 7459 * Automatically fills the content of a virtual views. 7460 * 7461 * <p>See {@link #autofill(AutofillValue)} and 7462 * {@link #onProvideAutofillVirtualStructure(ViewStructure, int)} for more info. 7463 * <p>To indicate that a virtual view was autofilled 7464 * <code>@android:drawable/autofilled_highlight</code> should be drawn over it until the data 7465 * changes. 7466 * 7467 * @param values map of values to be autofilled, keyed by virtual child id. 7468 */ 7469 public void autofill(@NonNull @SuppressWarnings("unused") SparseArray<AutofillValue> values) { 7470 } 7471 7472 /** 7473 * Describes the autofill type that should be used on calls to 7474 * {@link #autofill(AutofillValue)} and {@link #autofill(SparseArray)}. 7475 * 7476 * <p>By default returns {@link #AUTOFILL_TYPE_NONE}, but views should override it (and 7477 * {@link #autofill(AutofillValue)} to support the Autofill Framework. 7478 */ 7479 public @AutofillType int getAutofillType() { 7480 return AUTOFILL_TYPE_NONE; 7481 } 7482 7483 /** 7484 * Describes the content of a view so that a autofill service can fill in the appropriate data. 7485 * 7486 * @return The hints set via the attribute or {@code null} if no hint it set. 7487 * 7488 * @attr ref android.R.styleable#View_autofillHints 7489 */ 7490 @ViewDebug.ExportedProperty() 7491 @Nullable public String[] getAutofillHints() { 7492 return mAutofillHints; 7493 } 7494 7495 /** 7496 * @hide 7497 */ 7498 public boolean isAutofilled() { 7499 return (mPrivateFlags3 & PFLAG3_IS_AUTOFILLED) != 0; 7500 } 7501 7502 /** 7503 * Gets the {@link View}'s current autofill value. 7504 * 7505 * <p>By default returns {@code null}, but views should override it (and 7506 * {@link #autofill(AutofillValue)}, and {@link #getAutofillType()} to support the Autofill 7507 * Framework. 7508 */ 7509 @Nullable 7510 public AutofillValue getAutofillValue() { 7511 return null; 7512 } 7513 7514 /** 7515 * Gets the mode for determining whether this View is important for autofill. 7516 * 7517 * <p>See {@link #setImportantForAutofill(int)} for more info about this mode. 7518 * 7519 * @return {@link #IMPORTANT_FOR_AUTOFILL_AUTO} by default, or value passed to 7520 * {@link #setImportantForAutofill(int)}. 7521 * 7522 * @attr ref android.R.styleable#View_importantForAutofill 7523 */ 7524 @ViewDebug.ExportedProperty(mapping = { 7525 @ViewDebug.IntToString(from = IMPORTANT_FOR_AUTOFILL_AUTO, to = "auto"), 7526 @ViewDebug.IntToString(from = IMPORTANT_FOR_AUTOFILL_YES, to = "yes"), 7527 @ViewDebug.IntToString(from = IMPORTANT_FOR_AUTOFILL_NO, to = "no"), 7528 @ViewDebug.IntToString(from = IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS, 7529 to = "yesExcludeDescendants"), 7530 @ViewDebug.IntToString(from = IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS, 7531 to = "noExcludeDescendants")}) 7532 public @AutofillImportance int getImportantForAutofill() { 7533 return (mPrivateFlags3 7534 & PFLAG3_IMPORTANT_FOR_AUTOFILL_MASK) >> PFLAG3_IMPORTANT_FOR_AUTOFILL_SHIFT; 7535 } 7536 7537 /** 7538 * Sets the mode for determining whether this View is important for autofill. 7539 * 7540 * <p>See {@link #setImportantForAutofill(int)} for more info about this mode. 7541 * 7542 * @param mode {@link #IMPORTANT_FOR_AUTOFILL_AUTO}, {@link #IMPORTANT_FOR_AUTOFILL_YES}, 7543 * {@link #IMPORTANT_FOR_AUTOFILL_NO}, {@link #IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS}, 7544 * or {@link #IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS}. 7545 * 7546 * @attr ref android.R.styleable#View_importantForAutofill 7547 */ 7548 public void setImportantForAutofill(@AutofillImportance int mode) { 7549 mPrivateFlags3 &= ~PFLAG3_IMPORTANT_FOR_AUTOFILL_MASK; 7550 mPrivateFlags3 |= (mode << PFLAG3_IMPORTANT_FOR_AUTOFILL_SHIFT) 7551 & PFLAG3_IMPORTANT_FOR_AUTOFILL_MASK; 7552 } 7553 7554 /** 7555 * Hints the Android System whether the {@link android.app.assist.AssistStructure.ViewNode} 7556 * associated with this View should be included in a {@link ViewStructure} used for 7557 * autofill purposes. 7558 * 7559 * <p>Generally speaking, a view is important for autofill if: 7560 * <ol> 7561 * <li>The view can-be autofilled by an {@link android.service.autofill.AutofillService}. 7562 * <li>The view contents can help an {@link android.service.autofill.AutofillService} to 7563 * autofill other views. 7564 * <ol> 7565 * 7566 * <p>For example, view containers should typically return {@code false} for performance reasons 7567 * (since the important info is provided by their children), but if the container is actually 7568 * whose children are part of a compound view, it should return {@code true} (and then override 7569 * {@link #dispatchProvideAutofillStructure(ViewStructure, int)} to simply call 7570 * {@link #onProvideAutofillStructure(ViewStructure, int)} so its children are not included in 7571 * the structure). On the other hand, views representing labels or editable fields should 7572 * typically return {@code true}, but in some cases they could return {@code false} (for 7573 * example, if they're part of a "Captcha" mechanism). 7574 * 7575 * <p>By default, this method returns {@code true} if {@link #getImportantForAutofill()} returns 7576 * {@link #IMPORTANT_FOR_AUTOFILL_YES}, {@code false } if it returns 7577 * {@link #IMPORTANT_FOR_AUTOFILL_NO}, and use some heuristics to define the importance when it 7578 * returns {@link #IMPORTANT_FOR_AUTOFILL_AUTO}. Hence, it should rarely be overridden - Views 7579 * should use {@link #setImportantForAutofill(int)} instead. 7580 * 7581 * <p><strong>Note:</strong> returning {@code false} does not guarantee the view will be 7582 * excluded from the structure; for example, if the user explicitly requested autofill, the 7583 * View might be always included. 7584 * 7585 * <p>This decision applies just for the view, not its children - if the view children are not 7586 * important for autofill, the view should override 7587 * {@link #dispatchProvideAutofillStructure(ViewStructure, int)} to simply call 7588 * {@link #onProvideAutofillStructure(ViewStructure, int)} (instead of calling 7589 * {@link #dispatchProvideAutofillStructure(ViewStructure, int)} for each child). 7590 * 7591 * @return whether the view is considered important for autofill. 7592 * 7593 * @see #IMPORTANT_FOR_AUTOFILL_AUTO 7594 * @see #IMPORTANT_FOR_AUTOFILL_YES 7595 * @see #IMPORTANT_FOR_AUTOFILL_NO 7596 */ 7597 public final boolean isImportantForAutofill() { 7598 final int flag = getImportantForAutofill(); 7599 7600 // First, check if view explicity set it to YES or NO 7601 if ((flag & IMPORTANT_FOR_AUTOFILL_YES) != 0) { 7602 return true; 7603 } 7604 if ((flag & IMPORTANT_FOR_AUTOFILL_NO) != 0) { 7605 return false; 7606 } 7607 7608 // Then use some heuristics to handle AUTO. 7609 7610 // Always include views that have a explicity resource id. 7611 final int id = mID; 7612 if (id != NO_ID && !isViewIdGenerated(id)) { 7613 final Resources res = getResources(); 7614 String entry = null; 7615 String pkg = null; 7616 try { 7617 entry = res.getResourceEntryName(id); 7618 pkg = res.getResourcePackageName(id); 7619 } catch (Resources.NotFoundException e) { 7620 // ignore 7621 } 7622 if (entry != null && pkg != null && pkg.equals(mContext.getPackageName())) { 7623 return true; 7624 } 7625 } 7626 7627 // Otherwise, assume it's not important... 7628 return false; 7629 } 7630 7631 @Nullable 7632 private AutofillManager getAutofillManager() { 7633 return mContext.getSystemService(AutofillManager.class); 7634 } 7635 7636 private boolean isAutofillable() { 7637 return getAutofillType() != AUTOFILL_TYPE_NONE && !isAutofillBlocked(); 7638 } 7639 7640 private void populateVirtualStructure(ViewStructure structure, 7641 AccessibilityNodeProvider provider, AccessibilityNodeInfo info) { 7642 structure.setId(AccessibilityNodeInfo.getVirtualDescendantId(info.getSourceNodeId()), 7643 null, null, null); 7644 Rect rect = structure.getTempRect(); 7645 info.getBoundsInParent(rect); 7646 structure.setDimens(rect.left, rect.top, 0, 0, rect.width(), rect.height()); 7647 structure.setVisibility(VISIBLE); 7648 structure.setEnabled(info.isEnabled()); 7649 if (info.isClickable()) { 7650 structure.setClickable(true); 7651 } 7652 if (info.isFocusable()) { 7653 structure.setFocusable(true); 7654 } 7655 if (info.isFocused()) { 7656 structure.setFocused(true); 7657 } 7658 if (info.isAccessibilityFocused()) { 7659 structure.setAccessibilityFocused(true); 7660 } 7661 if (info.isSelected()) { 7662 structure.setSelected(true); 7663 } 7664 if (info.isLongClickable()) { 7665 structure.setLongClickable(true); 7666 } 7667 if (info.isCheckable()) { 7668 structure.setCheckable(true); 7669 if (info.isChecked()) { 7670 structure.setChecked(true); 7671 } 7672 } 7673 if (info.isContextClickable()) { 7674 structure.setContextClickable(true); 7675 } 7676 CharSequence cname = info.getClassName(); 7677 structure.setClassName(cname != null ? cname.toString() : null); 7678 structure.setContentDescription(info.getContentDescription()); 7679 if ((info.getText() != null || info.getError() != null)) { 7680 structure.setText(info.getText(), info.getTextSelectionStart(), 7681 info.getTextSelectionEnd()); 7682 } 7683 final int NCHILDREN = info.getChildCount(); 7684 if (NCHILDREN > 0) { 7685 structure.setChildCount(NCHILDREN); 7686 for (int i=0; i<NCHILDREN; i++) { 7687 AccessibilityNodeInfo cinfo = provider.createAccessibilityNodeInfo( 7688 AccessibilityNodeInfo.getVirtualDescendantId(info.getChildId(i))); 7689 ViewStructure child = structure.newChild(i); 7690 populateVirtualStructure(child, provider, cinfo); 7691 cinfo.recycle(); 7692 } 7693 } 7694 } 7695 7696 /** 7697 * Dispatch creation of {@link ViewStructure} down the hierarchy. The default 7698 * implementation calls {@link #onProvideStructure} and 7699 * {@link #onProvideVirtualStructure}. 7700 */ 7701 public void dispatchProvideStructure(ViewStructure structure) { 7702 dispatchProvideStructureForAssistOrAutofill(structure, false); 7703 } 7704 7705 /** 7706 * Dispatch creation of {@link ViewStructure} down the hierarchy. 7707 * 7708 * <p>The structure must be filled according to the request type, which is set in the 7709 * {@code flags} parameter - see the documentation on each flag for more details. 7710 * 7711 * <p>The default implementation calls {@link #onProvideAutofillStructure(ViewStructure, int)} 7712 * and {@link #onProvideAutofillVirtualStructure(ViewStructure, int)}. 7713 * 7714 * @param structure Fill in with structured view data. 7715 * @param flags optional flags (currently {@code 0}). 7716 */ 7717 public void dispatchProvideAutofillStructure(ViewStructure structure, int flags) { 7718 dispatchProvideStructureForAssistOrAutofill(structure, true); 7719 } 7720 7721 private void dispatchProvideStructureForAssistOrAutofill(ViewStructure structure, 7722 boolean forAutofill) { 7723 boolean blocked = forAutofill ? isAutofillBlocked() : isAssistBlocked(); 7724 if (!blocked) { 7725 if (forAutofill) { 7726 setAutofillId(structure); 7727 // NOTE: flags are not currently supported, hence 0 7728 onProvideAutofillStructure(structure, 0); 7729 onProvideAutofillVirtualStructure(structure, 0); 7730 } else { 7731 onProvideStructure(structure); 7732 onProvideVirtualStructure(structure); 7733 } 7734 } else { 7735 structure.setClassName(getAccessibilityClassName().toString()); 7736 structure.setAssistBlocked(true); 7737 } 7738 } 7739 7740 /** 7741 * @see #onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo) 7742 * 7743 * Note: Called from the default {@link AccessibilityDelegate}. 7744 * 7745 * @hide 7746 */ 7747 public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) { 7748 if (mAttachInfo == null) { 7749 return; 7750 } 7751 7752 Rect bounds = mAttachInfo.mTmpInvalRect; 7753 7754 getDrawingRect(bounds); 7755 info.setBoundsInParent(bounds); 7756 7757 getBoundsOnScreen(bounds, true); 7758 info.setBoundsInScreen(bounds); 7759 7760 ViewParent parent = getParentForAccessibility(); 7761 if (parent instanceof View) { 7762 info.setParent((View) parent); 7763 } 7764 7765 if (mID != View.NO_ID) { 7766 View rootView = getRootView(); 7767 if (rootView == null) { 7768 rootView = this; 7769 } 7770 7771 View label = rootView.findLabelForView(this, mID); 7772 if (label != null) { 7773 info.setLabeledBy(label); 7774 } 7775 7776 if ((mAttachInfo.mAccessibilityFetchFlags 7777 & AccessibilityNodeInfo.FLAG_REPORT_VIEW_IDS) != 0 7778 && Resources.resourceHasPackage(mID)) { 7779 try { 7780 String viewId = getResources().getResourceName(mID); 7781 info.setViewIdResourceName(viewId); 7782 } catch (Resources.NotFoundException nfe) { 7783 /* ignore */ 7784 } 7785 } 7786 } 7787 7788 if (mLabelForId != View.NO_ID) { 7789 View rootView = getRootView(); 7790 if (rootView == null) { 7791 rootView = this; 7792 } 7793 View labeled = rootView.findViewInsideOutShouldExist(this, mLabelForId); 7794 if (labeled != null) { 7795 info.setLabelFor(labeled); 7796 } 7797 } 7798 7799 if (mAccessibilityTraversalBeforeId != View.NO_ID) { 7800 View rootView = getRootView(); 7801 if (rootView == null) { 7802 rootView = this; 7803 } 7804 View next = rootView.findViewInsideOutShouldExist(this, 7805 mAccessibilityTraversalBeforeId); 7806 if (next != null && next.includeForAccessibility()) { 7807 info.setTraversalBefore(next); 7808 } 7809 } 7810 7811 if (mAccessibilityTraversalAfterId != View.NO_ID) { 7812 View rootView = getRootView(); 7813 if (rootView == null) { 7814 rootView = this; 7815 } 7816 View next = rootView.findViewInsideOutShouldExist(this, 7817 mAccessibilityTraversalAfterId); 7818 if (next != null && next.includeForAccessibility()) { 7819 info.setTraversalAfter(next); 7820 } 7821 } 7822 7823 info.setVisibleToUser(isVisibleToUser()); 7824 7825 info.setImportantForAccessibility(isImportantForAccessibility()); 7826 info.setPackageName(mContext.getPackageName()); 7827 info.setClassName(getAccessibilityClassName()); 7828 info.setContentDescription(getContentDescription()); 7829 7830 info.setEnabled(isEnabled()); 7831 info.setClickable(isClickable()); 7832 info.setFocusable(isFocusable()); 7833 info.setFocused(isFocused()); 7834 info.setAccessibilityFocused(isAccessibilityFocused()); 7835 info.setSelected(isSelected()); 7836 info.setLongClickable(isLongClickable()); 7837 info.setContextClickable(isContextClickable()); 7838 info.setLiveRegion(getAccessibilityLiveRegion()); 7839 7840 // TODO: These make sense only if we are in an AdapterView but all 7841 // views can be selected. Maybe from accessibility perspective 7842 // we should report as selectable view in an AdapterView. 7843 info.addAction(AccessibilityNodeInfo.ACTION_SELECT); 7844 info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_SELECTION); 7845 7846 if (isFocusable()) { 7847 if (isFocused()) { 7848 info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_FOCUS); 7849 } else { 7850 info.addAction(AccessibilityNodeInfo.ACTION_FOCUS); 7851 } 7852 } 7853 7854 if (!isAccessibilityFocused()) { 7855 info.addAction(AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS); 7856 } else { 7857 info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS); 7858 } 7859 7860 if (isClickable() && isEnabled()) { 7861 info.addAction(AccessibilityNodeInfo.ACTION_CLICK); 7862 } 7863 7864 if (isLongClickable() && isEnabled()) { 7865 info.addAction(AccessibilityNodeInfo.ACTION_LONG_CLICK); 7866 } 7867 7868 if (isContextClickable() && isEnabled()) { 7869 info.addAction(AccessibilityAction.ACTION_CONTEXT_CLICK); 7870 } 7871 7872 CharSequence text = getIterableTextForAccessibility(); 7873 if (text != null && text.length() > 0) { 7874 info.setTextSelection(getAccessibilitySelectionStart(), getAccessibilitySelectionEnd()); 7875 7876 info.addAction(AccessibilityNodeInfo.ACTION_SET_SELECTION); 7877 info.addAction(AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY); 7878 info.addAction(AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY); 7879 info.setMovementGranularities(AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER 7880 | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD 7881 | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH); 7882 } 7883 7884 info.addAction(AccessibilityAction.ACTION_SHOW_ON_SCREEN); 7885 populateAccessibilityNodeInfoDrawingOrderInParent(info); 7886 } 7887 7888 /** 7889 * Adds extra data to an {@link AccessibilityNodeInfo} based on an explicit request for the 7890 * additional data. 7891 * <p> 7892 * This method only needs overloading if the node is marked as having extra data available. 7893 * </p> 7894 * 7895 * @param info The info to which to add the extra data. Never {@code null}. 7896 * @param extraDataKey A key specifying the type of extra data to add to the info. The 7897 * extra data should be added to the {@link Bundle} returned by 7898 * the info's {@link AccessibilityNodeInfo#getExtras} method. Never 7899 * {@code null}. 7900 * @param arguments A {@link Bundle} holding any arguments relevant for this request. May be 7901 * {@code null} if the service provided no arguments. 7902 * 7903 * @see AccessibilityNodeInfo#setAvailableExtraData(List) 7904 */ 7905 public void addExtraDataToAccessibilityNodeInfo( 7906 @NonNull AccessibilityNodeInfo info, @NonNull String extraDataKey, 7907 @Nullable Bundle arguments) { 7908 } 7909 7910 /** 7911 * Determine the order in which this view will be drawn relative to its siblings for a11y 7912 * 7913 * @param info The info whose drawing order should be populated 7914 */ 7915 private void populateAccessibilityNodeInfoDrawingOrderInParent(AccessibilityNodeInfo info) { 7916 /* 7917 * If the view's bounds haven't been set yet, layout has not completed. In that situation, 7918 * drawing order may not be well-defined, and some Views with custom drawing order may 7919 * not be initialized sufficiently to respond properly getChildDrawingOrder. 7920 */ 7921 if ((mPrivateFlags & PFLAG_HAS_BOUNDS) == 0) { 7922 info.setDrawingOrder(0); 7923 return; 7924 } 7925 int drawingOrderInParent = 1; 7926 // Iterate up the hierarchy if parents are not important for a11y 7927 View viewAtDrawingLevel = this; 7928 final ViewParent parent = getParentForAccessibility(); 7929 while (viewAtDrawingLevel != parent) { 7930 final ViewParent currentParent = viewAtDrawingLevel.getParent(); 7931 if (!(currentParent instanceof ViewGroup)) { 7932 // Should only happen for the Decor 7933 drawingOrderInParent = 0; 7934 break; 7935 } else { 7936 final ViewGroup parentGroup = (ViewGroup) currentParent; 7937 final int childCount = parentGroup.getChildCount(); 7938 if (childCount > 1) { 7939 List<View> preorderedList = parentGroup.buildOrderedChildList(); 7940 if (preorderedList != null) { 7941 final int childDrawIndex = preorderedList.indexOf(viewAtDrawingLevel); 7942 for (int i = 0; i < childDrawIndex; i++) { 7943 drawingOrderInParent += numViewsForAccessibility(preorderedList.get(i)); 7944 } 7945 } else { 7946 final int childIndex = parentGroup.indexOfChild(viewAtDrawingLevel); 7947 final boolean customOrder = parentGroup.isChildrenDrawingOrderEnabled(); 7948 final int childDrawIndex = ((childIndex >= 0) && customOrder) ? parentGroup 7949 .getChildDrawingOrder(childCount, childIndex) : childIndex; 7950 final int numChildrenToIterate = customOrder ? childCount : childDrawIndex; 7951 if (childDrawIndex != 0) { 7952 for (int i = 0; i < numChildrenToIterate; i++) { 7953 final int otherDrawIndex = (customOrder ? 7954 parentGroup.getChildDrawingOrder(childCount, i) : i); 7955 if (otherDrawIndex < childDrawIndex) { 7956 drawingOrderInParent += 7957 numViewsForAccessibility(parentGroup.getChildAt(i)); 7958 } 7959 } 7960 } 7961 } 7962 } 7963 } 7964 viewAtDrawingLevel = (View) currentParent; 7965 } 7966 info.setDrawingOrder(drawingOrderInParent); 7967 } 7968 7969 private static int numViewsForAccessibility(View view) { 7970 if (view != null) { 7971 if (view.includeForAccessibility()) { 7972 return 1; 7973 } else if (view instanceof ViewGroup) { 7974 return ((ViewGroup) view).getNumChildrenForAccessibility(); 7975 } 7976 } 7977 return 0; 7978 } 7979 7980 private View findLabelForView(View view, int labeledId) { 7981 if (mMatchLabelForPredicate == null) { 7982 mMatchLabelForPredicate = new MatchLabelForPredicate(); 7983 } 7984 mMatchLabelForPredicate.mLabeledId = labeledId; 7985 return findViewByPredicateInsideOut(view, mMatchLabelForPredicate); 7986 } 7987 7988 /** 7989 * Computes whether this view is visible to the user. Such a view is 7990 * attached, visible, all its predecessors are visible, it is not clipped 7991 * entirely by its predecessors, and has an alpha greater than zero. 7992 * 7993 * @return Whether the view is visible on the screen. 7994 * 7995 * @hide 7996 */ 7997 protected boolean isVisibleToUser() { 7998 return isVisibleToUser(null); 7999 } 8000 8001 /** 8002 * Computes whether the given portion of this view is visible to the user. 8003 * Such a view is attached, visible, all its predecessors are visible, 8004 * has an alpha greater than zero, and the specified portion is not 8005 * clipped entirely by its predecessors. 8006 * 8007 * @param boundInView the portion of the view to test; coordinates should be relative; may be 8008 * <code>null</code>, and the entire view will be tested in this case. 8009 * When <code>true</code> is returned by the function, the actual visible 8010 * region will be stored in this parameter; that is, if boundInView is fully 8011 * contained within the view, no modification will be made, otherwise regions 8012 * outside of the visible area of the view will be clipped. 8013 * 8014 * @return Whether the specified portion of the view is visible on the screen. 8015 * 8016 * @hide 8017 */ 8018 protected boolean isVisibleToUser(Rect boundInView) { 8019 if (mAttachInfo != null) { 8020 // Attached to invisible window means this view is not visible. 8021 if (mAttachInfo.mWindowVisibility != View.VISIBLE) { 8022 return false; 8023 } 8024 // An invisible predecessor or one with alpha zero means 8025 // that this view is not visible to the user. 8026 Object current = this; 8027 while (current instanceof View) { 8028 View view = (View) current; 8029 // We have attach info so this view is attached and there is no 8030 // need to check whether we reach to ViewRootImpl on the way up. 8031 if (view.getAlpha() <= 0 || view.getTransitionAlpha() <= 0 || 8032 view.getVisibility() != VISIBLE) { 8033 return false; 8034 } 8035 current = view.mParent; 8036 } 8037 // Check if the view is entirely covered by its predecessors. 8038 Rect visibleRect = mAttachInfo.mTmpInvalRect; 8039 Point offset = mAttachInfo.mPoint; 8040 if (!getGlobalVisibleRect(visibleRect, offset)) { 8041 return false; 8042 } 8043 // Check if the visible portion intersects the rectangle of interest. 8044 if (boundInView != null) { 8045 visibleRect.offset(-offset.x, -offset.y); 8046 return boundInView.intersect(visibleRect); 8047 } 8048 return true; 8049 } 8050 return false; 8051 } 8052 8053 /** 8054 * Returns the delegate for implementing accessibility support via 8055 * composition. For more details see {@link AccessibilityDelegate}. 8056 * 8057 * @return The delegate, or null if none set. 8058 * 8059 * @hide 8060 */ 8061 public AccessibilityDelegate getAccessibilityDelegate() { 8062 return mAccessibilityDelegate; 8063 } 8064 8065 /** 8066 * Sets a delegate for implementing accessibility support via composition 8067 * (as opposed to inheritance). For more details, see 8068 * {@link AccessibilityDelegate}. 8069 * <p> 8070 * <strong>Note:</strong> On platform versions prior to 8071 * {@link android.os.Build.VERSION_CODES#M API 23}, delegate methods on 8072 * views in the {@code android.widget.*} package are called <i>before</i> 8073 * host methods. This prevents certain properties such as class name from 8074 * being modified by overriding 8075 * {@link AccessibilityDelegate#onInitializeAccessibilityNodeInfo(View, AccessibilityNodeInfo)}, 8076 * as any changes will be overwritten by the host class. 8077 * <p> 8078 * Starting in {@link android.os.Build.VERSION_CODES#M API 23}, delegate 8079 * methods are called <i>after</i> host methods, which all properties to be 8080 * modified without being overwritten by the host class. 8081 * 8082 * @param delegate the object to which accessibility method calls should be 8083 * delegated 8084 * @see AccessibilityDelegate 8085 */ 8086 public void setAccessibilityDelegate(@Nullable AccessibilityDelegate delegate) { 8087 mAccessibilityDelegate = delegate; 8088 } 8089 8090 /** 8091 * Gets the provider for managing a virtual view hierarchy rooted at this View 8092 * and reported to {@link android.accessibilityservice.AccessibilityService}s 8093 * that explore the window content. 8094 * <p> 8095 * If this method returns an instance, this instance is responsible for managing 8096 * {@link AccessibilityNodeInfo}s describing the virtual sub-tree rooted at this 8097 * View including the one representing the View itself. Similarly the returned 8098 * instance is responsible for performing accessibility actions on any virtual 8099 * view or the root view itself. 8100 * </p> 8101 * <p> 8102 * If an {@link AccessibilityDelegate} has been specified via calling 8103 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 8104 * {@link AccessibilityDelegate#getAccessibilityNodeProvider(View)} 8105 * is responsible for handling this call. 8106 * </p> 8107 * 8108 * @return The provider. 8109 * 8110 * @see AccessibilityNodeProvider 8111 */ 8112 public AccessibilityNodeProvider getAccessibilityNodeProvider() { 8113 if (mAccessibilityDelegate != null) { 8114 return mAccessibilityDelegate.getAccessibilityNodeProvider(this); 8115 } else { 8116 return null; 8117 } 8118 } 8119 8120 /** 8121 * Gets the unique identifier of this view on the screen for accessibility purposes. 8122 * 8123 * @return The view accessibility id. 8124 * 8125 * @hide 8126 */ 8127 public int getAccessibilityViewId() { 8128 if (mAccessibilityViewId == NO_ID) { 8129 mAccessibilityViewId = mContext.getNextAccessibilityId(); 8130 } 8131 return mAccessibilityViewId; 8132 } 8133 8134 /** 8135 * Gets the unique identifier of the window in which this View reseides. 8136 * 8137 * @return The window accessibility id. 8138 * 8139 * @hide 8140 */ 8141 public int getAccessibilityWindowId() { 8142 return mAttachInfo != null ? mAttachInfo.mAccessibilityWindowId 8143 : AccessibilityWindowInfo.UNDEFINED_WINDOW_ID; 8144 } 8145 8146 /** 8147 * Returns the {@link View}'s content description. 8148 * <p> 8149 * <strong>Note:</strong> Do not override this method, as it will have no 8150 * effect on the content description presented to accessibility services. 8151 * You must call {@link #setContentDescription(CharSequence)} to modify the 8152 * content description. 8153 * 8154 * @return the content description 8155 * @see #setContentDescription(CharSequence) 8156 * @attr ref android.R.styleable#View_contentDescription 8157 */ 8158 @ViewDebug.ExportedProperty(category = "accessibility") 8159 public CharSequence getContentDescription() { 8160 return mContentDescription; 8161 } 8162 8163 /** 8164 * Sets the {@link View}'s content description. 8165 * <p> 8166 * A content description briefly describes the view and is primarily used 8167 * for accessibility support to determine how a view should be presented to 8168 * the user. In the case of a view with no textual representation, such as 8169 * {@link android.widget.ImageButton}, a useful content description 8170 * explains what the view does. For example, an image button with a phone 8171 * icon that is used to place a call may use "Call" as its content 8172 * description. An image of a floppy disk that is used to save a file may 8173 * use "Save". 8174 * 8175 * @param contentDescription The content description. 8176 * @see #getContentDescription() 8177 * @attr ref android.R.styleable#View_contentDescription 8178 */ 8179 @RemotableViewMethod 8180 public void setContentDescription(CharSequence contentDescription) { 8181 if (mContentDescription == null) { 8182 if (contentDescription == null) { 8183 return; 8184 } 8185 } else if (mContentDescription.equals(contentDescription)) { 8186 return; 8187 } 8188 mContentDescription = contentDescription; 8189 final boolean nonEmptyDesc = contentDescription != null && contentDescription.length() > 0; 8190 if (nonEmptyDesc && getImportantForAccessibility() == IMPORTANT_FOR_ACCESSIBILITY_AUTO) { 8191 setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES); 8192 notifySubtreeAccessibilityStateChangedIfNeeded(); 8193 } else { 8194 notifyViewAccessibilityStateChangedIfNeeded( 8195 AccessibilityEvent.CONTENT_CHANGE_TYPE_CONTENT_DESCRIPTION); 8196 } 8197 } 8198 8199 /** 8200 * Sets the id of a view before which this one is visited in accessibility traversal. 8201 * A screen-reader must visit the content of this view before the content of the one 8202 * it precedes. For example, if view B is set to be before view A, then a screen-reader 8203 * will traverse the entire content of B before traversing the entire content of A, 8204 * regardles of what traversal strategy it is using. 8205 * <p> 8206 * Views that do not have specified before/after relationships are traversed in order 8207 * determined by the screen-reader. 8208 * </p> 8209 * <p> 8210 * Setting that this view is before a view that is not important for accessibility 8211 * or if this view is not important for accessibility will have no effect as the 8212 * screen-reader is not aware of unimportant views. 8213 * </p> 8214 * 8215 * @param beforeId The id of a view this one precedes in accessibility traversal. 8216 * 8217 * @attr ref android.R.styleable#View_accessibilityTraversalBefore 8218 * 8219 * @see #setImportantForAccessibility(int) 8220 */ 8221 @RemotableViewMethod 8222 public void setAccessibilityTraversalBefore(int beforeId) { 8223 if (mAccessibilityTraversalBeforeId == beforeId) { 8224 return; 8225 } 8226 mAccessibilityTraversalBeforeId = beforeId; 8227 notifyViewAccessibilityStateChangedIfNeeded( 8228 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 8229 } 8230 8231 /** 8232 * Gets the id of a view before which this one is visited in accessibility traversal. 8233 * 8234 * @return The id of a view this one precedes in accessibility traversal if 8235 * specified, otherwise {@link #NO_ID}. 8236 * 8237 * @see #setAccessibilityTraversalBefore(int) 8238 */ 8239 public int getAccessibilityTraversalBefore() { 8240 return mAccessibilityTraversalBeforeId; 8241 } 8242 8243 /** 8244 * Sets the id of a view after which this one is visited in accessibility traversal. 8245 * A screen-reader must visit the content of the other view before the content of this 8246 * one. For example, if view B is set to be after view A, then a screen-reader 8247 * will traverse the entire content of A before traversing the entire content of B, 8248 * regardles of what traversal strategy it is using. 8249 * <p> 8250 * Views that do not have specified before/after relationships are traversed in order 8251 * determined by the screen-reader. 8252 * </p> 8253 * <p> 8254 * Setting that this view is after a view that is not important for accessibility 8255 * or if this view is not important for accessibility will have no effect as the 8256 * screen-reader is not aware of unimportant views. 8257 * </p> 8258 * 8259 * @param afterId The id of a view this one succedees in accessibility traversal. 8260 * 8261 * @attr ref android.R.styleable#View_accessibilityTraversalAfter 8262 * 8263 * @see #setImportantForAccessibility(int) 8264 */ 8265 @RemotableViewMethod 8266 public void setAccessibilityTraversalAfter(int afterId) { 8267 if (mAccessibilityTraversalAfterId == afterId) { 8268 return; 8269 } 8270 mAccessibilityTraversalAfterId = afterId; 8271 notifyViewAccessibilityStateChangedIfNeeded( 8272 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 8273 } 8274 8275 /** 8276 * Gets the id of a view after which this one is visited in accessibility traversal. 8277 * 8278 * @return The id of a view this one succeedes in accessibility traversal if 8279 * specified, otherwise {@link #NO_ID}. 8280 * 8281 * @see #setAccessibilityTraversalAfter(int) 8282 */ 8283 public int getAccessibilityTraversalAfter() { 8284 return mAccessibilityTraversalAfterId; 8285 } 8286 8287 /** 8288 * Gets the id of a view for which this view serves as a label for 8289 * accessibility purposes. 8290 * 8291 * @return The labeled view id. 8292 */ 8293 @ViewDebug.ExportedProperty(category = "accessibility") 8294 public int getLabelFor() { 8295 return mLabelForId; 8296 } 8297 8298 /** 8299 * Sets the id of a view for which this view serves as a label for 8300 * accessibility purposes. 8301 * 8302 * @param id The labeled view id. 8303 */ 8304 @RemotableViewMethod 8305 public void setLabelFor(@IdRes int id) { 8306 if (mLabelForId == id) { 8307 return; 8308 } 8309 mLabelForId = id; 8310 if (mLabelForId != View.NO_ID 8311 && mID == View.NO_ID) { 8312 mID = generateViewId(); 8313 } 8314 notifyViewAccessibilityStateChangedIfNeeded( 8315 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 8316 } 8317 8318 /** 8319 * Invoked whenever this view loses focus, either by losing window focus or by losing 8320 * focus within its window. This method can be used to clear any state tied to the 8321 * focus. For instance, if a button is held pressed with the trackball and the window 8322 * loses focus, this method can be used to cancel the press. 8323 * 8324 * Subclasses of View overriding this method should always call super.onFocusLost(). 8325 * 8326 * @see #onFocusChanged(boolean, int, android.graphics.Rect) 8327 * @see #onWindowFocusChanged(boolean) 8328 * 8329 * @hide pending API council approval 8330 */ 8331 @CallSuper 8332 protected void onFocusLost() { 8333 resetPressedState(); 8334 } 8335 8336 private void resetPressedState() { 8337 if ((mViewFlags & ENABLED_MASK) == DISABLED) { 8338 return; 8339 } 8340 8341 if (isPressed()) { 8342 setPressed(false); 8343 8344 if (!mHasPerformedLongPress) { 8345 removeLongPressCallback(); 8346 } 8347 } 8348 } 8349 8350 /** 8351 * Returns true if this view has focus 8352 * 8353 * @return True if this view has focus, false otherwise. 8354 */ 8355 @ViewDebug.ExportedProperty(category = "focus") 8356 public boolean isFocused() { 8357 return (mPrivateFlags & PFLAG_FOCUSED) != 0; 8358 } 8359 8360 /** 8361 * Find the view in the hierarchy rooted at this view that currently has 8362 * focus. 8363 * 8364 * @return The view that currently has focus, or null if no focused view can 8365 * be found. 8366 */ 8367 public View findFocus() { 8368 return (mPrivateFlags & PFLAG_FOCUSED) != 0 ? this : null; 8369 } 8370 8371 /** 8372 * Indicates whether this view is one of the set of scrollable containers in 8373 * its window. 8374 * 8375 * @return whether this view is one of the set of scrollable containers in 8376 * its window 8377 * 8378 * @attr ref android.R.styleable#View_isScrollContainer 8379 */ 8380 public boolean isScrollContainer() { 8381 return (mPrivateFlags & PFLAG_SCROLL_CONTAINER_ADDED) != 0; 8382 } 8383 8384 /** 8385 * Change whether this view is one of the set of scrollable containers in 8386 * its window. This will be used to determine whether the window can 8387 * resize or must pan when a soft input area is open -- scrollable 8388 * containers allow the window to use resize mode since the container 8389 * will appropriately shrink. 8390 * 8391 * @attr ref android.R.styleable#View_isScrollContainer 8392 */ 8393 public void setScrollContainer(boolean isScrollContainer) { 8394 if (isScrollContainer) { 8395 if (mAttachInfo != null && (mPrivateFlags&PFLAG_SCROLL_CONTAINER_ADDED) == 0) { 8396 mAttachInfo.mScrollContainers.add(this); 8397 mPrivateFlags |= PFLAG_SCROLL_CONTAINER_ADDED; 8398 } 8399 mPrivateFlags |= PFLAG_SCROLL_CONTAINER; 8400 } else { 8401 if ((mPrivateFlags&PFLAG_SCROLL_CONTAINER_ADDED) != 0) { 8402 mAttachInfo.mScrollContainers.remove(this); 8403 } 8404 mPrivateFlags &= ~(PFLAG_SCROLL_CONTAINER|PFLAG_SCROLL_CONTAINER_ADDED); 8405 } 8406 } 8407 8408 /** 8409 * Returns the quality of the drawing cache. 8410 * 8411 * @return One of {@link #DRAWING_CACHE_QUALITY_AUTO}, 8412 * {@link #DRAWING_CACHE_QUALITY_LOW}, or {@link #DRAWING_CACHE_QUALITY_HIGH} 8413 * 8414 * @see #setDrawingCacheQuality(int) 8415 * @see #setDrawingCacheEnabled(boolean) 8416 * @see #isDrawingCacheEnabled() 8417 * 8418 * @attr ref android.R.styleable#View_drawingCacheQuality 8419 */ 8420 @DrawingCacheQuality 8421 public int getDrawingCacheQuality() { 8422 return mViewFlags & DRAWING_CACHE_QUALITY_MASK; 8423 } 8424 8425 /** 8426 * Set the drawing cache quality of this view. This value is used only when the 8427 * drawing cache is enabled 8428 * 8429 * @param quality One of {@link #DRAWING_CACHE_QUALITY_AUTO}, 8430 * {@link #DRAWING_CACHE_QUALITY_LOW}, or {@link #DRAWING_CACHE_QUALITY_HIGH} 8431 * 8432 * @see #getDrawingCacheQuality() 8433 * @see #setDrawingCacheEnabled(boolean) 8434 * @see #isDrawingCacheEnabled() 8435 * 8436 * @attr ref android.R.styleable#View_drawingCacheQuality 8437 */ 8438 public void setDrawingCacheQuality(@DrawingCacheQuality int quality) { 8439 setFlags(quality, DRAWING_CACHE_QUALITY_MASK); 8440 } 8441 8442 /** 8443 * Returns whether the screen should remain on, corresponding to the current 8444 * value of {@link #KEEP_SCREEN_ON}. 8445 * 8446 * @return Returns true if {@link #KEEP_SCREEN_ON} is set. 8447 * 8448 * @see #setKeepScreenOn(boolean) 8449 * 8450 * @attr ref android.R.styleable#View_keepScreenOn 8451 */ 8452 public boolean getKeepScreenOn() { 8453 return (mViewFlags & KEEP_SCREEN_ON) != 0; 8454 } 8455 8456 /** 8457 * Controls whether the screen should remain on, modifying the 8458 * value of {@link #KEEP_SCREEN_ON}. 8459 * 8460 * @param keepScreenOn Supply true to set {@link #KEEP_SCREEN_ON}. 8461 * 8462 * @see #getKeepScreenOn() 8463 * 8464 * @attr ref android.R.styleable#View_keepScreenOn 8465 */ 8466 public void setKeepScreenOn(boolean keepScreenOn) { 8467 setFlags(keepScreenOn ? KEEP_SCREEN_ON : 0, KEEP_SCREEN_ON); 8468 } 8469 8470 /** 8471 * Gets the id of the view to use when the next focus is {@link #FOCUS_LEFT}. 8472 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically. 8473 * 8474 * @attr ref android.R.styleable#View_nextFocusLeft 8475 */ 8476 public int getNextFocusLeftId() { 8477 return mNextFocusLeftId; 8478 } 8479 8480 /** 8481 * Sets the id of the view to use when the next focus is {@link #FOCUS_LEFT}. 8482 * @param nextFocusLeftId The next focus ID, or {@link #NO_ID} if the framework should 8483 * decide automatically. 8484 * 8485 * @attr ref android.R.styleable#View_nextFocusLeft 8486 */ 8487 public void setNextFocusLeftId(int nextFocusLeftId) { 8488 mNextFocusLeftId = nextFocusLeftId; 8489 } 8490 8491 /** 8492 * Gets the id of the view to use when the next focus is {@link #FOCUS_RIGHT}. 8493 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically. 8494 * 8495 * @attr ref android.R.styleable#View_nextFocusRight 8496 */ 8497 public int getNextFocusRightId() { 8498 return mNextFocusRightId; 8499 } 8500 8501 /** 8502 * Sets the id of the view to use when the next focus is {@link #FOCUS_RIGHT}. 8503 * @param nextFocusRightId The next focus ID, or {@link #NO_ID} if the framework should 8504 * decide automatically. 8505 * 8506 * @attr ref android.R.styleable#View_nextFocusRight 8507 */ 8508 public void setNextFocusRightId(int nextFocusRightId) { 8509 mNextFocusRightId = nextFocusRightId; 8510 } 8511 8512 /** 8513 * Gets the id of the view to use when the next focus is {@link #FOCUS_UP}. 8514 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically. 8515 * 8516 * @attr ref android.R.styleable#View_nextFocusUp 8517 */ 8518 public int getNextFocusUpId() { 8519 return mNextFocusUpId; 8520 } 8521 8522 /** 8523 * Sets the id of the view to use when the next focus is {@link #FOCUS_UP}. 8524 * @param nextFocusUpId The next focus ID, or {@link #NO_ID} if the framework should 8525 * decide automatically. 8526 * 8527 * @attr ref android.R.styleable#View_nextFocusUp 8528 */ 8529 public void setNextFocusUpId(int nextFocusUpId) { 8530 mNextFocusUpId = nextFocusUpId; 8531 } 8532 8533 /** 8534 * Gets the id of the view to use when the next focus is {@link #FOCUS_DOWN}. 8535 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically. 8536 * 8537 * @attr ref android.R.styleable#View_nextFocusDown 8538 */ 8539 public int getNextFocusDownId() { 8540 return mNextFocusDownId; 8541 } 8542 8543 /** 8544 * Sets the id of the view to use when the next focus is {@link #FOCUS_DOWN}. 8545 * @param nextFocusDownId The next focus ID, or {@link #NO_ID} if the framework should 8546 * decide automatically. 8547 * 8548 * @attr ref android.R.styleable#View_nextFocusDown 8549 */ 8550 public void setNextFocusDownId(int nextFocusDownId) { 8551 mNextFocusDownId = nextFocusDownId; 8552 } 8553 8554 /** 8555 * Gets the id of the view to use when the next focus is {@link #FOCUS_FORWARD}. 8556 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically. 8557 * 8558 * @attr ref android.R.styleable#View_nextFocusForward 8559 */ 8560 public int getNextFocusForwardId() { 8561 return mNextFocusForwardId; 8562 } 8563 8564 /** 8565 * Sets the id of the view to use when the next focus is {@link #FOCUS_FORWARD}. 8566 * @param nextFocusForwardId The next focus ID, or {@link #NO_ID} if the framework should 8567 * decide automatically. 8568 * 8569 * @attr ref android.R.styleable#View_nextFocusForward 8570 */ 8571 public void setNextFocusForwardId(int nextFocusForwardId) { 8572 mNextFocusForwardId = nextFocusForwardId; 8573 } 8574 8575 /** 8576 * Gets the id of the root of the next keyboard navigation cluster. 8577 * @return The next keyboard navigation cluster ID, or {@link #NO_ID} if the framework should 8578 * decide automatically. 8579 * 8580 * @attr ref android.R.styleable#View_nextClusterForward 8581 */ 8582 public int getNextClusterForwardId() { 8583 return mNextClusterForwardId; 8584 } 8585 8586 /** 8587 * Sets the id of the view to use as the root of the next keyboard navigation cluster. 8588 * @param nextClusterForwardId The next cluster ID, or {@link #NO_ID} if the framework should 8589 * decide automatically. 8590 * 8591 * @attr ref android.R.styleable#View_nextClusterForward 8592 */ 8593 public void setNextClusterForwardId(int nextClusterForwardId) { 8594 mNextClusterForwardId = nextClusterForwardId; 8595 } 8596 8597 /** 8598 * Returns the visibility of this view and all of its ancestors 8599 * 8600 * @return True if this view and all of its ancestors are {@link #VISIBLE} 8601 */ 8602 public boolean isShown() { 8603 View current = this; 8604 //noinspection ConstantConditions 8605 do { 8606 if ((current.mViewFlags & VISIBILITY_MASK) != VISIBLE) { 8607 return false; 8608 } 8609 ViewParent parent = current.mParent; 8610 if (parent == null) { 8611 return false; // We are not attached to the view root 8612 } 8613 if (!(parent instanceof View)) { 8614 return true; 8615 } 8616 current = (View) parent; 8617 } while (current != null); 8618 8619 return false; 8620 } 8621 8622 /** 8623 * Called by the view hierarchy when the content insets for a window have 8624 * changed, to allow it to adjust its content to fit within those windows. 8625 * The content insets tell you the space that the status bar, input method, 8626 * and other system windows infringe on the application's window. 8627 * 8628 * <p>You do not normally need to deal with this function, since the default 8629 * window decoration given to applications takes care of applying it to the 8630 * content of the window. If you use {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN} 8631 * or {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION} this will not be the case, 8632 * and your content can be placed under those system elements. You can then 8633 * use this method within your view hierarchy if you have parts of your UI 8634 * which you would like to ensure are not being covered. 8635 * 8636 * <p>The default implementation of this method simply applies the content 8637 * insets to the view's padding, consuming that content (modifying the 8638 * insets to be 0), and returning true. This behavior is off by default, but can 8639 * be enabled through {@link #setFitsSystemWindows(boolean)}. 8640 * 8641 * <p>This function's traversal down the hierarchy is depth-first. The same content 8642 * insets object is propagated down the hierarchy, so any changes made to it will 8643 * be seen by all following views (including potentially ones above in 8644 * the hierarchy since this is a depth-first traversal). The first view 8645 * that returns true will abort the entire traversal. 8646 * 8647 * <p>The default implementation works well for a situation where it is 8648 * used with a container that covers the entire window, allowing it to 8649 * apply the appropriate insets to its content on all edges. If you need 8650 * a more complicated layout (such as two different views fitting system 8651 * windows, one on the top of the window, and one on the bottom), 8652 * you can override the method and handle the insets however you would like. 8653 * Note that the insets provided by the framework are always relative to the 8654 * far edges of the window, not accounting for the location of the called view 8655 * within that window. (In fact when this method is called you do not yet know 8656 * where the layout will place the view, as it is done before layout happens.) 8657 * 8658 * <p>Note: unlike many View methods, there is no dispatch phase to this 8659 * call. If you are overriding it in a ViewGroup and want to allow the 8660 * call to continue to your children, you must be sure to call the super 8661 * implementation. 8662 * 8663 * <p>Here is a sample layout that makes use of fitting system windows 8664 * to have controls for a video view placed inside of the window decorations 8665 * that it hides and shows. This can be used with code like the second 8666 * sample (video player) shown in {@link #setSystemUiVisibility(int)}. 8667 * 8668 * {@sample development/samples/ApiDemos/res/layout/video_player.xml complete} 8669 * 8670 * @param insets Current content insets of the window. Prior to 8671 * {@link android.os.Build.VERSION_CODES#JELLY_BEAN} you must not modify 8672 * the insets or else you and Android will be unhappy. 8673 * 8674 * @return {@code true} if this view applied the insets and it should not 8675 * continue propagating further down the hierarchy, {@code false} otherwise. 8676 * @see #getFitsSystemWindows() 8677 * @see #setFitsSystemWindows(boolean) 8678 * @see #setSystemUiVisibility(int) 8679 * 8680 * @deprecated As of API 20 use {@link #dispatchApplyWindowInsets(WindowInsets)} to apply 8681 * insets to views. Views should override {@link #onApplyWindowInsets(WindowInsets)} or use 8682 * {@link #setOnApplyWindowInsetsListener(android.view.View.OnApplyWindowInsetsListener)} 8683 * to implement handling their own insets. 8684 */ 8685 @Deprecated 8686 protected boolean fitSystemWindows(Rect insets) { 8687 if ((mPrivateFlags3 & PFLAG3_APPLYING_INSETS) == 0) { 8688 if (insets == null) { 8689 // Null insets by definition have already been consumed. 8690 // This call cannot apply insets since there are none to apply, 8691 // so return false. 8692 return false; 8693 } 8694 // If we're not in the process of dispatching the newer apply insets call, 8695 // that means we're not in the compatibility path. Dispatch into the newer 8696 // apply insets path and take things from there. 8697 try { 8698 mPrivateFlags3 |= PFLAG3_FITTING_SYSTEM_WINDOWS; 8699 return dispatchApplyWindowInsets(new WindowInsets(insets)).isConsumed(); 8700 } finally { 8701 mPrivateFlags3 &= ~PFLAG3_FITTING_SYSTEM_WINDOWS; 8702 } 8703 } else { 8704 // We're being called from the newer apply insets path. 8705 // Perform the standard fallback behavior. 8706 return fitSystemWindowsInt(insets); 8707 } 8708 } 8709 8710 private boolean fitSystemWindowsInt(Rect insets) { 8711 if ((mViewFlags & FITS_SYSTEM_WINDOWS) == FITS_SYSTEM_WINDOWS) { 8712 mUserPaddingStart = UNDEFINED_PADDING; 8713 mUserPaddingEnd = UNDEFINED_PADDING; 8714 Rect localInsets = sThreadLocal.get(); 8715 if (localInsets == null) { 8716 localInsets = new Rect(); 8717 sThreadLocal.set(localInsets); 8718 } 8719 boolean res = computeFitSystemWindows(insets, localInsets); 8720 mUserPaddingLeftInitial = localInsets.left; 8721 mUserPaddingRightInitial = localInsets.right; 8722 internalSetPadding(localInsets.left, localInsets.top, 8723 localInsets.right, localInsets.bottom); 8724 return res; 8725 } 8726 return false; 8727 } 8728 8729 /** 8730 * Called when the view should apply {@link WindowInsets} according to its internal policy. 8731 * 8732 * <p>This method should be overridden by views that wish to apply a policy different from or 8733 * in addition to the default behavior. Clients that wish to force a view subtree 8734 * to apply insets should call {@link #dispatchApplyWindowInsets(WindowInsets)}.</p> 8735 * 8736 * <p>Clients may supply an {@link OnApplyWindowInsetsListener} to a view. If one is set 8737 * it will be called during dispatch instead of this method. The listener may optionally 8738 * call this method from its own implementation if it wishes to apply the view's default 8739 * insets policy in addition to its own.</p> 8740 * 8741 * <p>Implementations of this method should either return the insets parameter unchanged 8742 * or a new {@link WindowInsets} cloned from the supplied insets with any insets consumed 8743 * that this view applied itself. This allows new inset types added in future platform 8744 * versions to pass through existing implementations unchanged without being erroneously 8745 * consumed.</p> 8746 * 8747 * <p>By default if a view's {@link #setFitsSystemWindows(boolean) fitsSystemWindows} 8748 * property is set then the view will consume the system window insets and apply them 8749 * as padding for the view.</p> 8750 * 8751 * @param insets Insets to apply 8752 * @return The supplied insets with any applied insets consumed 8753 */ 8754 public WindowInsets onApplyWindowInsets(WindowInsets insets) { 8755 if ((mPrivateFlags3 & PFLAG3_FITTING_SYSTEM_WINDOWS) == 0) { 8756 // We weren't called from within a direct call to fitSystemWindows, 8757 // call into it as a fallback in case we're in a class that overrides it 8758 // and has logic to perform. 8759 if (fitSystemWindows(insets.getSystemWindowInsets())) { 8760 return insets.consumeSystemWindowInsets(); 8761 } 8762 } else { 8763 // We were called from within a direct call to fitSystemWindows. 8764 if (fitSystemWindowsInt(insets.getSystemWindowInsets())) { 8765 return insets.consumeSystemWindowInsets(); 8766 } 8767 } 8768 return insets; 8769 } 8770 8771 /** 8772 * Set an {@link OnApplyWindowInsetsListener} to take over the policy for applying 8773 * window insets to this view. The listener's 8774 * {@link OnApplyWindowInsetsListener#onApplyWindowInsets(View, WindowInsets) onApplyWindowInsets} 8775 * method will be called instead of the view's 8776 * {@link #onApplyWindowInsets(WindowInsets) onApplyWindowInsets} method. 8777 * 8778 * @param listener Listener to set 8779 * 8780 * @see #onApplyWindowInsets(WindowInsets) 8781 */ 8782 public void setOnApplyWindowInsetsListener(OnApplyWindowInsetsListener listener) { 8783 getListenerInfo().mOnApplyWindowInsetsListener = listener; 8784 } 8785 8786 /** 8787 * Request to apply the given window insets to this view or another view in its subtree. 8788 * 8789 * <p>This method should be called by clients wishing to apply insets corresponding to areas 8790 * obscured by window decorations or overlays. This can include the status and navigation bars, 8791 * action bars, input methods and more. New inset categories may be added in the future. 8792 * The method returns the insets provided minus any that were applied by this view or its 8793 * children.</p> 8794 * 8795 * <p>Clients wishing to provide custom behavior should override the 8796 * {@link #onApplyWindowInsets(WindowInsets)} method or alternatively provide a 8797 * {@link OnApplyWindowInsetsListener} via the 8798 * {@link #setOnApplyWindowInsetsListener(View.OnApplyWindowInsetsListener) setOnApplyWindowInsetsListener} 8799 * method.</p> 8800 * 8801 * <p>This method replaces the older {@link #fitSystemWindows(Rect) fitSystemWindows} method. 8802 * </p> 8803 * 8804 * @param insets Insets to apply 8805 * @return The provided insets minus the insets that were consumed 8806 */ 8807 public WindowInsets dispatchApplyWindowInsets(WindowInsets insets) { 8808 try { 8809 mPrivateFlags3 |= PFLAG3_APPLYING_INSETS; 8810 if (mListenerInfo != null && mListenerInfo.mOnApplyWindowInsetsListener != null) { 8811 return mListenerInfo.mOnApplyWindowInsetsListener.onApplyWindowInsets(this, insets); 8812 } else { 8813 return onApplyWindowInsets(insets); 8814 } 8815 } finally { 8816 mPrivateFlags3 &= ~PFLAG3_APPLYING_INSETS; 8817 } 8818 } 8819 8820 /** 8821 * Compute the view's coordinate within the surface. 8822 * 8823 * <p>Computes the coordinates of this view in its surface. The argument 8824 * must be an array of two integers. After the method returns, the array 8825 * contains the x and y location in that order.</p> 8826 * @hide 8827 * @param location an array of two integers in which to hold the coordinates 8828 */ 8829 public void getLocationInSurface(@Size(2) int[] location) { 8830 getLocationInWindow(location); 8831 if (mAttachInfo != null && mAttachInfo.mViewRootImpl != null) { 8832 location[0] += mAttachInfo.mViewRootImpl.mWindowAttributes.surfaceInsets.left; 8833 location[1] += mAttachInfo.mViewRootImpl.mWindowAttributes.surfaceInsets.top; 8834 } 8835 } 8836 8837 /** 8838 * Provide original WindowInsets that are dispatched to the view hierarchy. The insets are 8839 * only available if the view is attached. 8840 * 8841 * @return WindowInsets from the top of the view hierarchy or null if View is detached 8842 */ 8843 public WindowInsets getRootWindowInsets() { 8844 if (mAttachInfo != null) { 8845 return mAttachInfo.mViewRootImpl.getWindowInsets(false /* forceConstruct */); 8846 } 8847 return null; 8848 } 8849 8850 /** 8851 * @hide Compute the insets that should be consumed by this view and the ones 8852 * that should propagate to those under it. 8853 */ 8854 protected boolean computeFitSystemWindows(Rect inoutInsets, Rect outLocalInsets) { 8855 if ((mViewFlags & OPTIONAL_FITS_SYSTEM_WINDOWS) == 0 8856 || mAttachInfo == null 8857 || ((mAttachInfo.mSystemUiVisibility & SYSTEM_UI_LAYOUT_FLAGS) == 0 8858 && !mAttachInfo.mOverscanRequested)) { 8859 outLocalInsets.set(inoutInsets); 8860 inoutInsets.set(0, 0, 0, 0); 8861 return true; 8862 } else { 8863 // The application wants to take care of fitting system window for 8864 // the content... however we still need to take care of any overscan here. 8865 final Rect overscan = mAttachInfo.mOverscanInsets; 8866 outLocalInsets.set(overscan); 8867 inoutInsets.left -= overscan.left; 8868 inoutInsets.top -= overscan.top; 8869 inoutInsets.right -= overscan.right; 8870 inoutInsets.bottom -= overscan.bottom; 8871 return false; 8872 } 8873 } 8874 8875 /** 8876 * Compute insets that should be consumed by this view and the ones that should propagate 8877 * to those under it. 8878 * 8879 * @param in Insets currently being processed by this View, likely received as a parameter 8880 * to {@link #onApplyWindowInsets(WindowInsets)}. 8881 * @param outLocalInsets A Rect that will receive the insets that should be consumed 8882 * by this view 8883 * @return Insets that should be passed along to views under this one 8884 */ 8885 public WindowInsets computeSystemWindowInsets(WindowInsets in, Rect outLocalInsets) { 8886 if ((mViewFlags & OPTIONAL_FITS_SYSTEM_WINDOWS) == 0 8887 || mAttachInfo == null 8888 || (mAttachInfo.mSystemUiVisibility & SYSTEM_UI_LAYOUT_FLAGS) == 0) { 8889 outLocalInsets.set(in.getSystemWindowInsets()); 8890 return in.consumeSystemWindowInsets(); 8891 } else { 8892 outLocalInsets.set(0, 0, 0, 0); 8893 return in; 8894 } 8895 } 8896 8897 /** 8898 * Sets whether or not this view should account for system screen decorations 8899 * such as the status bar and inset its content; that is, controlling whether 8900 * the default implementation of {@link #fitSystemWindows(Rect)} will be 8901 * executed. See that method for more details. 8902 * 8903 * <p>Note that if you are providing your own implementation of 8904 * {@link #fitSystemWindows(Rect)}, then there is no need to set this 8905 * flag to true -- your implementation will be overriding the default 8906 * implementation that checks this flag. 8907 * 8908 * @param fitSystemWindows If true, then the default implementation of 8909 * {@link #fitSystemWindows(Rect)} will be executed. 8910 * 8911 * @attr ref android.R.styleable#View_fitsSystemWindows 8912 * @see #getFitsSystemWindows() 8913 * @see #fitSystemWindows(Rect) 8914 * @see #setSystemUiVisibility(int) 8915 */ 8916 public void setFitsSystemWindows(boolean fitSystemWindows) { 8917 setFlags(fitSystemWindows ? FITS_SYSTEM_WINDOWS : 0, FITS_SYSTEM_WINDOWS); 8918 } 8919 8920 /** 8921 * Check for state of {@link #setFitsSystemWindows(boolean)}. If this method 8922 * returns {@code true}, the default implementation of {@link #fitSystemWindows(Rect)} 8923 * will be executed. 8924 * 8925 * @return {@code true} if the default implementation of 8926 * {@link #fitSystemWindows(Rect)} will be executed. 8927 * 8928 * @attr ref android.R.styleable#View_fitsSystemWindows 8929 * @see #setFitsSystemWindows(boolean) 8930 * @see #fitSystemWindows(Rect) 8931 * @see #setSystemUiVisibility(int) 8932 */ 8933 @ViewDebug.ExportedProperty 8934 public boolean getFitsSystemWindows() { 8935 return (mViewFlags & FITS_SYSTEM_WINDOWS) == FITS_SYSTEM_WINDOWS; 8936 } 8937 8938 /** @hide */ 8939 public boolean fitsSystemWindows() { 8940 return getFitsSystemWindows(); 8941 } 8942 8943 /** 8944 * Ask that a new dispatch of {@link #fitSystemWindows(Rect)} be performed. 8945 * @deprecated Use {@link #requestApplyInsets()} for newer platform versions. 8946 */ 8947 @Deprecated 8948 public void requestFitSystemWindows() { 8949 if (mParent != null) { 8950 mParent.requestFitSystemWindows(); 8951 } 8952 } 8953 8954 /** 8955 * Ask that a new dispatch of {@link #onApplyWindowInsets(WindowInsets)} be performed. 8956 */ 8957 public void requestApplyInsets() { 8958 requestFitSystemWindows(); 8959 } 8960 8961 /** 8962 * For use by PhoneWindow to make its own system window fitting optional. 8963 * @hide 8964 */ 8965 public void makeOptionalFitsSystemWindows() { 8966 setFlags(OPTIONAL_FITS_SYSTEM_WINDOWS, OPTIONAL_FITS_SYSTEM_WINDOWS); 8967 } 8968 8969 /** 8970 * Returns the outsets, which areas of the device that aren't a surface, but we would like to 8971 * treat them as such. 8972 * @hide 8973 */ 8974 public void getOutsets(Rect outOutsetRect) { 8975 if (mAttachInfo != null) { 8976 outOutsetRect.set(mAttachInfo.mOutsets); 8977 } else { 8978 outOutsetRect.setEmpty(); 8979 } 8980 } 8981 8982 /** 8983 * Returns the visibility status for this view. 8984 * 8985 * @return One of {@link #VISIBLE}, {@link #INVISIBLE}, or {@link #GONE}. 8986 * @attr ref android.R.styleable#View_visibility 8987 */ 8988 @ViewDebug.ExportedProperty(mapping = { 8989 @ViewDebug.IntToString(from = VISIBLE, to = "VISIBLE"), 8990 @ViewDebug.IntToString(from = INVISIBLE, to = "INVISIBLE"), 8991 @ViewDebug.IntToString(from = GONE, to = "GONE") 8992 }) 8993 @Visibility 8994 public int getVisibility() { 8995 return mViewFlags & VISIBILITY_MASK; 8996 } 8997 8998 /** 8999 * Set the visibility state of this view. 9000 * 9001 * @param visibility One of {@link #VISIBLE}, {@link #INVISIBLE}, or {@link #GONE}. 9002 * @attr ref android.R.styleable#View_visibility 9003 */ 9004 @RemotableViewMethod 9005 public void setVisibility(@Visibility int visibility) { 9006 setFlags(visibility, VISIBILITY_MASK); 9007 } 9008 9009 /** 9010 * Returns the enabled status for this view. The interpretation of the 9011 * enabled state varies by subclass. 9012 * 9013 * @return True if this view is enabled, false otherwise. 9014 */ 9015 @ViewDebug.ExportedProperty 9016 public boolean isEnabled() { 9017 return (mViewFlags & ENABLED_MASK) == ENABLED; 9018 } 9019 9020 /** 9021 * Set the enabled state of this view. The interpretation of the enabled 9022 * state varies by subclass. 9023 * 9024 * @param enabled True if this view is enabled, false otherwise. 9025 */ 9026 @RemotableViewMethod 9027 public void setEnabled(boolean enabled) { 9028 if (enabled == isEnabled()) return; 9029 9030 setFlags(enabled ? ENABLED : DISABLED, ENABLED_MASK); 9031 9032 /* 9033 * The View most likely has to change its appearance, so refresh 9034 * the drawable state. 9035 */ 9036 refreshDrawableState(); 9037 9038 // Invalidate too, since the default behavior for views is to be 9039 // be drawn at 50% alpha rather than to change the drawable. 9040 invalidate(true); 9041 9042 if (!enabled) { 9043 cancelPendingInputEvents(); 9044 } 9045 } 9046 9047 /** 9048 * Set whether this view can receive the focus. 9049 * <p> 9050 * Setting this to false will also ensure that this view is not focusable 9051 * in touch mode. 9052 * 9053 * @param focusable If true, this view can receive the focus. 9054 * 9055 * @see #setFocusableInTouchMode(boolean) 9056 * @see #setFocusable(int) 9057 * @attr ref android.R.styleable#View_focusable 9058 */ 9059 public void setFocusable(boolean focusable) { 9060 setFocusable(focusable ? FOCUSABLE : NOT_FOCUSABLE); 9061 } 9062 9063 /** 9064 * Sets whether this view can receive focus. 9065 * <p> 9066 * Setting this to {@link #FOCUSABLE_AUTO} tells the framework to determine focusability 9067 * automatically based on the view's interactivity. This is the default. 9068 * <p> 9069 * Setting this to NOT_FOCUSABLE will ensure that this view is also not focusable 9070 * in touch mode. 9071 * 9072 * @param focusable One of {@link #NOT_FOCUSABLE}, {@link #FOCUSABLE}, 9073 * or {@link #FOCUSABLE_AUTO}. 9074 * @see #setFocusableInTouchMode(boolean) 9075 * @attr ref android.R.styleable#View_focusable 9076 */ 9077 public void setFocusable(@Focusable int focusable) { 9078 if ((focusable & (FOCUSABLE_AUTO | FOCUSABLE)) == 0) { 9079 setFlags(0, FOCUSABLE_IN_TOUCH_MODE); 9080 } 9081 setFlags(focusable, FOCUSABLE_MASK); 9082 } 9083 9084 /** 9085 * Set whether this view can receive focus while in touch mode. 9086 * 9087 * Setting this to true will also ensure that this view is focusable. 9088 * 9089 * @param focusableInTouchMode If true, this view can receive the focus while 9090 * in touch mode. 9091 * 9092 * @see #setFocusable(boolean) 9093 * @attr ref android.R.styleable#View_focusableInTouchMode 9094 */ 9095 public void setFocusableInTouchMode(boolean focusableInTouchMode) { 9096 // Focusable in touch mode should always be set before the focusable flag 9097 // otherwise, setting the focusable flag will trigger a focusableViewAvailable() 9098 // which, in touch mode, will not successfully request focus on this view 9099 // because the focusable in touch mode flag is not set 9100 setFlags(focusableInTouchMode ? FOCUSABLE_IN_TOUCH_MODE : 0, FOCUSABLE_IN_TOUCH_MODE); 9101 9102 // Clear FOCUSABLE_AUTO if set. 9103 if (focusableInTouchMode) { 9104 // Clears FOCUSABLE_AUTO if set. 9105 setFlags(FOCUSABLE, FOCUSABLE_MASK); 9106 } 9107 } 9108 9109 /** 9110 * Sets the hints that helps the autofill service to select the appropriate data to fill the 9111 * view. 9112 * 9113 * @param autofillHints The autofill hints to set. If the array is emtpy, {@code null} is set. 9114 * @attr ref android.R.styleable#View_autofillHints 9115 */ 9116 public void setAutofillHints(@Nullable String... autofillHints) { 9117 if (autofillHints == null || autofillHints.length == 0) { 9118 mAutofillHints = null; 9119 } else { 9120 mAutofillHints = autofillHints; 9121 } 9122 } 9123 9124 /** 9125 * @hide 9126 */ 9127 @TestApi 9128 public void setAutofilled(boolean isAutofilled) { 9129 boolean wasChanged = isAutofilled != isAutofilled(); 9130 9131 if (wasChanged) { 9132 if (isAutofilled) { 9133 mPrivateFlags3 |= PFLAG3_IS_AUTOFILLED; 9134 } else { 9135 mPrivateFlags3 &= ~PFLAG3_IS_AUTOFILLED; 9136 } 9137 9138 invalidate(); 9139 } 9140 } 9141 9142 /** 9143 * Set whether this view should have sound effects enabled for events such as 9144 * clicking and touching. 9145 * 9146 * <p>You may wish to disable sound effects for a view if you already play sounds, 9147 * for instance, a dial key that plays dtmf tones. 9148 * 9149 * @param soundEffectsEnabled whether sound effects are enabled for this view. 9150 * @see #isSoundEffectsEnabled() 9151 * @see #playSoundEffect(int) 9152 * @attr ref android.R.styleable#View_soundEffectsEnabled 9153 */ 9154 public void setSoundEffectsEnabled(boolean soundEffectsEnabled) { 9155 setFlags(soundEffectsEnabled ? SOUND_EFFECTS_ENABLED: 0, SOUND_EFFECTS_ENABLED); 9156 } 9157 9158 /** 9159 * @return whether this view should have sound effects enabled for events such as 9160 * clicking and touching. 9161 * 9162 * @see #setSoundEffectsEnabled(boolean) 9163 * @see #playSoundEffect(int) 9164 * @attr ref android.R.styleable#View_soundEffectsEnabled 9165 */ 9166 @ViewDebug.ExportedProperty 9167 public boolean isSoundEffectsEnabled() { 9168 return SOUND_EFFECTS_ENABLED == (mViewFlags & SOUND_EFFECTS_ENABLED); 9169 } 9170 9171 /** 9172 * Set whether this view should have haptic feedback for events such as 9173 * long presses. 9174 * 9175 * <p>You may wish to disable haptic feedback if your view already controls 9176 * its own haptic feedback. 9177 * 9178 * @param hapticFeedbackEnabled whether haptic feedback enabled for this view. 9179 * @see #isHapticFeedbackEnabled() 9180 * @see #performHapticFeedback(int) 9181 * @attr ref android.R.styleable#View_hapticFeedbackEnabled 9182 */ 9183 public void setHapticFeedbackEnabled(boolean hapticFeedbackEnabled) { 9184 setFlags(hapticFeedbackEnabled ? HAPTIC_FEEDBACK_ENABLED: 0, HAPTIC_FEEDBACK_ENABLED); 9185 } 9186 9187 /** 9188 * @return whether this view should have haptic feedback enabled for events 9189 * long presses. 9190 * 9191 * @see #setHapticFeedbackEnabled(boolean) 9192 * @see #performHapticFeedback(int) 9193 * @attr ref android.R.styleable#View_hapticFeedbackEnabled 9194 */ 9195 @ViewDebug.ExportedProperty 9196 public boolean isHapticFeedbackEnabled() { 9197 return HAPTIC_FEEDBACK_ENABLED == (mViewFlags & HAPTIC_FEEDBACK_ENABLED); 9198 } 9199 9200 /** 9201 * Returns the layout direction for this view. 9202 * 9203 * @return One of {@link #LAYOUT_DIRECTION_LTR}, 9204 * {@link #LAYOUT_DIRECTION_RTL}, 9205 * {@link #LAYOUT_DIRECTION_INHERIT} or 9206 * {@link #LAYOUT_DIRECTION_LOCALE}. 9207 * 9208 * @attr ref android.R.styleable#View_layoutDirection 9209 * 9210 * @hide 9211 */ 9212 @ViewDebug.ExportedProperty(category = "layout", mapping = { 9213 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_LTR, to = "LTR"), 9214 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_RTL, to = "RTL"), 9215 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_INHERIT, to = "INHERIT"), 9216 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_LOCALE, to = "LOCALE") 9217 }) 9218 @LayoutDir 9219 public int getRawLayoutDirection() { 9220 return (mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_MASK) >> PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 9221 } 9222 9223 /** 9224 * Set the layout direction for this view. This will propagate a reset of layout direction 9225 * resolution to the view's children and resolve layout direction for this view. 9226 * 9227 * @param layoutDirection the layout direction to set. Should be one of: 9228 * 9229 * {@link #LAYOUT_DIRECTION_LTR}, 9230 * {@link #LAYOUT_DIRECTION_RTL}, 9231 * {@link #LAYOUT_DIRECTION_INHERIT}, 9232 * {@link #LAYOUT_DIRECTION_LOCALE}. 9233 * 9234 * Resolution will be done if the value is set to LAYOUT_DIRECTION_INHERIT. The resolution 9235 * proceeds up the parent chain of the view to get the value. If there is no parent, then it 9236 * will return the default {@link #LAYOUT_DIRECTION_LTR}. 9237 * 9238 * @attr ref android.R.styleable#View_layoutDirection 9239 */ 9240 @RemotableViewMethod 9241 public void setLayoutDirection(@LayoutDir int layoutDirection) { 9242 if (getRawLayoutDirection() != layoutDirection) { 9243 // Reset the current layout direction and the resolved one 9244 mPrivateFlags2 &= ~PFLAG2_LAYOUT_DIRECTION_MASK; 9245 resetRtlProperties(); 9246 // Set the new layout direction (filtered) 9247 mPrivateFlags2 |= 9248 ((layoutDirection << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT) & PFLAG2_LAYOUT_DIRECTION_MASK); 9249 // We need to resolve all RTL properties as they all depend on layout direction 9250 resolveRtlPropertiesIfNeeded(); 9251 requestLayout(); 9252 invalidate(true); 9253 } 9254 } 9255 9256 /** 9257 * Returns the resolved layout direction for this view. 9258 * 9259 * @return {@link #LAYOUT_DIRECTION_RTL} if the layout direction is RTL or returns 9260 * {@link #LAYOUT_DIRECTION_LTR} if the layout direction is not RTL. 9261 * 9262 * For compatibility, this will return {@link #LAYOUT_DIRECTION_LTR} if API version 9263 * is lower than {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR1}. 9264 * 9265 * @attr ref android.R.styleable#View_layoutDirection 9266 */ 9267 @ViewDebug.ExportedProperty(category = "layout", mapping = { 9268 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_LTR, to = "RESOLVED_DIRECTION_LTR"), 9269 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_RTL, to = "RESOLVED_DIRECTION_RTL") 9270 }) 9271 @ResolvedLayoutDir 9272 public int getLayoutDirection() { 9273 final int targetSdkVersion = getContext().getApplicationInfo().targetSdkVersion; 9274 if (targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR1) { 9275 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED; 9276 return LAYOUT_DIRECTION_RESOLVED_DEFAULT; 9277 } 9278 return ((mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL) == 9279 PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL) ? LAYOUT_DIRECTION_RTL : LAYOUT_DIRECTION_LTR; 9280 } 9281 9282 /** 9283 * Indicates whether or not this view's layout is right-to-left. This is resolved from 9284 * layout attribute and/or the inherited value from the parent 9285 * 9286 * @return true if the layout is right-to-left. 9287 * 9288 * @hide 9289 */ 9290 @ViewDebug.ExportedProperty(category = "layout") 9291 public boolean isLayoutRtl() { 9292 return (getLayoutDirection() == LAYOUT_DIRECTION_RTL); 9293 } 9294 9295 /** 9296 * Indicates whether the view is currently tracking transient state that the 9297 * app should not need to concern itself with saving and restoring, but that 9298 * the framework should take special note to preserve when possible. 9299 * 9300 * <p>A view with transient state cannot be trivially rebound from an external 9301 * data source, such as an adapter binding item views in a list. This may be 9302 * because the view is performing an animation, tracking user selection 9303 * of content, or similar.</p> 9304 * 9305 * @return true if the view has transient state 9306 */ 9307 @ViewDebug.ExportedProperty(category = "layout") 9308 public boolean hasTransientState() { 9309 return (mPrivateFlags2 & PFLAG2_HAS_TRANSIENT_STATE) == PFLAG2_HAS_TRANSIENT_STATE; 9310 } 9311 9312 /** 9313 * Set whether this view is currently tracking transient state that the 9314 * framework should attempt to preserve when possible. This flag is reference counted, 9315 * so every call to setHasTransientState(true) should be paired with a later call 9316 * to setHasTransientState(false). 9317 * 9318 * <p>A view with transient state cannot be trivially rebound from an external 9319 * data source, such as an adapter binding item views in a list. This may be 9320 * because the view is performing an animation, tracking user selection 9321 * of content, or similar.</p> 9322 * 9323 * @param hasTransientState true if this view has transient state 9324 */ 9325 public void setHasTransientState(boolean hasTransientState) { 9326 mTransientStateCount = hasTransientState ? mTransientStateCount + 1 : 9327 mTransientStateCount - 1; 9328 if (mTransientStateCount < 0) { 9329 mTransientStateCount = 0; 9330 Log.e(VIEW_LOG_TAG, "hasTransientState decremented below 0: " + 9331 "unmatched pair of setHasTransientState calls"); 9332 } else if ((hasTransientState && mTransientStateCount == 1) || 9333 (!hasTransientState && mTransientStateCount == 0)) { 9334 // update flag if we've just incremented up from 0 or decremented down to 0 9335 mPrivateFlags2 = (mPrivateFlags2 & ~PFLAG2_HAS_TRANSIENT_STATE) | 9336 (hasTransientState ? PFLAG2_HAS_TRANSIENT_STATE : 0); 9337 if (mParent != null) { 9338 try { 9339 mParent.childHasTransientStateChanged(this, hasTransientState); 9340 } catch (AbstractMethodError e) { 9341 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 9342 " does not fully implement ViewParent", e); 9343 } 9344 } 9345 } 9346 } 9347 9348 /** 9349 * Returns true if this view is currently attached to a window. 9350 */ 9351 public boolean isAttachedToWindow() { 9352 return mAttachInfo != null; 9353 } 9354 9355 /** 9356 * Returns true if this view has been through at least one layout since it 9357 * was last attached to or detached from a window. 9358 */ 9359 public boolean isLaidOut() { 9360 return (mPrivateFlags3 & PFLAG3_IS_LAID_OUT) == PFLAG3_IS_LAID_OUT; 9361 } 9362 9363 /** 9364 * If this view doesn't do any drawing on its own, set this flag to 9365 * allow further optimizations. By default, this flag is not set on 9366 * View, but could be set on some View subclasses such as ViewGroup. 9367 * 9368 * Typically, if you override {@link #onDraw(android.graphics.Canvas)} 9369 * you should clear this flag. 9370 * 9371 * @param willNotDraw whether or not this View draw on its own 9372 */ 9373 public void setWillNotDraw(boolean willNotDraw) { 9374 setFlags(willNotDraw ? WILL_NOT_DRAW : 0, DRAW_MASK); 9375 } 9376 9377 /** 9378 * Returns whether or not this View draws on its own. 9379 * 9380 * @return true if this view has nothing to draw, false otherwise 9381 */ 9382 @ViewDebug.ExportedProperty(category = "drawing") 9383 public boolean willNotDraw() { 9384 return (mViewFlags & DRAW_MASK) == WILL_NOT_DRAW; 9385 } 9386 9387 /** 9388 * When a View's drawing cache is enabled, drawing is redirected to an 9389 * offscreen bitmap. Some views, like an ImageView, must be able to 9390 * bypass this mechanism if they already draw a single bitmap, to avoid 9391 * unnecessary usage of the memory. 9392 * 9393 * @param willNotCacheDrawing true if this view does not cache its 9394 * drawing, false otherwise 9395 */ 9396 public void setWillNotCacheDrawing(boolean willNotCacheDrawing) { 9397 setFlags(willNotCacheDrawing ? WILL_NOT_CACHE_DRAWING : 0, WILL_NOT_CACHE_DRAWING); 9398 } 9399 9400 /** 9401 * Returns whether or not this View can cache its drawing or not. 9402 * 9403 * @return true if this view does not cache its drawing, false otherwise 9404 */ 9405 @ViewDebug.ExportedProperty(category = "drawing") 9406 public boolean willNotCacheDrawing() { 9407 return (mViewFlags & WILL_NOT_CACHE_DRAWING) == WILL_NOT_CACHE_DRAWING; 9408 } 9409 9410 /** 9411 * Indicates whether this view reacts to click events or not. 9412 * 9413 * @return true if the view is clickable, false otherwise 9414 * 9415 * @see #setClickable(boolean) 9416 * @attr ref android.R.styleable#View_clickable 9417 */ 9418 @ViewDebug.ExportedProperty 9419 public boolean isClickable() { 9420 return (mViewFlags & CLICKABLE) == CLICKABLE; 9421 } 9422 9423 /** 9424 * Enables or disables click events for this view. When a view 9425 * is clickable it will change its state to "pressed" on every click. 9426 * Subclasses should set the view clickable to visually react to 9427 * user's clicks. 9428 * 9429 * @param clickable true to make the view clickable, false otherwise 9430 * 9431 * @see #isClickable() 9432 * @attr ref android.R.styleable#View_clickable 9433 */ 9434 public void setClickable(boolean clickable) { 9435 setFlags(clickable ? CLICKABLE : 0, CLICKABLE); 9436 } 9437 9438 /** 9439 * Indicates whether this view reacts to long click events or not. 9440 * 9441 * @return true if the view is long clickable, false otherwise 9442 * 9443 * @see #setLongClickable(boolean) 9444 * @attr ref android.R.styleable#View_longClickable 9445 */ 9446 public boolean isLongClickable() { 9447 return (mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE; 9448 } 9449 9450 /** 9451 * Enables or disables long click events for this view. When a view is long 9452 * clickable it reacts to the user holding down the button for a longer 9453 * duration than a tap. This event can either launch the listener or a 9454 * context menu. 9455 * 9456 * @param longClickable true to make the view long clickable, false otherwise 9457 * @see #isLongClickable() 9458 * @attr ref android.R.styleable#View_longClickable 9459 */ 9460 public void setLongClickable(boolean longClickable) { 9461 setFlags(longClickable ? LONG_CLICKABLE : 0, LONG_CLICKABLE); 9462 } 9463 9464 /** 9465 * Indicates whether this view reacts to context clicks or not. 9466 * 9467 * @return true if the view is context clickable, false otherwise 9468 * @see #setContextClickable(boolean) 9469 * @attr ref android.R.styleable#View_contextClickable 9470 */ 9471 public boolean isContextClickable() { 9472 return (mViewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE; 9473 } 9474 9475 /** 9476 * Enables or disables context clicking for this view. This event can launch the listener. 9477 * 9478 * @param contextClickable true to make the view react to a context click, false otherwise 9479 * @see #isContextClickable() 9480 * @attr ref android.R.styleable#View_contextClickable 9481 */ 9482 public void setContextClickable(boolean contextClickable) { 9483 setFlags(contextClickable ? CONTEXT_CLICKABLE : 0, CONTEXT_CLICKABLE); 9484 } 9485 9486 /** 9487 * Sets the pressed state for this view and provides a touch coordinate for 9488 * animation hinting. 9489 * 9490 * @param pressed Pass true to set the View's internal state to "pressed", 9491 * or false to reverts the View's internal state from a 9492 * previously set "pressed" state. 9493 * @param x The x coordinate of the touch that caused the press 9494 * @param y The y coordinate of the touch that caused the press 9495 */ 9496 private void setPressed(boolean pressed, float x, float y) { 9497 if (pressed) { 9498 drawableHotspotChanged(x, y); 9499 } 9500 9501 setPressed(pressed); 9502 } 9503 9504 /** 9505 * Sets the pressed state for this view. 9506 * 9507 * @see #isClickable() 9508 * @see #setClickable(boolean) 9509 * 9510 * @param pressed Pass true to set the View's internal state to "pressed", or false to reverts 9511 * the View's internal state from a previously set "pressed" state. 9512 */ 9513 public void setPressed(boolean pressed) { 9514 final boolean needsRefresh = pressed != ((mPrivateFlags & PFLAG_PRESSED) == PFLAG_PRESSED); 9515 9516 if (pressed) { 9517 mPrivateFlags |= PFLAG_PRESSED; 9518 } else { 9519 mPrivateFlags &= ~PFLAG_PRESSED; 9520 } 9521 9522 if (needsRefresh) { 9523 refreshDrawableState(); 9524 } 9525 dispatchSetPressed(pressed); 9526 } 9527 9528 /** 9529 * Dispatch setPressed to all of this View's children. 9530 * 9531 * @see #setPressed(boolean) 9532 * 9533 * @param pressed The new pressed state 9534 */ 9535 protected void dispatchSetPressed(boolean pressed) { 9536 } 9537 9538 /** 9539 * Indicates whether the view is currently in pressed state. Unless 9540 * {@link #setPressed(boolean)} is explicitly called, only clickable views can enter 9541 * the pressed state. 9542 * 9543 * @see #setPressed(boolean) 9544 * @see #isClickable() 9545 * @see #setClickable(boolean) 9546 * 9547 * @return true if the view is currently pressed, false otherwise 9548 */ 9549 @ViewDebug.ExportedProperty 9550 public boolean isPressed() { 9551 return (mPrivateFlags & PFLAG_PRESSED) == PFLAG_PRESSED; 9552 } 9553 9554 /** 9555 * @hide 9556 * Indicates whether this view will participate in data collection through 9557 * {@link ViewStructure}. If true, it will not provide any data 9558 * for itself or its children. If false, the normal data collection will be allowed. 9559 * 9560 * @return Returns false if assist data collection is not blocked, else true. 9561 * 9562 * @see #setAssistBlocked(boolean) 9563 * @attr ref android.R.styleable#View_assistBlocked 9564 */ 9565 public boolean isAssistBlocked() { 9566 return (mPrivateFlags3 & PFLAG3_ASSIST_BLOCKED) != 0; 9567 } 9568 9569 /** 9570 * @hide 9571 * Indicates whether this view will participate in data collection through 9572 * {@link ViewStructure} for autofill purposes. 9573 * 9574 * <p>If {@code true}, it will not provide any data for itself or its children. 9575 * <p>If {@code false}, the normal data collection will be allowed. 9576 * 9577 * @return Returns {@code false} if assist data collection for autofill is not blocked, 9578 * else {@code true}. 9579 */ 9580 public boolean isAutofillBlocked() { 9581 // TODO(b/36171235): properly implement it using isImportantForAutofill() 9582 return false; 9583 } 9584 9585 /** 9586 * @hide 9587 * Controls whether assist data collection from this view and its children is enabled 9588 * (that is, whether {@link #onProvideStructure} and 9589 * {@link #onProvideVirtualStructure} will be called). The default value is false, 9590 * allowing normal assist collection. Setting this to false will disable assist collection. 9591 * 9592 * @param enabled Set to true to <em>disable</em> assist data collection, or false 9593 * (the default) to allow it. 9594 * 9595 * @see #isAssistBlocked() 9596 * @see #onProvideStructure 9597 * @see #onProvideVirtualStructure 9598 * @attr ref android.R.styleable#View_assistBlocked 9599 */ 9600 public void setAssistBlocked(boolean enabled) { 9601 if (enabled) { 9602 mPrivateFlags3 |= PFLAG3_ASSIST_BLOCKED; 9603 } else { 9604 mPrivateFlags3 &= ~PFLAG3_ASSIST_BLOCKED; 9605 } 9606 } 9607 9608 /** 9609 * Indicates whether this view will save its state (that is, 9610 * whether its {@link #onSaveInstanceState} method will be called). 9611 * 9612 * @return Returns true if the view state saving is enabled, else false. 9613 * 9614 * @see #setSaveEnabled(boolean) 9615 * @attr ref android.R.styleable#View_saveEnabled 9616 */ 9617 public boolean isSaveEnabled() { 9618 return (mViewFlags & SAVE_DISABLED_MASK) != SAVE_DISABLED; 9619 } 9620 9621 /** 9622 * Controls whether the saving of this view's state is 9623 * enabled (that is, whether its {@link #onSaveInstanceState} method 9624 * will be called). Note that even if freezing is enabled, the 9625 * view still must have an id assigned to it (via {@link #setId(int)}) 9626 * for its state to be saved. This flag can only disable the 9627 * saving of this view; any child views may still have their state saved. 9628 * 9629 * @param enabled Set to false to <em>disable</em> state saving, or true 9630 * (the default) to allow it. 9631 * 9632 * @see #isSaveEnabled() 9633 * @see #setId(int) 9634 * @see #onSaveInstanceState() 9635 * @attr ref android.R.styleable#View_saveEnabled 9636 */ 9637 public void setSaveEnabled(boolean enabled) { 9638 setFlags(enabled ? 0 : SAVE_DISABLED, SAVE_DISABLED_MASK); 9639 } 9640 9641 /** 9642 * Gets whether the framework should discard touches when the view's 9643 * window is obscured by another visible window. 9644 * Refer to the {@link View} security documentation for more details. 9645 * 9646 * @return True if touch filtering is enabled. 9647 * 9648 * @see #setFilterTouchesWhenObscured(boolean) 9649 * @attr ref android.R.styleable#View_filterTouchesWhenObscured 9650 */ 9651 @ViewDebug.ExportedProperty 9652 public boolean getFilterTouchesWhenObscured() { 9653 return (mViewFlags & FILTER_TOUCHES_WHEN_OBSCURED) != 0; 9654 } 9655 9656 /** 9657 * Sets whether the framework should discard touches when the view's 9658 * window is obscured by another visible window. 9659 * Refer to the {@link View} security documentation for more details. 9660 * 9661 * @param enabled True if touch filtering should be enabled. 9662 * 9663 * @see #getFilterTouchesWhenObscured 9664 * @attr ref android.R.styleable#View_filterTouchesWhenObscured 9665 */ 9666 public void setFilterTouchesWhenObscured(boolean enabled) { 9667 setFlags(enabled ? FILTER_TOUCHES_WHEN_OBSCURED : 0, 9668 FILTER_TOUCHES_WHEN_OBSCURED); 9669 } 9670 9671 /** 9672 * Indicates whether the entire hierarchy under this view will save its 9673 * state when a state saving traversal occurs from its parent. The default 9674 * is true; if false, these views will not be saved unless 9675 * {@link #saveHierarchyState(SparseArray)} is called directly on this view. 9676 * 9677 * @return Returns true if the view state saving from parent is enabled, else false. 9678 * 9679 * @see #setSaveFromParentEnabled(boolean) 9680 */ 9681 public boolean isSaveFromParentEnabled() { 9682 return (mViewFlags & PARENT_SAVE_DISABLED_MASK) != PARENT_SAVE_DISABLED; 9683 } 9684 9685 /** 9686 * Controls whether the entire hierarchy under this view will save its 9687 * state when a state saving traversal occurs from its parent. The default 9688 * is true; if false, these views will not be saved unless 9689 * {@link #saveHierarchyState(SparseArray)} is called directly on this view. 9690 * 9691 * @param enabled Set to false to <em>disable</em> state saving, or true 9692 * (the default) to allow it. 9693 * 9694 * @see #isSaveFromParentEnabled() 9695 * @see #setId(int) 9696 * @see #onSaveInstanceState() 9697 */ 9698 public void setSaveFromParentEnabled(boolean enabled) { 9699 setFlags(enabled ? 0 : PARENT_SAVE_DISABLED, PARENT_SAVE_DISABLED_MASK); 9700 } 9701 9702 9703 /** 9704 * Returns whether this View is currently able to take focus. 9705 * 9706 * @return True if this view can take focus, or false otherwise. 9707 */ 9708 @ViewDebug.ExportedProperty(category = "focus") 9709 public final boolean isFocusable() { 9710 return FOCUSABLE == (mViewFlags & FOCUSABLE); 9711 } 9712 9713 /** 9714 * Returns the focusable setting for this view. 9715 * 9716 * @return One of {@link #NOT_FOCUSABLE}, {@link #FOCUSABLE}, or {@link #FOCUSABLE_AUTO}. 9717 * @attr ref android.R.styleable#View_focusable 9718 */ 9719 @ViewDebug.ExportedProperty(mapping = { 9720 @ViewDebug.IntToString(from = NOT_FOCUSABLE, to = "NOT_FOCUSABLE"), 9721 @ViewDebug.IntToString(from = FOCUSABLE, to = "FOCUSABLE"), 9722 @ViewDebug.IntToString(from = FOCUSABLE_AUTO, to = "FOCUSABLE_AUTO") 9723 }, category = "focus") 9724 @Focusable 9725 public int getFocusable() { 9726 return (mViewFlags & FOCUSABLE_AUTO) > 0 ? FOCUSABLE_AUTO : mViewFlags & FOCUSABLE; 9727 } 9728 9729 /** 9730 * When a view is focusable, it may not want to take focus when in touch mode. 9731 * For example, a button would like focus when the user is navigating via a D-pad 9732 * so that the user can click on it, but once the user starts touching the screen, 9733 * the button shouldn't take focus 9734 * @return Whether the view is focusable in touch mode. 9735 * @attr ref android.R.styleable#View_focusableInTouchMode 9736 */ 9737 @ViewDebug.ExportedProperty(category = "focus") 9738 public final boolean isFocusableInTouchMode() { 9739 return FOCUSABLE_IN_TOUCH_MODE == (mViewFlags & FOCUSABLE_IN_TOUCH_MODE); 9740 } 9741 9742 /** 9743 * Find the nearest view in the specified direction that can take focus. 9744 * This does not actually give focus to that view. 9745 * 9746 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT 9747 * 9748 * @return The nearest focusable in the specified direction, or null if none 9749 * can be found. 9750 */ 9751 public View focusSearch(@FocusRealDirection int direction) { 9752 if (mParent != null) { 9753 return mParent.focusSearch(this, direction); 9754 } else { 9755 return null; 9756 } 9757 } 9758 9759 /** 9760 * Returns whether this View is a root of a keyboard navigation cluster. 9761 * 9762 * @return True if this view is a root of a cluster, or false otherwise. 9763 * @attr ref android.R.styleable#View_keyboardNavigationCluster 9764 */ 9765 @ViewDebug.ExportedProperty(category = "focus") 9766 public final boolean isKeyboardNavigationCluster() { 9767 return (mPrivateFlags3 & PFLAG3_CLUSTER) != 0; 9768 } 9769 9770 /** 9771 * Searches up the view hierarchy to find the top-most cluster. All deeper/nested clusters 9772 * will be ignored. 9773 * 9774 * @return the keyboard navigation cluster that this view is in (can be this view) 9775 * or {@code null} if not in one 9776 */ 9777 View findKeyboardNavigationCluster() { 9778 if (mParent instanceof View) { 9779 View cluster = ((View) mParent).findKeyboardNavigationCluster(); 9780 if (cluster != null) { 9781 return cluster; 9782 } else if (isKeyboardNavigationCluster()) { 9783 return this; 9784 } 9785 } 9786 return null; 9787 } 9788 9789 /** 9790 * Set whether this view is a root of a keyboard navigation cluster. 9791 * 9792 * @param isCluster If true, this view is a root of a cluster. 9793 * 9794 * @attr ref android.R.styleable#View_keyboardNavigationCluster 9795 */ 9796 public void setKeyboardNavigationCluster(boolean isCluster) { 9797 if (isCluster) { 9798 mPrivateFlags3 |= PFLAG3_CLUSTER; 9799 } else { 9800 mPrivateFlags3 &= ~PFLAG3_CLUSTER; 9801 } 9802 } 9803 9804 /** 9805 * Sets this View as the one which receives focus the next time cluster navigation jumps 9806 * to the cluster containing this View. This does NOT change focus even if the cluster 9807 * containing this view is current. 9808 * 9809 * @hide 9810 */ 9811 public final void setFocusedInCluster() { 9812 View top = findKeyboardNavigationCluster(); 9813 if (top == this) { 9814 return; 9815 } 9816 ViewParent parent = mParent; 9817 View child = this; 9818 while (parent instanceof ViewGroup) { 9819 ((ViewGroup) parent).setFocusedInCluster(child); 9820 if (parent == top) { 9821 return; 9822 } 9823 child = (View) parent; 9824 parent = parent.getParent(); 9825 } 9826 } 9827 9828 /** 9829 * Returns whether this View should receive focus when the focus is restored for the view 9830 * hierarchy containing this view. 9831 * <p> 9832 * Focus gets restored for a view hierarchy when the root of the hierarchy gets added to a 9833 * window or serves as a target of cluster navigation. 9834 * 9835 * @see #restoreDefaultFocus() 9836 * 9837 * @return {@code true} if this view is the default-focus view, {@code false} otherwise 9838 * @attr ref android.R.styleable#View_focusedByDefault 9839 */ 9840 @ViewDebug.ExportedProperty(category = "focus") 9841 public final boolean isFocusedByDefault() { 9842 return (mPrivateFlags3 & PFLAG3_FOCUSED_BY_DEFAULT) != 0; 9843 } 9844 9845 /** 9846 * Sets whether this View should receive focus when the focus is restored for the view 9847 * hierarchy containing this view. 9848 * <p> 9849 * Focus gets restored for a view hierarchy when the root of the hierarchy gets added to a 9850 * window or serves as a target of cluster navigation. 9851 * 9852 * @param isFocusedByDefault {@code true} to set this view as the default-focus view, 9853 * {@code false} otherwise. 9854 * 9855 * @see #restoreDefaultFocus() 9856 * 9857 * @attr ref android.R.styleable#View_focusedByDefault 9858 */ 9859 public void setFocusedByDefault(boolean isFocusedByDefault) { 9860 if (isFocusedByDefault == ((mPrivateFlags3 & PFLAG3_FOCUSED_BY_DEFAULT) != 0)) { 9861 return; 9862 } 9863 9864 if (isFocusedByDefault) { 9865 mPrivateFlags3 |= PFLAG3_FOCUSED_BY_DEFAULT; 9866 } else { 9867 mPrivateFlags3 &= ~PFLAG3_FOCUSED_BY_DEFAULT; 9868 } 9869 9870 if (mParent instanceof ViewGroup) { 9871 if (isFocusedByDefault) { 9872 ((ViewGroup) mParent).setDefaultFocus(this); 9873 } else { 9874 ((ViewGroup) mParent).clearDefaultFocus(this); 9875 } 9876 } 9877 } 9878 9879 /** 9880 * Returns whether the view hierarchy with this view as a root contain a default-focus view. 9881 * 9882 * @return {@code true} if this view has default focus, {@code false} otherwise 9883 */ 9884 boolean hasDefaultFocus() { 9885 return isFocusedByDefault(); 9886 } 9887 9888 /** 9889 * Find the nearest keyboard navigation cluster in the specified direction. 9890 * This does not actually give focus to that cluster. 9891 * 9892 * @param currentCluster The starting point of the search. Null means the current cluster is not 9893 * found yet 9894 * @param direction Direction to look 9895 * 9896 * @return The nearest keyboard navigation cluster in the specified direction, or null if none 9897 * can be found 9898 */ 9899 public View keyboardNavigationClusterSearch(View currentCluster, 9900 @FocusDirection int direction) { 9901 if (isKeyboardNavigationCluster()) { 9902 currentCluster = this; 9903 } 9904 if (isRootNamespace()) { 9905 // Root namespace means we should consider ourselves the top of the 9906 // tree for group searching; otherwise we could be group searching 9907 // into other tabs. see LocalActivityManager and TabHost for more info. 9908 return FocusFinder.getInstance().findNextKeyboardNavigationCluster( 9909 this, currentCluster, direction); 9910 } else if (mParent != null) { 9911 return mParent.keyboardNavigationClusterSearch(currentCluster, direction); 9912 } 9913 return null; 9914 } 9915 9916 /** 9917 * This method is the last chance for the focused view and its ancestors to 9918 * respond to an arrow key. This is called when the focused view did not 9919 * consume the key internally, nor could the view system find a new view in 9920 * the requested direction to give focus to. 9921 * 9922 * @param focused The currently focused view. 9923 * @param direction The direction focus wants to move. One of FOCUS_UP, 9924 * FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT. 9925 * @return True if the this view consumed this unhandled move. 9926 */ 9927 public boolean dispatchUnhandledMove(View focused, @FocusRealDirection int direction) { 9928 return false; 9929 } 9930 9931 /** 9932 * Sets whether this View should use a default focus highlight when it gets focused but doesn't 9933 * have {@link android.R.attr#state_focused} defined in its background. 9934 * 9935 * @param defaultFocusHighlightEnabled {@code true} to set this view to use a default focus 9936 * highlight, {@code false} otherwise. 9937 * 9938 * @attr ref android.R.styleable#View_defaultFocusHighlightEnabled 9939 */ 9940 public void setDefaultFocusHighlightEnabled(boolean defaultFocusHighlightEnabled) { 9941 mDefaultFocusHighlightEnabled = defaultFocusHighlightEnabled; 9942 } 9943 9944 /** 9945 9946 /** 9947 * Returns whether this View should use a default focus highlight when it gets focused but 9948 * doesn't have {@link android.R.attr#state_focused} defined in its background. 9949 * 9950 * @return True if this View should use a default focus highlight. 9951 * @attr ref android.R.styleable#View_defaultFocusHighlightEnabled 9952 */ 9953 @ViewDebug.ExportedProperty(category = "focus") 9954 public final boolean getDefaultFocusHighlightEnabled() { 9955 return mDefaultFocusHighlightEnabled; 9956 } 9957 9958 /** 9959 * If a user manually specified the next view id for a particular direction, 9960 * use the root to look up the view. 9961 * @param root The root view of the hierarchy containing this view. 9962 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, FOCUS_RIGHT, FOCUS_FORWARD, 9963 * or FOCUS_BACKWARD. 9964 * @return The user specified next view, or null if there is none. 9965 */ 9966 View findUserSetNextFocus(View root, @FocusDirection int direction) { 9967 switch (direction) { 9968 case FOCUS_LEFT: 9969 if (mNextFocusLeftId == View.NO_ID) return null; 9970 return findViewInsideOutShouldExist(root, mNextFocusLeftId); 9971 case FOCUS_RIGHT: 9972 if (mNextFocusRightId == View.NO_ID) return null; 9973 return findViewInsideOutShouldExist(root, mNextFocusRightId); 9974 case FOCUS_UP: 9975 if (mNextFocusUpId == View.NO_ID) return null; 9976 return findViewInsideOutShouldExist(root, mNextFocusUpId); 9977 case FOCUS_DOWN: 9978 if (mNextFocusDownId == View.NO_ID) return null; 9979 return findViewInsideOutShouldExist(root, mNextFocusDownId); 9980 case FOCUS_FORWARD: 9981 if (mNextFocusForwardId == View.NO_ID) return null; 9982 return findViewInsideOutShouldExist(root, mNextFocusForwardId); 9983 case FOCUS_BACKWARD: { 9984 if (mID == View.NO_ID) return null; 9985 final int id = mID; 9986 return root.findViewByPredicateInsideOut(this, new Predicate<View>() { 9987 @Override 9988 public boolean test(View t) { 9989 return t.mNextFocusForwardId == id; 9990 } 9991 }); 9992 } 9993 } 9994 return null; 9995 } 9996 9997 /** 9998 * If a user manually specified the next keyboard-navigation cluster for a particular direction, 9999 * use the root to look up the view. 10000 * 10001 * @param root the root view of the hierarchy containing this view 10002 * @param direction {@link #FOCUS_FORWARD} or {@link #FOCUS_BACKWARD} 10003 * @return the user-specified next cluster, or {@code null} if there is none 10004 */ 10005 View findUserSetNextKeyboardNavigationCluster(View root, @FocusDirection int direction) { 10006 switch (direction) { 10007 case FOCUS_FORWARD: 10008 if (mNextClusterForwardId == View.NO_ID) return null; 10009 return findViewInsideOutShouldExist(root, mNextClusterForwardId); 10010 case FOCUS_BACKWARD: { 10011 if (mID == View.NO_ID) return null; 10012 final int id = mID; 10013 return root.findViewByPredicateInsideOut(this, 10014 (Predicate<View>) t -> t.mNextClusterForwardId == id); 10015 } 10016 } 10017 return null; 10018 } 10019 10020 private View findViewInsideOutShouldExist(View root, int id) { 10021 if (mMatchIdPredicate == null) { 10022 mMatchIdPredicate = new MatchIdPredicate(); 10023 } 10024 mMatchIdPredicate.mId = id; 10025 View result = root.findViewByPredicateInsideOut(this, mMatchIdPredicate); 10026 if (result == null) { 10027 Log.w(VIEW_LOG_TAG, "couldn't find view with id " + id); 10028 } 10029 return result; 10030 } 10031 10032 /** 10033 * Find and return all focusable views that are descendants of this view, 10034 * possibly including this view if it is focusable itself. 10035 * 10036 * @param direction The direction of the focus 10037 * @return A list of focusable views 10038 */ 10039 public ArrayList<View> getFocusables(@FocusDirection int direction) { 10040 ArrayList<View> result = new ArrayList<View>(24); 10041 addFocusables(result, direction); 10042 return result; 10043 } 10044 10045 /** 10046 * Add any focusable views that are descendants of this view (possibly 10047 * including this view if it is focusable itself) to views. If we are in touch mode, 10048 * only add views that are also focusable in touch mode. 10049 * 10050 * @param views Focusable views found so far 10051 * @param direction The direction of the focus 10052 */ 10053 public void addFocusables(ArrayList<View> views, @FocusDirection int direction) { 10054 addFocusables(views, direction, isInTouchMode() ? FOCUSABLES_TOUCH_MODE : FOCUSABLES_ALL); 10055 } 10056 10057 /** 10058 * Adds any focusable views that are descendants of this view (possibly 10059 * including this view if it is focusable itself) to views. This method 10060 * adds all focusable views regardless if we are in touch mode or 10061 * only views focusable in touch mode if we are in touch mode or 10062 * only views that can take accessibility focus if accessibility is enabled 10063 * depending on the focusable mode parameter. 10064 * 10065 * @param views Focusable views found so far or null if all we are interested is 10066 * the number of focusables. 10067 * @param direction The direction of the focus. 10068 * @param focusableMode The type of focusables to be added. 10069 * 10070 * @see #FOCUSABLES_ALL 10071 * @see #FOCUSABLES_TOUCH_MODE 10072 */ 10073 public void addFocusables(ArrayList<View> views, @FocusDirection int direction, 10074 @FocusableMode int focusableMode) { 10075 if (views == null) { 10076 return; 10077 } 10078 if (!isFocusable()) { 10079 return; 10080 } 10081 if ((focusableMode & FOCUSABLES_TOUCH_MODE) == FOCUSABLES_TOUCH_MODE 10082 && !isFocusableInTouchMode()) { 10083 return; 10084 } 10085 views.add(this); 10086 } 10087 10088 /** 10089 * Adds any keyboard navigation cluster roots that are descendants of this view (possibly 10090 * including this view if it is a cluster root itself) to views. 10091 * 10092 * @param views Keyboard navigation cluster roots found so far 10093 * @param direction Direction to look 10094 */ 10095 public void addKeyboardNavigationClusters( 10096 @NonNull Collection<View> views, 10097 int direction) { 10098 if (!isKeyboardNavigationCluster()) { 10099 return; 10100 } 10101 if (!hasFocusable()) { 10102 return; 10103 } 10104 views.add(this); 10105 } 10106 10107 /** 10108 * Finds the Views that contain given text. The containment is case insensitive. 10109 * The search is performed by either the text that the View renders or the content 10110 * description that describes the view for accessibility purposes and the view does 10111 * not render or both. Clients can specify how the search is to be performed via 10112 * passing the {@link #FIND_VIEWS_WITH_TEXT} and 10113 * {@link #FIND_VIEWS_WITH_CONTENT_DESCRIPTION} flags. 10114 * 10115 * @param outViews The output list of matching Views. 10116 * @param searched The text to match against. 10117 * 10118 * @see #FIND_VIEWS_WITH_TEXT 10119 * @see #FIND_VIEWS_WITH_CONTENT_DESCRIPTION 10120 * @see #setContentDescription(CharSequence) 10121 */ 10122 public void findViewsWithText(ArrayList<View> outViews, CharSequence searched, 10123 @FindViewFlags int flags) { 10124 if (getAccessibilityNodeProvider() != null) { 10125 if ((flags & FIND_VIEWS_WITH_ACCESSIBILITY_NODE_PROVIDERS) != 0) { 10126 outViews.add(this); 10127 } 10128 } else if ((flags & FIND_VIEWS_WITH_CONTENT_DESCRIPTION) != 0 10129 && (searched != null && searched.length() > 0) 10130 && (mContentDescription != null && mContentDescription.length() > 0)) { 10131 String searchedLowerCase = searched.toString().toLowerCase(); 10132 String contentDescriptionLowerCase = mContentDescription.toString().toLowerCase(); 10133 if (contentDescriptionLowerCase.contains(searchedLowerCase)) { 10134 outViews.add(this); 10135 } 10136 } 10137 } 10138 10139 /** 10140 * Find and return all touchable views that are descendants of this view, 10141 * possibly including this view if it is touchable itself. 10142 * 10143 * @return A list of touchable views 10144 */ 10145 public ArrayList<View> getTouchables() { 10146 ArrayList<View> result = new ArrayList<View>(); 10147 addTouchables(result); 10148 return result; 10149 } 10150 10151 /** 10152 * Add any touchable views that are descendants of this view (possibly 10153 * including this view if it is touchable itself) to views. 10154 * 10155 * @param views Touchable views found so far 10156 */ 10157 public void addTouchables(ArrayList<View> views) { 10158 final int viewFlags = mViewFlags; 10159 10160 if (((viewFlags & CLICKABLE) == CLICKABLE || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE 10161 || (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE) 10162 && (viewFlags & ENABLED_MASK) == ENABLED) { 10163 views.add(this); 10164 } 10165 } 10166 10167 /** 10168 * Returns whether this View is accessibility focused. 10169 * 10170 * @return True if this View is accessibility focused. 10171 */ 10172 public boolean isAccessibilityFocused() { 10173 return (mPrivateFlags2 & PFLAG2_ACCESSIBILITY_FOCUSED) != 0; 10174 } 10175 10176 /** 10177 * Call this to try to give accessibility focus to this view. 10178 * 10179 * A view will not actually take focus if {@link AccessibilityManager#isEnabled()} 10180 * returns false or the view is no visible or the view already has accessibility 10181 * focus. 10182 * 10183 * See also {@link #focusSearch(int)}, which is what you call to say that you 10184 * have focus, and you want your parent to look for the next one. 10185 * 10186 * @return Whether this view actually took accessibility focus. 10187 * 10188 * @hide 10189 */ 10190 public boolean requestAccessibilityFocus() { 10191 AccessibilityManager manager = AccessibilityManager.getInstance(mContext); 10192 if (!manager.isEnabled() || !manager.isTouchExplorationEnabled()) { 10193 return false; 10194 } 10195 if ((mViewFlags & VISIBILITY_MASK) != VISIBLE) { 10196 return false; 10197 } 10198 if ((mPrivateFlags2 & PFLAG2_ACCESSIBILITY_FOCUSED) == 0) { 10199 mPrivateFlags2 |= PFLAG2_ACCESSIBILITY_FOCUSED; 10200 ViewRootImpl viewRootImpl = getViewRootImpl(); 10201 if (viewRootImpl != null) { 10202 viewRootImpl.setAccessibilityFocus(this, null); 10203 } 10204 invalidate(); 10205 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED); 10206 return true; 10207 } 10208 return false; 10209 } 10210 10211 /** 10212 * Call this to try to clear accessibility focus of this view. 10213 * 10214 * See also {@link #focusSearch(int)}, which is what you call to say that you 10215 * have focus, and you want your parent to look for the next one. 10216 * 10217 * @hide 10218 */ 10219 public void clearAccessibilityFocus() { 10220 clearAccessibilityFocusNoCallbacks(0); 10221 10222 // Clear the global reference of accessibility focus if this view or 10223 // any of its descendants had accessibility focus. This will NOT send 10224 // an event or update internal state if focus is cleared from a 10225 // descendant view, which may leave views in inconsistent states. 10226 final ViewRootImpl viewRootImpl = getViewRootImpl(); 10227 if (viewRootImpl != null) { 10228 final View focusHost = viewRootImpl.getAccessibilityFocusedHost(); 10229 if (focusHost != null && ViewRootImpl.isViewDescendantOf(focusHost, this)) { 10230 viewRootImpl.setAccessibilityFocus(null, null); 10231 } 10232 } 10233 } 10234 10235 private void sendAccessibilityHoverEvent(int eventType) { 10236 // Since we are not delivering to a client accessibility events from not 10237 // important views (unless the clinet request that) we need to fire the 10238 // event from the deepest view exposed to the client. As a consequence if 10239 // the user crosses a not exposed view the client will see enter and exit 10240 // of the exposed predecessor followed by and enter and exit of that same 10241 // predecessor when entering and exiting the not exposed descendant. This 10242 // is fine since the client has a clear idea which view is hovered at the 10243 // price of a couple more events being sent. This is a simple and 10244 // working solution. 10245 View source = this; 10246 while (true) { 10247 if (source.includeForAccessibility()) { 10248 source.sendAccessibilityEvent(eventType); 10249 return; 10250 } 10251 ViewParent parent = source.getParent(); 10252 if (parent instanceof View) { 10253 source = (View) parent; 10254 } else { 10255 return; 10256 } 10257 } 10258 } 10259 10260 /** 10261 * Clears accessibility focus without calling any callback methods 10262 * normally invoked in {@link #clearAccessibilityFocus()}. This method 10263 * is used separately from that one for clearing accessibility focus when 10264 * giving this focus to another view. 10265 * 10266 * @param action The action, if any, that led to focus being cleared. Set to 10267 * AccessibilityNodeInfo#ACTION_ACCESSIBILITY_FOCUS to specify that focus is moving within 10268 * the window. 10269 */ 10270 void clearAccessibilityFocusNoCallbacks(int action) { 10271 if ((mPrivateFlags2 & PFLAG2_ACCESSIBILITY_FOCUSED) != 0) { 10272 mPrivateFlags2 &= ~PFLAG2_ACCESSIBILITY_FOCUSED; 10273 invalidate(); 10274 if (AccessibilityManager.getInstance(mContext).isEnabled()) { 10275 AccessibilityEvent event = AccessibilityEvent.obtain( 10276 AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED); 10277 event.setAction(action); 10278 if (mAccessibilityDelegate != null) { 10279 mAccessibilityDelegate.sendAccessibilityEventUnchecked(this, event); 10280 } else { 10281 sendAccessibilityEventUnchecked(event); 10282 } 10283 } 10284 } 10285 } 10286 10287 /** 10288 * Call this to try to give focus to a specific view or to one of its 10289 * descendants. 10290 * 10291 * A view will not actually take focus if it is not focusable ({@link #isFocusable} returns 10292 * false), or if it is focusable and it is not focusable in touch mode 10293 * ({@link #isFocusableInTouchMode}) while the device is in touch mode. 10294 * 10295 * See also {@link #focusSearch(int)}, which is what you call to say that you 10296 * have focus, and you want your parent to look for the next one. 10297 * 10298 * This is equivalent to calling {@link #requestFocus(int, Rect)} with arguments 10299 * {@link #FOCUS_DOWN} and <code>null</code>. 10300 * 10301 * @return Whether this view or one of its descendants actually took focus. 10302 */ 10303 public final boolean requestFocus() { 10304 return requestFocus(View.FOCUS_DOWN); 10305 } 10306 10307 /** 10308 * This will request focus for whichever View was last focused within this 10309 * cluster before a focus-jump out of it. 10310 * 10311 * @hide 10312 */ 10313 @TestApi 10314 public boolean restoreFocusInCluster(@FocusRealDirection int direction) { 10315 // Prioritize focusableByDefault over algorithmic focus selection. 10316 if (restoreDefaultFocus()) { 10317 return true; 10318 } 10319 return requestFocus(direction); 10320 } 10321 10322 /** 10323 * This will request focus for whichever View not in a cluster was last focused before a 10324 * focus-jump to a cluster. If no non-cluster View has previously had focus, this will focus 10325 * the "first" focusable view it finds. 10326 * 10327 * @hide 10328 */ 10329 @TestApi 10330 public boolean restoreFocusNotInCluster() { 10331 return requestFocus(View.FOCUS_DOWN); 10332 } 10333 10334 /** 10335 * Gives focus to the default-focus view in the view hierarchy that has this view as a root. 10336 * If the default-focus view cannot be found, falls back to calling {@link #requestFocus(int)}. 10337 * 10338 * @return Whether this view or one of its descendants actually took focus 10339 */ 10340 public boolean restoreDefaultFocus() { 10341 return requestFocus(View.FOCUS_DOWN); 10342 } 10343 10344 /** 10345 * Call this to try to give focus to a specific view or to one of its 10346 * descendants and give it a hint about what direction focus is heading. 10347 * 10348 * A view will not actually take focus if it is not focusable ({@link #isFocusable} returns 10349 * false), or if it is focusable and it is not focusable in touch mode 10350 * ({@link #isFocusableInTouchMode}) while the device is in touch mode. 10351 * 10352 * See also {@link #focusSearch(int)}, which is what you call to say that you 10353 * have focus, and you want your parent to look for the next one. 10354 * 10355 * This is equivalent to calling {@link #requestFocus(int, Rect)} with 10356 * <code>null</code> set for the previously focused rectangle. 10357 * 10358 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT 10359 * @return Whether this view or one of its descendants actually took focus. 10360 */ 10361 public final boolean requestFocus(int direction) { 10362 return requestFocus(direction, null); 10363 } 10364 10365 /** 10366 * Call this to try to give focus to a specific view or to one of its descendants 10367 * and give it hints about the direction and a specific rectangle that the focus 10368 * is coming from. The rectangle can help give larger views a finer grained hint 10369 * about where focus is coming from, and therefore, where to show selection, or 10370 * forward focus change internally. 10371 * 10372 * A view will not actually take focus if it is not focusable ({@link #isFocusable} returns 10373 * false), or if it is focusable and it is not focusable in touch mode 10374 * ({@link #isFocusableInTouchMode}) while the device is in touch mode. 10375 * 10376 * A View will not take focus if it is not visible. 10377 * 10378 * A View will not take focus if one of its parents has 10379 * {@link android.view.ViewGroup#getDescendantFocusability()} equal to 10380 * {@link ViewGroup#FOCUS_BLOCK_DESCENDANTS}. 10381 * 10382 * See also {@link #focusSearch(int)}, which is what you call to say that you 10383 * have focus, and you want your parent to look for the next one. 10384 * 10385 * You may wish to override this method if your custom {@link View} has an internal 10386 * {@link View} that it wishes to forward the request to. 10387 * 10388 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT 10389 * @param previouslyFocusedRect The rectangle (in this View's coordinate system) 10390 * to give a finer grained hint about where focus is coming from. May be null 10391 * if there is no hint. 10392 * @return Whether this view or one of its descendants actually took focus. 10393 */ 10394 public boolean requestFocus(int direction, Rect previouslyFocusedRect) { 10395 return requestFocusNoSearch(direction, previouslyFocusedRect); 10396 } 10397 10398 private boolean requestFocusNoSearch(int direction, Rect previouslyFocusedRect) { 10399 // need to be focusable 10400 if ((mViewFlags & FOCUSABLE) != FOCUSABLE 10401 || (mViewFlags & VISIBILITY_MASK) != VISIBLE) { 10402 return false; 10403 } 10404 10405 // need to be focusable in touch mode if in touch mode 10406 if (isInTouchMode() && 10407 (FOCUSABLE_IN_TOUCH_MODE != (mViewFlags & FOCUSABLE_IN_TOUCH_MODE))) { 10408 return false; 10409 } 10410 10411 // need to not have any parents blocking us 10412 if (hasAncestorThatBlocksDescendantFocus()) { 10413 return false; 10414 } 10415 10416 handleFocusGainInternal(direction, previouslyFocusedRect); 10417 return true; 10418 } 10419 10420 /** 10421 * Call this to try to give focus to a specific view or to one of its descendants. This is a 10422 * special variant of {@link #requestFocus() } that will allow views that are not focusable in 10423 * touch mode to request focus when they are touched. 10424 * 10425 * @return Whether this view or one of its descendants actually took focus. 10426 * 10427 * @see #isInTouchMode() 10428 * 10429 */ 10430 public final boolean requestFocusFromTouch() { 10431 // Leave touch mode if we need to 10432 if (isInTouchMode()) { 10433 ViewRootImpl viewRoot = getViewRootImpl(); 10434 if (viewRoot != null) { 10435 viewRoot.ensureTouchMode(false); 10436 } 10437 } 10438 return requestFocus(View.FOCUS_DOWN); 10439 } 10440 10441 /** 10442 * @return Whether any ancestor of this view blocks descendant focus. 10443 */ 10444 private boolean hasAncestorThatBlocksDescendantFocus() { 10445 final boolean focusableInTouchMode = isFocusableInTouchMode(); 10446 ViewParent ancestor = mParent; 10447 while (ancestor instanceof ViewGroup) { 10448 final ViewGroup vgAncestor = (ViewGroup) ancestor; 10449 if (vgAncestor.getDescendantFocusability() == ViewGroup.FOCUS_BLOCK_DESCENDANTS 10450 || (!focusableInTouchMode && vgAncestor.shouldBlockFocusForTouchscreen())) { 10451 return true; 10452 } else { 10453 ancestor = vgAncestor.getParent(); 10454 } 10455 } 10456 return false; 10457 } 10458 10459 /** 10460 * Gets the mode for determining whether this View is important for accessibility. 10461 * A view is important for accessibility if it fires accessibility events and if it 10462 * is reported to accessibility services that query the screen. 10463 * 10464 * @return The mode for determining whether a view is important for accessibility, one 10465 * of {@link #IMPORTANT_FOR_ACCESSIBILITY_AUTO}, {@link #IMPORTANT_FOR_ACCESSIBILITY_YES}, 10466 * {@link #IMPORTANT_FOR_ACCESSIBILITY_NO}, or 10467 * {@link #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS}. 10468 * 10469 * @attr ref android.R.styleable#View_importantForAccessibility 10470 * 10471 * @see #IMPORTANT_FOR_ACCESSIBILITY_YES 10472 * @see #IMPORTANT_FOR_ACCESSIBILITY_NO 10473 * @see #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS 10474 * @see #IMPORTANT_FOR_ACCESSIBILITY_AUTO 10475 */ 10476 @ViewDebug.ExportedProperty(category = "accessibility", mapping = { 10477 @ViewDebug.IntToString(from = IMPORTANT_FOR_ACCESSIBILITY_AUTO, to = "auto"), 10478 @ViewDebug.IntToString(from = IMPORTANT_FOR_ACCESSIBILITY_YES, to = "yes"), 10479 @ViewDebug.IntToString(from = IMPORTANT_FOR_ACCESSIBILITY_NO, to = "no"), 10480 @ViewDebug.IntToString(from = IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS, 10481 to = "noHideDescendants") 10482 }) 10483 public int getImportantForAccessibility() { 10484 return (mPrivateFlags2 & PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK) 10485 >> PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT; 10486 } 10487 10488 /** 10489 * Sets the live region mode for this view. This indicates to accessibility 10490 * services whether they should automatically notify the user about changes 10491 * to the view's content description or text, or to the content descriptions 10492 * or text of the view's children (where applicable). 10493 * <p> 10494 * For example, in a login screen with a TextView that displays an "incorrect 10495 * password" notification, that view should be marked as a live region with 10496 * mode {@link #ACCESSIBILITY_LIVE_REGION_POLITE}. 10497 * <p> 10498 * To disable change notifications for this view, use 10499 * {@link #ACCESSIBILITY_LIVE_REGION_NONE}. This is the default live region 10500 * mode for most views. 10501 * <p> 10502 * To indicate that the user should be notified of changes, use 10503 * {@link #ACCESSIBILITY_LIVE_REGION_POLITE}. 10504 * <p> 10505 * If the view's changes should interrupt ongoing speech and notify the user 10506 * immediately, use {@link #ACCESSIBILITY_LIVE_REGION_ASSERTIVE}. 10507 * 10508 * @param mode The live region mode for this view, one of: 10509 * <ul> 10510 * <li>{@link #ACCESSIBILITY_LIVE_REGION_NONE} 10511 * <li>{@link #ACCESSIBILITY_LIVE_REGION_POLITE} 10512 * <li>{@link #ACCESSIBILITY_LIVE_REGION_ASSERTIVE} 10513 * </ul> 10514 * @attr ref android.R.styleable#View_accessibilityLiveRegion 10515 */ 10516 public void setAccessibilityLiveRegion(int mode) { 10517 if (mode != getAccessibilityLiveRegion()) { 10518 mPrivateFlags2 &= ~PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK; 10519 mPrivateFlags2 |= (mode << PFLAG2_ACCESSIBILITY_LIVE_REGION_SHIFT) 10520 & PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK; 10521 notifyViewAccessibilityStateChangedIfNeeded( 10522 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 10523 } 10524 } 10525 10526 /** 10527 * Gets the live region mode for this View. 10528 * 10529 * @return The live region mode for the view. 10530 * 10531 * @attr ref android.R.styleable#View_accessibilityLiveRegion 10532 * 10533 * @see #setAccessibilityLiveRegion(int) 10534 */ 10535 public int getAccessibilityLiveRegion() { 10536 return (mPrivateFlags2 & PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK) 10537 >> PFLAG2_ACCESSIBILITY_LIVE_REGION_SHIFT; 10538 } 10539 10540 /** 10541 * Sets how to determine whether this view is important for accessibility 10542 * which is if it fires accessibility events and if it is reported to 10543 * accessibility services that query the screen. 10544 * 10545 * @param mode How to determine whether this view is important for accessibility. 10546 * 10547 * @attr ref android.R.styleable#View_importantForAccessibility 10548 * 10549 * @see #IMPORTANT_FOR_ACCESSIBILITY_YES 10550 * @see #IMPORTANT_FOR_ACCESSIBILITY_NO 10551 * @see #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS 10552 * @see #IMPORTANT_FOR_ACCESSIBILITY_AUTO 10553 */ 10554 public void setImportantForAccessibility(int mode) { 10555 final int oldMode = getImportantForAccessibility(); 10556 if (mode != oldMode) { 10557 final boolean hideDescendants = 10558 mode == IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS; 10559 10560 // If this node or its descendants are no longer important, try to 10561 // clear accessibility focus. 10562 if (mode == IMPORTANT_FOR_ACCESSIBILITY_NO || hideDescendants) { 10563 final View focusHost = findAccessibilityFocusHost(hideDescendants); 10564 if (focusHost != null) { 10565 focusHost.clearAccessibilityFocus(); 10566 } 10567 } 10568 10569 // If we're moving between AUTO and another state, we might not need 10570 // to send a subtree changed notification. We'll store the computed 10571 // importance, since we'll need to check it later to make sure. 10572 final boolean maySkipNotify = oldMode == IMPORTANT_FOR_ACCESSIBILITY_AUTO 10573 || mode == IMPORTANT_FOR_ACCESSIBILITY_AUTO; 10574 final boolean oldIncludeForAccessibility = maySkipNotify && includeForAccessibility(); 10575 mPrivateFlags2 &= ~PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK; 10576 mPrivateFlags2 |= (mode << PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT) 10577 & PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK; 10578 if (!maySkipNotify || oldIncludeForAccessibility != includeForAccessibility()) { 10579 notifySubtreeAccessibilityStateChangedIfNeeded(); 10580 } else { 10581 notifyViewAccessibilityStateChangedIfNeeded( 10582 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 10583 } 10584 } 10585 } 10586 10587 /** 10588 * Returns the view within this view's hierarchy that is hosting 10589 * accessibility focus. 10590 * 10591 * @param searchDescendants whether to search for focus in descendant views 10592 * @return the view hosting accessibility focus, or {@code null} 10593 */ 10594 private View findAccessibilityFocusHost(boolean searchDescendants) { 10595 if (isAccessibilityFocusedViewOrHost()) { 10596 return this; 10597 } 10598 10599 if (searchDescendants) { 10600 final ViewRootImpl viewRoot = getViewRootImpl(); 10601 if (viewRoot != null) { 10602 final View focusHost = viewRoot.getAccessibilityFocusedHost(); 10603 if (focusHost != null && ViewRootImpl.isViewDescendantOf(focusHost, this)) { 10604 return focusHost; 10605 } 10606 } 10607 } 10608 10609 return null; 10610 } 10611 10612 /** 10613 * Computes whether this view should be exposed for accessibility. In 10614 * general, views that are interactive or provide information are exposed 10615 * while views that serve only as containers are hidden. 10616 * <p> 10617 * If an ancestor of this view has importance 10618 * {@link #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS}, this method 10619 * returns <code>false</code>. 10620 * <p> 10621 * Otherwise, the value is computed according to the view's 10622 * {@link #getImportantForAccessibility()} value: 10623 * <ol> 10624 * <li>{@link #IMPORTANT_FOR_ACCESSIBILITY_NO} or 10625 * {@link #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS}, return <code>false 10626 * </code> 10627 * <li>{@link #IMPORTANT_FOR_ACCESSIBILITY_YES}, return <code>true</code> 10628 * <li>{@link #IMPORTANT_FOR_ACCESSIBILITY_AUTO}, return <code>true</code> if 10629 * view satisfies any of the following: 10630 * <ul> 10631 * <li>Is actionable, e.g. {@link #isClickable()}, 10632 * {@link #isLongClickable()}, or {@link #isFocusable()} 10633 * <li>Has an {@link AccessibilityDelegate} 10634 * <li>Has an interaction listener, e.g. {@link OnTouchListener}, 10635 * {@link OnKeyListener}, etc. 10636 * <li>Is an accessibility live region, e.g. 10637 * {@link #getAccessibilityLiveRegion()} is not 10638 * {@link #ACCESSIBILITY_LIVE_REGION_NONE}. 10639 * </ul> 10640 * </ol> 10641 * 10642 * @return Whether the view is exposed for accessibility. 10643 * @see #setImportantForAccessibility(int) 10644 * @see #getImportantForAccessibility() 10645 */ 10646 public boolean isImportantForAccessibility() { 10647 final int mode = (mPrivateFlags2 & PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK) 10648 >> PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT; 10649 if (mode == IMPORTANT_FOR_ACCESSIBILITY_NO 10650 || mode == IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS) { 10651 return false; 10652 } 10653 10654 // Check parent mode to ensure we're not hidden. 10655 ViewParent parent = mParent; 10656 while (parent instanceof View) { 10657 if (((View) parent).getImportantForAccessibility() 10658 == IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS) { 10659 return false; 10660 } 10661 parent = parent.getParent(); 10662 } 10663 10664 return mode == IMPORTANT_FOR_ACCESSIBILITY_YES || isActionableForAccessibility() 10665 || hasListenersForAccessibility() || getAccessibilityNodeProvider() != null 10666 || getAccessibilityLiveRegion() != ACCESSIBILITY_LIVE_REGION_NONE; 10667 } 10668 10669 /** 10670 * Gets the parent for accessibility purposes. Note that the parent for 10671 * accessibility is not necessary the immediate parent. It is the first 10672 * predecessor that is important for accessibility. 10673 * 10674 * @return The parent for accessibility purposes. 10675 */ 10676 public ViewParent getParentForAccessibility() { 10677 if (mParent instanceof View) { 10678 View parentView = (View) mParent; 10679 if (parentView.includeForAccessibility()) { 10680 return mParent; 10681 } else { 10682 return mParent.getParentForAccessibility(); 10683 } 10684 } 10685 return null; 10686 } 10687 10688 /** 10689 * Adds the children of this View relevant for accessibility to the given list 10690 * as output. Since some Views are not important for accessibility the added 10691 * child views are not necessarily direct children of this view, rather they are 10692 * the first level of descendants important for accessibility. 10693 * 10694 * @param outChildren The output list that will receive children for accessibility. 10695 */ 10696 public void addChildrenForAccessibility(ArrayList<View> outChildren) { 10697 10698 } 10699 10700 /** 10701 * Whether to regard this view for accessibility. A view is regarded for 10702 * accessibility if it is important for accessibility or the querying 10703 * accessibility service has explicitly requested that view not 10704 * important for accessibility are regarded. 10705 * 10706 * @return Whether to regard the view for accessibility. 10707 * 10708 * @hide 10709 */ 10710 public boolean includeForAccessibility() { 10711 if (mAttachInfo != null) { 10712 return (mAttachInfo.mAccessibilityFetchFlags 10713 & AccessibilityNodeInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS) != 0 10714 || isImportantForAccessibility(); 10715 } 10716 return false; 10717 } 10718 10719 /** 10720 * Returns whether the View is considered actionable from 10721 * accessibility perspective. Such view are important for 10722 * accessibility. 10723 * 10724 * @return True if the view is actionable for accessibility. 10725 * 10726 * @hide 10727 */ 10728 public boolean isActionableForAccessibility() { 10729 return (isClickable() || isLongClickable() || isFocusable()); 10730 } 10731 10732 /** 10733 * Returns whether the View has registered callbacks which makes it 10734 * important for accessibility. 10735 * 10736 * @return True if the view is actionable for accessibility. 10737 */ 10738 private boolean hasListenersForAccessibility() { 10739 ListenerInfo info = getListenerInfo(); 10740 return mTouchDelegate != null || info.mOnKeyListener != null 10741 || info.mOnTouchListener != null || info.mOnGenericMotionListener != null 10742 || info.mOnHoverListener != null || info.mOnDragListener != null; 10743 } 10744 10745 /** 10746 * Notifies that the accessibility state of this view changed. The change 10747 * is local to this view and does not represent structural changes such 10748 * as children and parent. For example, the view became focusable. The 10749 * notification is at at most once every 10750 * {@link ViewConfiguration#getSendRecurringAccessibilityEventsInterval()} 10751 * to avoid unnecessary load to the system. Also once a view has a pending 10752 * notification this method is a NOP until the notification has been sent. 10753 * 10754 * @hide 10755 */ 10756 public void notifyViewAccessibilityStateChangedIfNeeded(int changeType) { 10757 if (!AccessibilityManager.getInstance(mContext).isEnabled() || mAttachInfo == null) { 10758 return; 10759 } 10760 if (mSendViewStateChangedAccessibilityEvent == null) { 10761 mSendViewStateChangedAccessibilityEvent = 10762 new SendViewStateChangedAccessibilityEvent(); 10763 } 10764 mSendViewStateChangedAccessibilityEvent.runOrPost(changeType); 10765 } 10766 10767 /** 10768 * Notifies that the accessibility state of this view changed. The change 10769 * is *not* local to this view and does represent structural changes such 10770 * as children and parent. For example, the view size changed. The 10771 * notification is at at most once every 10772 * {@link ViewConfiguration#getSendRecurringAccessibilityEventsInterval()} 10773 * to avoid unnecessary load to the system. Also once a view has a pending 10774 * notification this method is a NOP until the notification has been sent. 10775 * 10776 * @hide 10777 */ 10778 public void notifySubtreeAccessibilityStateChangedIfNeeded() { 10779 if (!AccessibilityManager.getInstance(mContext).isEnabled() || mAttachInfo == null) { 10780 return; 10781 } 10782 if ((mPrivateFlags2 & PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED) == 0) { 10783 mPrivateFlags2 |= PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED; 10784 if (mParent != null) { 10785 try { 10786 mParent.notifySubtreeAccessibilityStateChanged( 10787 this, this, AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE); 10788 } catch (AbstractMethodError e) { 10789 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 10790 " does not fully implement ViewParent", e); 10791 } 10792 } 10793 } 10794 } 10795 10796 /** 10797 * Change the visibility of the View without triggering any other changes. This is 10798 * important for transitions, where visibility changes should not adjust focus or 10799 * trigger a new layout. This is only used when the visibility has already been changed 10800 * and we need a transient value during an animation. When the animation completes, 10801 * the original visibility value is always restored. 10802 * 10803 * @param visibility One of {@link #VISIBLE}, {@link #INVISIBLE}, or {@link #GONE}. 10804 * @hide 10805 */ 10806 public void setTransitionVisibility(@Visibility int visibility) { 10807 mViewFlags = (mViewFlags & ~View.VISIBILITY_MASK) | visibility; 10808 } 10809 10810 /** 10811 * Reset the flag indicating the accessibility state of the subtree rooted 10812 * at this view changed. 10813 */ 10814 void resetSubtreeAccessibilityStateChanged() { 10815 mPrivateFlags2 &= ~PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED; 10816 } 10817 10818 /** 10819 * Report an accessibility action to this view's parents for delegated processing. 10820 * 10821 * <p>Implementations of {@link #performAccessibilityAction(int, Bundle)} may internally 10822 * call this method to delegate an accessibility action to a supporting parent. If the parent 10823 * returns true from its 10824 * {@link ViewParent#onNestedPrePerformAccessibilityAction(View, int, android.os.Bundle)} 10825 * method this method will return true to signify that the action was consumed.</p> 10826 * 10827 * <p>This method is useful for implementing nested scrolling child views. If 10828 * {@link #isNestedScrollingEnabled()} returns true and the action is a scrolling action 10829 * a custom view implementation may invoke this method to allow a parent to consume the 10830 * scroll first. If this method returns true the custom view should skip its own scrolling 10831 * behavior.</p> 10832 * 10833 * @param action Accessibility action to delegate 10834 * @param arguments Optional action arguments 10835 * @return true if the action was consumed by a parent 10836 */ 10837 public boolean dispatchNestedPrePerformAccessibilityAction(int action, Bundle arguments) { 10838 for (ViewParent p = getParent(); p != null; p = p.getParent()) { 10839 if (p.onNestedPrePerformAccessibilityAction(this, action, arguments)) { 10840 return true; 10841 } 10842 } 10843 return false; 10844 } 10845 10846 /** 10847 * Performs the specified accessibility action on the view. For 10848 * possible accessibility actions look at {@link AccessibilityNodeInfo}. 10849 * <p> 10850 * If an {@link AccessibilityDelegate} has been specified via calling 10851 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 10852 * {@link AccessibilityDelegate#performAccessibilityAction(View, int, Bundle)} 10853 * is responsible for handling this call. 10854 * </p> 10855 * 10856 * <p>The default implementation will delegate 10857 * {@link AccessibilityNodeInfo#ACTION_SCROLL_BACKWARD} and 10858 * {@link AccessibilityNodeInfo#ACTION_SCROLL_FORWARD} to nested scrolling parents if 10859 * {@link #isNestedScrollingEnabled() nested scrolling is enabled} on this view.</p> 10860 * 10861 * @param action The action to perform. 10862 * @param arguments Optional action arguments. 10863 * @return Whether the action was performed. 10864 */ 10865 public boolean performAccessibilityAction(int action, Bundle arguments) { 10866 if (mAccessibilityDelegate != null) { 10867 return mAccessibilityDelegate.performAccessibilityAction(this, action, arguments); 10868 } else { 10869 return performAccessibilityActionInternal(action, arguments); 10870 } 10871 } 10872 10873 /** 10874 * @see #performAccessibilityAction(int, Bundle) 10875 * 10876 * Note: Called from the default {@link AccessibilityDelegate}. 10877 * 10878 * @hide 10879 */ 10880 public boolean performAccessibilityActionInternal(int action, Bundle arguments) { 10881 if (isNestedScrollingEnabled() 10882 && (action == AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD 10883 || action == AccessibilityNodeInfo.ACTION_SCROLL_FORWARD 10884 || action == R.id.accessibilityActionScrollUp 10885 || action == R.id.accessibilityActionScrollLeft 10886 || action == R.id.accessibilityActionScrollDown 10887 || action == R.id.accessibilityActionScrollRight)) { 10888 if (dispatchNestedPrePerformAccessibilityAction(action, arguments)) { 10889 return true; 10890 } 10891 } 10892 10893 switch (action) { 10894 case AccessibilityNodeInfo.ACTION_CLICK: { 10895 if (isClickable()) { 10896 performClick(); 10897 return true; 10898 } 10899 } break; 10900 case AccessibilityNodeInfo.ACTION_LONG_CLICK: { 10901 if (isLongClickable()) { 10902 performLongClick(); 10903 return true; 10904 } 10905 } break; 10906 case AccessibilityNodeInfo.ACTION_FOCUS: { 10907 if (!hasFocus()) { 10908 // Get out of touch mode since accessibility 10909 // wants to move focus around. 10910 getViewRootImpl().ensureTouchMode(false); 10911 return requestFocus(); 10912 } 10913 } break; 10914 case AccessibilityNodeInfo.ACTION_CLEAR_FOCUS: { 10915 if (hasFocus()) { 10916 clearFocus(); 10917 return !isFocused(); 10918 } 10919 } break; 10920 case AccessibilityNodeInfo.ACTION_SELECT: { 10921 if (!isSelected()) { 10922 setSelected(true); 10923 return isSelected(); 10924 } 10925 } break; 10926 case AccessibilityNodeInfo.ACTION_CLEAR_SELECTION: { 10927 if (isSelected()) { 10928 setSelected(false); 10929 return !isSelected(); 10930 } 10931 } break; 10932 case AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS: { 10933 if (!isAccessibilityFocused()) { 10934 return requestAccessibilityFocus(); 10935 } 10936 } break; 10937 case AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS: { 10938 if (isAccessibilityFocused()) { 10939 clearAccessibilityFocus(); 10940 return true; 10941 } 10942 } break; 10943 case AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY: { 10944 if (arguments != null) { 10945 final int granularity = arguments.getInt( 10946 AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT); 10947 final boolean extendSelection = arguments.getBoolean( 10948 AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN); 10949 return traverseAtGranularity(granularity, true, extendSelection); 10950 } 10951 } break; 10952 case AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY: { 10953 if (arguments != null) { 10954 final int granularity = arguments.getInt( 10955 AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT); 10956 final boolean extendSelection = arguments.getBoolean( 10957 AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN); 10958 return traverseAtGranularity(granularity, false, extendSelection); 10959 } 10960 } break; 10961 case AccessibilityNodeInfo.ACTION_SET_SELECTION: { 10962 CharSequence text = getIterableTextForAccessibility(); 10963 if (text == null) { 10964 return false; 10965 } 10966 final int start = (arguments != null) ? arguments.getInt( 10967 AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT, -1) : -1; 10968 final int end = (arguments != null) ? arguments.getInt( 10969 AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT, -1) : -1; 10970 // Only cursor position can be specified (selection length == 0) 10971 if ((getAccessibilitySelectionStart() != start 10972 || getAccessibilitySelectionEnd() != end) 10973 && (start == end)) { 10974 setAccessibilitySelection(start, end); 10975 notifyViewAccessibilityStateChangedIfNeeded( 10976 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 10977 return true; 10978 } 10979 } break; 10980 case R.id.accessibilityActionShowOnScreen: { 10981 if (mAttachInfo != null) { 10982 final Rect r = mAttachInfo.mTmpInvalRect; 10983 getDrawingRect(r); 10984 return requestRectangleOnScreen(r, true); 10985 } 10986 } break; 10987 case R.id.accessibilityActionContextClick: { 10988 if (isContextClickable()) { 10989 performContextClick(); 10990 return true; 10991 } 10992 } break; 10993 } 10994 return false; 10995 } 10996 10997 private boolean traverseAtGranularity(int granularity, boolean forward, 10998 boolean extendSelection) { 10999 CharSequence text = getIterableTextForAccessibility(); 11000 if (text == null || text.length() == 0) { 11001 return false; 11002 } 11003 TextSegmentIterator iterator = getIteratorForGranularity(granularity); 11004 if (iterator == null) { 11005 return false; 11006 } 11007 int current = getAccessibilitySelectionEnd(); 11008 if (current == ACCESSIBILITY_CURSOR_POSITION_UNDEFINED) { 11009 current = forward ? 0 : text.length(); 11010 } 11011 final int[] range = forward ? iterator.following(current) : iterator.preceding(current); 11012 if (range == null) { 11013 return false; 11014 } 11015 final int segmentStart = range[0]; 11016 final int segmentEnd = range[1]; 11017 int selectionStart; 11018 int selectionEnd; 11019 if (extendSelection && isAccessibilitySelectionExtendable()) { 11020 selectionStart = getAccessibilitySelectionStart(); 11021 if (selectionStart == ACCESSIBILITY_CURSOR_POSITION_UNDEFINED) { 11022 selectionStart = forward ? segmentStart : segmentEnd; 11023 } 11024 selectionEnd = forward ? segmentEnd : segmentStart; 11025 } else { 11026 selectionStart = selectionEnd= forward ? segmentEnd : segmentStart; 11027 } 11028 setAccessibilitySelection(selectionStart, selectionEnd); 11029 final int action = forward ? AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY 11030 : AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY; 11031 sendViewTextTraversedAtGranularityEvent(action, granularity, segmentStart, segmentEnd); 11032 return true; 11033 } 11034 11035 /** 11036 * Gets the text reported for accessibility purposes. 11037 * 11038 * @return The accessibility text. 11039 * 11040 * @hide 11041 */ 11042 public CharSequence getIterableTextForAccessibility() { 11043 return getContentDescription(); 11044 } 11045 11046 /** 11047 * Gets whether accessibility selection can be extended. 11048 * 11049 * @return If selection is extensible. 11050 * 11051 * @hide 11052 */ 11053 public boolean isAccessibilitySelectionExtendable() { 11054 return false; 11055 } 11056 11057 /** 11058 * @hide 11059 */ 11060 public int getAccessibilitySelectionStart() { 11061 return mAccessibilityCursorPosition; 11062 } 11063 11064 /** 11065 * @hide 11066 */ 11067 public int getAccessibilitySelectionEnd() { 11068 return getAccessibilitySelectionStart(); 11069 } 11070 11071 /** 11072 * @hide 11073 */ 11074 public void setAccessibilitySelection(int start, int end) { 11075 if (start == end && end == mAccessibilityCursorPosition) { 11076 return; 11077 } 11078 if (start >= 0 && start == end && end <= getIterableTextForAccessibility().length()) { 11079 mAccessibilityCursorPosition = start; 11080 } else { 11081 mAccessibilityCursorPosition = ACCESSIBILITY_CURSOR_POSITION_UNDEFINED; 11082 } 11083 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED); 11084 } 11085 11086 private void sendViewTextTraversedAtGranularityEvent(int action, int granularity, 11087 int fromIndex, int toIndex) { 11088 if (mParent == null) { 11089 return; 11090 } 11091 AccessibilityEvent event = AccessibilityEvent.obtain( 11092 AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY); 11093 onInitializeAccessibilityEvent(event); 11094 onPopulateAccessibilityEvent(event); 11095 event.setFromIndex(fromIndex); 11096 event.setToIndex(toIndex); 11097 event.setAction(action); 11098 event.setMovementGranularity(granularity); 11099 mParent.requestSendAccessibilityEvent(this, event); 11100 } 11101 11102 /** 11103 * @hide 11104 */ 11105 public TextSegmentIterator getIteratorForGranularity(int granularity) { 11106 switch (granularity) { 11107 case AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER: { 11108 CharSequence text = getIterableTextForAccessibility(); 11109 if (text != null && text.length() > 0) { 11110 CharacterTextSegmentIterator iterator = 11111 CharacterTextSegmentIterator.getInstance( 11112 mContext.getResources().getConfiguration().locale); 11113 iterator.initialize(text.toString()); 11114 return iterator; 11115 } 11116 } break; 11117 case AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD: { 11118 CharSequence text = getIterableTextForAccessibility(); 11119 if (text != null && text.length() > 0) { 11120 WordTextSegmentIterator iterator = 11121 WordTextSegmentIterator.getInstance( 11122 mContext.getResources().getConfiguration().locale); 11123 iterator.initialize(text.toString()); 11124 return iterator; 11125 } 11126 } break; 11127 case AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH: { 11128 CharSequence text = getIterableTextForAccessibility(); 11129 if (text != null && text.length() > 0) { 11130 ParagraphTextSegmentIterator iterator = 11131 ParagraphTextSegmentIterator.getInstance(); 11132 iterator.initialize(text.toString()); 11133 return iterator; 11134 } 11135 } break; 11136 } 11137 return null; 11138 } 11139 11140 /** 11141 * Tells whether the {@link View} is in the state between {@link #onStartTemporaryDetach()} 11142 * and {@link #onFinishTemporaryDetach()}. 11143 * 11144 * <p>This method always returns {@code true} when called directly or indirectly from 11145 * {@link #onStartTemporaryDetach()}. The return value when called directly or indirectly from 11146 * {@link #onFinishTemporaryDetach()}, however, depends on the OS version. 11147 * <ul> 11148 * <li>{@code true} on {@link android.os.Build.VERSION_CODES#N API 24}</li> 11149 * <li>{@code false} on {@link android.os.Build.VERSION_CODES#N_MR1 API 25}} and later</li> 11150 * </ul> 11151 * </p> 11152 * 11153 * @return {@code true} when the View is in the state between {@link #onStartTemporaryDetach()} 11154 * and {@link #onFinishTemporaryDetach()}. 11155 */ 11156 public final boolean isTemporarilyDetached() { 11157 return (mPrivateFlags3 & PFLAG3_TEMPORARY_DETACH) != 0; 11158 } 11159 11160 /** 11161 * Dispatch {@link #onStartTemporaryDetach()} to this View and its direct children if this is 11162 * a container View. 11163 */ 11164 @CallSuper 11165 public void dispatchStartTemporaryDetach() { 11166 mPrivateFlags3 |= PFLAG3_TEMPORARY_DETACH; 11167 notifyEnterOrExitForAutoFillIfNeeded(false); 11168 onStartTemporaryDetach(); 11169 } 11170 11171 /** 11172 * This is called when a container is going to temporarily detach a child, with 11173 * {@link ViewGroup#detachViewFromParent(View) ViewGroup.detachViewFromParent}. 11174 * It will either be followed by {@link #onFinishTemporaryDetach()} or 11175 * {@link #onDetachedFromWindow()} when the container is done. 11176 */ 11177 public void onStartTemporaryDetach() { 11178 removeUnsetPressCallback(); 11179 mPrivateFlags |= PFLAG_CANCEL_NEXT_UP_EVENT; 11180 } 11181 11182 /** 11183 * Dispatch {@link #onFinishTemporaryDetach()} to this View and its direct children if this is 11184 * a container View. 11185 */ 11186 @CallSuper 11187 public void dispatchFinishTemporaryDetach() { 11188 mPrivateFlags3 &= ~PFLAG3_TEMPORARY_DETACH; 11189 onFinishTemporaryDetach(); 11190 if (hasWindowFocus() && hasFocus()) { 11191 InputMethodManager.getInstance().focusIn(this); 11192 } 11193 notifyEnterOrExitForAutoFillIfNeeded(true); 11194 } 11195 11196 /** 11197 * Called after {@link #onStartTemporaryDetach} when the container is done 11198 * changing the view. 11199 */ 11200 public void onFinishTemporaryDetach() { 11201 } 11202 11203 /** 11204 * Return the global {@link KeyEvent.DispatcherState KeyEvent.DispatcherState} 11205 * for this view's window. Returns null if the view is not currently attached 11206 * to the window. Normally you will not need to use this directly, but 11207 * just use the standard high-level event callbacks like 11208 * {@link #onKeyDown(int, KeyEvent)}. 11209 */ 11210 public KeyEvent.DispatcherState getKeyDispatcherState() { 11211 return mAttachInfo != null ? mAttachInfo.mKeyDispatchState : null; 11212 } 11213 11214 /** 11215 * Dispatch a key event before it is processed by any input method 11216 * associated with the view hierarchy. This can be used to intercept 11217 * key events in special situations before the IME consumes them; a 11218 * typical example would be handling the BACK key to update the application's 11219 * UI instead of allowing the IME to see it and close itself. 11220 * 11221 * @param event The key event to be dispatched. 11222 * @return True if the event was handled, false otherwise. 11223 */ 11224 public boolean dispatchKeyEventPreIme(KeyEvent event) { 11225 return onKeyPreIme(event.getKeyCode(), event); 11226 } 11227 11228 /** 11229 * Dispatch a key event to the next view on the focus path. This path runs 11230 * from the top of the view tree down to the currently focused view. If this 11231 * view has focus, it will dispatch to itself. Otherwise it will dispatch 11232 * the next node down the focus path. This method also fires any key 11233 * listeners. 11234 * 11235 * @param event The key event to be dispatched. 11236 * @return True if the event was handled, false otherwise. 11237 */ 11238 public boolean dispatchKeyEvent(KeyEvent event) { 11239 if (mInputEventConsistencyVerifier != null) { 11240 mInputEventConsistencyVerifier.onKeyEvent(event, 0); 11241 } 11242 11243 // Give any attached key listener a first crack at the event. 11244 //noinspection SimplifiableIfStatement 11245 ListenerInfo li = mListenerInfo; 11246 if (li != null && li.mOnKeyListener != null && (mViewFlags & ENABLED_MASK) == ENABLED 11247 && li.mOnKeyListener.onKey(this, event.getKeyCode(), event)) { 11248 return true; 11249 } 11250 11251 if (event.dispatch(this, mAttachInfo != null 11252 ? mAttachInfo.mKeyDispatchState : null, this)) { 11253 return true; 11254 } 11255 11256 if (mInputEventConsistencyVerifier != null) { 11257 mInputEventConsistencyVerifier.onUnhandledEvent(event, 0); 11258 } 11259 return false; 11260 } 11261 11262 /** 11263 * Dispatches a key shortcut event. 11264 * 11265 * @param event The key event to be dispatched. 11266 * @return True if the event was handled by the view, false otherwise. 11267 */ 11268 public boolean dispatchKeyShortcutEvent(KeyEvent event) { 11269 return onKeyShortcut(event.getKeyCode(), event); 11270 } 11271 11272 /** 11273 * Pass the touch screen motion event down to the target view, or this 11274 * view if it is the target. 11275 * 11276 * @param event The motion event to be dispatched. 11277 * @return True if the event was handled by the view, false otherwise. 11278 */ 11279 public boolean dispatchTouchEvent(MotionEvent event) { 11280 // If the event should be handled by accessibility focus first. 11281 if (event.isTargetAccessibilityFocus()) { 11282 // We don't have focus or no virtual descendant has it, do not handle the event. 11283 if (!isAccessibilityFocusedViewOrHost()) { 11284 return false; 11285 } 11286 // We have focus and got the event, then use normal event dispatch. 11287 event.setTargetAccessibilityFocus(false); 11288 } 11289 11290 boolean result = false; 11291 11292 if (mInputEventConsistencyVerifier != null) { 11293 mInputEventConsistencyVerifier.onTouchEvent(event, 0); 11294 } 11295 11296 final int actionMasked = event.getActionMasked(); 11297 if (actionMasked == MotionEvent.ACTION_DOWN) { 11298 // Defensive cleanup for new gesture 11299 stopNestedScroll(); 11300 } 11301 11302 if (onFilterTouchEventForSecurity(event)) { 11303 if ((mViewFlags & ENABLED_MASK) == ENABLED && handleScrollBarDragging(event)) { 11304 result = true; 11305 } 11306 //noinspection SimplifiableIfStatement 11307 ListenerInfo li = mListenerInfo; 11308 if (li != null && li.mOnTouchListener != null 11309 && (mViewFlags & ENABLED_MASK) == ENABLED 11310 && li.mOnTouchListener.onTouch(this, event)) { 11311 result = true; 11312 } 11313 11314 if (!result && onTouchEvent(event)) { 11315 result = true; 11316 } 11317 } 11318 11319 if (!result && mInputEventConsistencyVerifier != null) { 11320 mInputEventConsistencyVerifier.onUnhandledEvent(event, 0); 11321 } 11322 11323 // Clean up after nested scrolls if this is the end of a gesture; 11324 // also cancel it if we tried an ACTION_DOWN but we didn't want the rest 11325 // of the gesture. 11326 if (actionMasked == MotionEvent.ACTION_UP || 11327 actionMasked == MotionEvent.ACTION_CANCEL || 11328 (actionMasked == MotionEvent.ACTION_DOWN && !result)) { 11329 stopNestedScroll(); 11330 } 11331 11332 return result; 11333 } 11334 11335 boolean isAccessibilityFocusedViewOrHost() { 11336 return isAccessibilityFocused() || (getViewRootImpl() != null && getViewRootImpl() 11337 .getAccessibilityFocusedHost() == this); 11338 } 11339 11340 /** 11341 * Filter the touch event to apply security policies. 11342 * 11343 * @param event The motion event to be filtered. 11344 * @return True if the event should be dispatched, false if the event should be dropped. 11345 * 11346 * @see #getFilterTouchesWhenObscured 11347 */ 11348 public boolean onFilterTouchEventForSecurity(MotionEvent event) { 11349 //noinspection RedundantIfStatement 11350 if ((mViewFlags & FILTER_TOUCHES_WHEN_OBSCURED) != 0 11351 && (event.getFlags() & MotionEvent.FLAG_WINDOW_IS_OBSCURED) != 0) { 11352 // Window is obscured, drop this touch. 11353 return false; 11354 } 11355 return true; 11356 } 11357 11358 /** 11359 * Pass a trackball motion event down to the focused view. 11360 * 11361 * @param event The motion event to be dispatched. 11362 * @return True if the event was handled by the view, false otherwise. 11363 */ 11364 public boolean dispatchTrackballEvent(MotionEvent event) { 11365 if (mInputEventConsistencyVerifier != null) { 11366 mInputEventConsistencyVerifier.onTrackballEvent(event, 0); 11367 } 11368 11369 return onTrackballEvent(event); 11370 } 11371 11372 /** 11373 * Pass a captured pointer event down to the focused view. 11374 * 11375 * @param event The motion event to be dispatched. 11376 * @return True if the event was handled by the view, false otherwise. 11377 */ 11378 public boolean dispatchCapturedPointerEvent(MotionEvent event) { 11379 if (!hasPointerCapture()) { 11380 return false; 11381 } 11382 //noinspection SimplifiableIfStatement 11383 ListenerInfo li = mListenerInfo; 11384 if (li != null && li.mOnCapturedPointerListener != null 11385 && li.mOnCapturedPointerListener.onCapturedPointer(this, event)) { 11386 return true; 11387 } 11388 return onCapturedPointerEvent(event); 11389 } 11390 11391 /** 11392 * Dispatch a generic motion event. 11393 * <p> 11394 * Generic motion events with source class {@link InputDevice#SOURCE_CLASS_POINTER} 11395 * are delivered to the view under the pointer. All other generic motion events are 11396 * delivered to the focused view. Hover events are handled specially and are delivered 11397 * to {@link #onHoverEvent(MotionEvent)}. 11398 * </p> 11399 * 11400 * @param event The motion event to be dispatched. 11401 * @return True if the event was handled by the view, false otherwise. 11402 */ 11403 public boolean dispatchGenericMotionEvent(MotionEvent event) { 11404 if (mInputEventConsistencyVerifier != null) { 11405 mInputEventConsistencyVerifier.onGenericMotionEvent(event, 0); 11406 } 11407 11408 final int source = event.getSource(); 11409 if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) { 11410 final int action = event.getAction(); 11411 if (action == MotionEvent.ACTION_HOVER_ENTER 11412 || action == MotionEvent.ACTION_HOVER_MOVE 11413 || action == MotionEvent.ACTION_HOVER_EXIT) { 11414 if (dispatchHoverEvent(event)) { 11415 return true; 11416 } 11417 } else if (dispatchGenericPointerEvent(event)) { 11418 return true; 11419 } 11420 } else if (dispatchGenericFocusedEvent(event)) { 11421 return true; 11422 } 11423 11424 if (dispatchGenericMotionEventInternal(event)) { 11425 return true; 11426 } 11427 11428 if (mInputEventConsistencyVerifier != null) { 11429 mInputEventConsistencyVerifier.onUnhandledEvent(event, 0); 11430 } 11431 return false; 11432 } 11433 11434 private boolean dispatchGenericMotionEventInternal(MotionEvent event) { 11435 //noinspection SimplifiableIfStatement 11436 ListenerInfo li = mListenerInfo; 11437 if (li != null && li.mOnGenericMotionListener != null 11438 && (mViewFlags & ENABLED_MASK) == ENABLED 11439 && li.mOnGenericMotionListener.onGenericMotion(this, event)) { 11440 return true; 11441 } 11442 11443 if (onGenericMotionEvent(event)) { 11444 return true; 11445 } 11446 11447 final int actionButton = event.getActionButton(); 11448 switch (event.getActionMasked()) { 11449 case MotionEvent.ACTION_BUTTON_PRESS: 11450 if (isContextClickable() && !mInContextButtonPress && !mHasPerformedLongPress 11451 && (actionButton == MotionEvent.BUTTON_STYLUS_PRIMARY 11452 || actionButton == MotionEvent.BUTTON_SECONDARY)) { 11453 if (performContextClick(event.getX(), event.getY())) { 11454 mInContextButtonPress = true; 11455 setPressed(true, event.getX(), event.getY()); 11456 removeTapCallback(); 11457 removeLongPressCallback(); 11458 return true; 11459 } 11460 } 11461 break; 11462 11463 case MotionEvent.ACTION_BUTTON_RELEASE: 11464 if (mInContextButtonPress && (actionButton == MotionEvent.BUTTON_STYLUS_PRIMARY 11465 || actionButton == MotionEvent.BUTTON_SECONDARY)) { 11466 mInContextButtonPress = false; 11467 mIgnoreNextUpEvent = true; 11468 } 11469 break; 11470 } 11471 11472 if (mInputEventConsistencyVerifier != null) { 11473 mInputEventConsistencyVerifier.onUnhandledEvent(event, 0); 11474 } 11475 return false; 11476 } 11477 11478 /** 11479 * Dispatch a hover event. 11480 * <p> 11481 * Do not call this method directly. 11482 * Call {@link #dispatchGenericMotionEvent(MotionEvent)} instead. 11483 * </p> 11484 * 11485 * @param event The motion event to be dispatched. 11486 * @return True if the event was handled by the view, false otherwise. 11487 */ 11488 protected boolean dispatchHoverEvent(MotionEvent event) { 11489 ListenerInfo li = mListenerInfo; 11490 //noinspection SimplifiableIfStatement 11491 if (li != null && li.mOnHoverListener != null 11492 && (mViewFlags & ENABLED_MASK) == ENABLED 11493 && li.mOnHoverListener.onHover(this, event)) { 11494 return true; 11495 } 11496 11497 return onHoverEvent(event); 11498 } 11499 11500 /** 11501 * Returns true if the view has a child to which it has recently sent 11502 * {@link MotionEvent#ACTION_HOVER_ENTER}. If this view is hovered and 11503 * it does not have a hovered child, then it must be the innermost hovered view. 11504 * @hide 11505 */ 11506 protected boolean hasHoveredChild() { 11507 return false; 11508 } 11509 11510 /** 11511 * Dispatch a generic motion event to the view under the first pointer. 11512 * <p> 11513 * Do not call this method directly. 11514 * Call {@link #dispatchGenericMotionEvent(MotionEvent)} instead. 11515 * </p> 11516 * 11517 * @param event The motion event to be dispatched. 11518 * @return True if the event was handled by the view, false otherwise. 11519 */ 11520 protected boolean dispatchGenericPointerEvent(MotionEvent event) { 11521 return false; 11522 } 11523 11524 /** 11525 * Dispatch a generic motion event to the currently focused view. 11526 * <p> 11527 * Do not call this method directly. 11528 * Call {@link #dispatchGenericMotionEvent(MotionEvent)} instead. 11529 * </p> 11530 * 11531 * @param event The motion event to be dispatched. 11532 * @return True if the event was handled by the view, false otherwise. 11533 */ 11534 protected boolean dispatchGenericFocusedEvent(MotionEvent event) { 11535 return false; 11536 } 11537 11538 /** 11539 * Dispatch a pointer event. 11540 * <p> 11541 * Dispatches touch related pointer events to {@link #onTouchEvent(MotionEvent)} and all 11542 * other events to {@link #onGenericMotionEvent(MotionEvent)}. This separation of concerns 11543 * reinforces the invariant that {@link #onTouchEvent(MotionEvent)} is really about touches 11544 * and should not be expected to handle other pointing device features. 11545 * </p> 11546 * 11547 * @param event The motion event to be dispatched. 11548 * @return True if the event was handled by the view, false otherwise. 11549 * @hide 11550 */ 11551 public final boolean dispatchPointerEvent(MotionEvent event) { 11552 if (event.isTouchEvent()) { 11553 return dispatchTouchEvent(event); 11554 } else { 11555 return dispatchGenericMotionEvent(event); 11556 } 11557 } 11558 11559 /** 11560 * Called when the window containing this view gains or loses window focus. 11561 * ViewGroups should override to route to their children. 11562 * 11563 * @param hasFocus True if the window containing this view now has focus, 11564 * false otherwise. 11565 */ 11566 public void dispatchWindowFocusChanged(boolean hasFocus) { 11567 onWindowFocusChanged(hasFocus); 11568 } 11569 11570 /** 11571 * Called when the window containing this view gains or loses focus. Note 11572 * that this is separate from view focus: to receive key events, both 11573 * your view and its window must have focus. If a window is displayed 11574 * on top of yours that takes input focus, then your own window will lose 11575 * focus but the view focus will remain unchanged. 11576 * 11577 * @param hasWindowFocus True if the window containing this view now has 11578 * focus, false otherwise. 11579 */ 11580 public void onWindowFocusChanged(boolean hasWindowFocus) { 11581 InputMethodManager imm = InputMethodManager.peekInstance(); 11582 if (!hasWindowFocus) { 11583 if (isPressed()) { 11584 setPressed(false); 11585 } 11586 mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN; 11587 if (imm != null && (mPrivateFlags & PFLAG_FOCUSED) != 0) { 11588 imm.focusOut(this); 11589 } 11590 removeLongPressCallback(); 11591 removeTapCallback(); 11592 onFocusLost(); 11593 } else if (imm != null && (mPrivateFlags & PFLAG_FOCUSED) != 0) { 11594 imm.focusIn(this); 11595 } 11596 11597 notifyEnterOrExitForAutoFillIfNeeded(hasWindowFocus); 11598 11599 refreshDrawableState(); 11600 } 11601 11602 /** 11603 * Returns true if this view is in a window that currently has window focus. 11604 * Note that this is not the same as the view itself having focus. 11605 * 11606 * @return True if this view is in a window that currently has window focus. 11607 */ 11608 public boolean hasWindowFocus() { 11609 return mAttachInfo != null && mAttachInfo.mHasWindowFocus; 11610 } 11611 11612 /** 11613 * Dispatch a view visibility change down the view hierarchy. 11614 * ViewGroups should override to route to their children. 11615 * @param changedView The view whose visibility changed. Could be 'this' or 11616 * an ancestor view. 11617 * @param visibility The new visibility of changedView: {@link #VISIBLE}, 11618 * {@link #INVISIBLE} or {@link #GONE}. 11619 */ 11620 protected void dispatchVisibilityChanged(@NonNull View changedView, 11621 @Visibility int visibility) { 11622 onVisibilityChanged(changedView, visibility); 11623 } 11624 11625 /** 11626 * Called when the visibility of the view or an ancestor of the view has 11627 * changed. 11628 * 11629 * @param changedView The view whose visibility changed. May be 11630 * {@code this} or an ancestor view. 11631 * @param visibility The new visibility, one of {@link #VISIBLE}, 11632 * {@link #INVISIBLE} or {@link #GONE}. 11633 */ 11634 protected void onVisibilityChanged(@NonNull View changedView, @Visibility int visibility) { 11635 } 11636 11637 /** 11638 * Dispatch a hint about whether this view is displayed. For instance, when 11639 * a View moves out of the screen, it might receives a display hint indicating 11640 * the view is not displayed. Applications should not <em>rely</em> on this hint 11641 * as there is no guarantee that they will receive one. 11642 * 11643 * @param hint A hint about whether or not this view is displayed: 11644 * {@link #VISIBLE} or {@link #INVISIBLE}. 11645 */ 11646 public void dispatchDisplayHint(@Visibility int hint) { 11647 onDisplayHint(hint); 11648 } 11649 11650 /** 11651 * Gives this view a hint about whether is displayed or not. For instance, when 11652 * a View moves out of the screen, it might receives a display hint indicating 11653 * the view is not displayed. Applications should not <em>rely</em> on this hint 11654 * as there is no guarantee that they will receive one. 11655 * 11656 * @param hint A hint about whether or not this view is displayed: 11657 * {@link #VISIBLE} or {@link #INVISIBLE}. 11658 */ 11659 protected void onDisplayHint(@Visibility int hint) { 11660 } 11661 11662 /** 11663 * Dispatch a window visibility change down the view hierarchy. 11664 * ViewGroups should override to route to their children. 11665 * 11666 * @param visibility The new visibility of the window. 11667 * 11668 * @see #onWindowVisibilityChanged(int) 11669 */ 11670 public void dispatchWindowVisibilityChanged(@Visibility int visibility) { 11671 onWindowVisibilityChanged(visibility); 11672 } 11673 11674 /** 11675 * Called when the window containing has change its visibility 11676 * (between {@link #GONE}, {@link #INVISIBLE}, and {@link #VISIBLE}). Note 11677 * that this tells you whether or not your window is being made visible 11678 * to the window manager; this does <em>not</em> tell you whether or not 11679 * your window is obscured by other windows on the screen, even if it 11680 * is itself visible. 11681 * 11682 * @param visibility The new visibility of the window. 11683 */ 11684 protected void onWindowVisibilityChanged(@Visibility int visibility) { 11685 if (visibility == VISIBLE) { 11686 initialAwakenScrollBars(); 11687 } 11688 } 11689 11690 /** 11691 * Internal dispatching method for {@link #onVisibilityAggregated}. Overridden by 11692 * ViewGroup. Intended to only be called when {@link #isAttachedToWindow()}, 11693 * {@link #getWindowVisibility()} is {@link #VISIBLE} and this view's parent {@link #isShown()}. 11694 * 11695 * @param isVisible true if this view's visibility to the user is uninterrupted by its 11696 * ancestors or by window visibility 11697 * @return true if this view is visible to the user, not counting clipping or overlapping 11698 */ 11699 boolean dispatchVisibilityAggregated(boolean isVisible) { 11700 final boolean thisVisible = getVisibility() == VISIBLE; 11701 // If we're not visible but something is telling us we are, ignore it. 11702 if (thisVisible || !isVisible) { 11703 onVisibilityAggregated(isVisible); 11704 } 11705 return thisVisible && isVisible; 11706 } 11707 11708 /** 11709 * Called when the user-visibility of this View is potentially affected by a change 11710 * to this view itself, an ancestor view or the window this view is attached to. 11711 * 11712 * @param isVisible true if this view and all of its ancestors are {@link #VISIBLE} 11713 * and this view's window is also visible 11714 */ 11715 @CallSuper 11716 public void onVisibilityAggregated(boolean isVisible) { 11717 if (isVisible && mAttachInfo != null) { 11718 initialAwakenScrollBars(); 11719 } 11720 11721 final Drawable dr = mBackground; 11722 if (dr != null && isVisible != dr.isVisible()) { 11723 dr.setVisible(isVisible, false); 11724 } 11725 final Drawable hl = mDefaultFocusHighlight; 11726 if (hl != null && isVisible != hl.isVisible()) { 11727 hl.setVisible(isVisible, false); 11728 } 11729 final Drawable fg = mForegroundInfo != null ? mForegroundInfo.mDrawable : null; 11730 if (fg != null && isVisible != fg.isVisible()) { 11731 fg.setVisible(isVisible, false); 11732 } 11733 11734 if (isAutofillable()) { 11735 AutofillManager afm = getAutofillManager(); 11736 11737 if (afm != null && getAccessibilityViewId() > LAST_APP_ACCESSIBILITY_ID) { 11738 if (mVisibilityChangeForAutofillHandler != null) { 11739 mVisibilityChangeForAutofillHandler.removeMessages(0); 11740 } 11741 11742 // If the view is in the background but still part of the hierarchy this is called 11743 // with isVisible=false. Hence visibility==false requires further checks 11744 if (isVisible) { 11745 afm.notifyViewVisibilityChange(this, true); 11746 } else { 11747 if (mVisibilityChangeForAutofillHandler == null) { 11748 mVisibilityChangeForAutofillHandler = 11749 new VisibilityChangeForAutofillHandler(afm, this); 11750 } 11751 // Let current operation (e.g. removal of the view from the hierarchy) 11752 // finish before checking state 11753 mVisibilityChangeForAutofillHandler.obtainMessage(0, this).sendToTarget(); 11754 } 11755 } 11756 } 11757 } 11758 11759 /** 11760 * Returns the current visibility of the window this view is attached to 11761 * (either {@link #GONE}, {@link #INVISIBLE}, or {@link #VISIBLE}). 11762 * 11763 * @return Returns the current visibility of the view's window. 11764 */ 11765 @Visibility 11766 public int getWindowVisibility() { 11767 return mAttachInfo != null ? mAttachInfo.mWindowVisibility : GONE; 11768 } 11769 11770 /** 11771 * Retrieve the overall visible display size in which the window this view is 11772 * attached to has been positioned in. This takes into account screen 11773 * decorations above the window, for both cases where the window itself 11774 * is being position inside of them or the window is being placed under 11775 * then and covered insets are used for the window to position its content 11776 * inside. In effect, this tells you the available area where content can 11777 * be placed and remain visible to users. 11778 * 11779 * <p>This function requires an IPC back to the window manager to retrieve 11780 * the requested information, so should not be used in performance critical 11781 * code like drawing. 11782 * 11783 * @param outRect Filled in with the visible display frame. If the view 11784 * is not attached to a window, this is simply the raw display size. 11785 */ 11786 public void getWindowVisibleDisplayFrame(Rect outRect) { 11787 if (mAttachInfo != null) { 11788 try { 11789 mAttachInfo.mSession.getDisplayFrame(mAttachInfo.mWindow, outRect); 11790 } catch (RemoteException e) { 11791 return; 11792 } 11793 // XXX This is really broken, and probably all needs to be done 11794 // in the window manager, and we need to know more about whether 11795 // we want the area behind or in front of the IME. 11796 final Rect insets = mAttachInfo.mVisibleInsets; 11797 outRect.left += insets.left; 11798 outRect.top += insets.top; 11799 outRect.right -= insets.right; 11800 outRect.bottom -= insets.bottom; 11801 return; 11802 } 11803 // The view is not attached to a display so we don't have a context. 11804 // Make a best guess about the display size. 11805 Display d = DisplayManagerGlobal.getInstance().getRealDisplay(Display.DEFAULT_DISPLAY); 11806 d.getRectSize(outRect); 11807 } 11808 11809 /** 11810 * Like {@link #getWindowVisibleDisplayFrame}, but returns the "full" display frame this window 11811 * is currently in without any insets. 11812 * 11813 * @hide 11814 */ 11815 public void getWindowDisplayFrame(Rect outRect) { 11816 if (mAttachInfo != null) { 11817 try { 11818 mAttachInfo.mSession.getDisplayFrame(mAttachInfo.mWindow, outRect); 11819 } catch (RemoteException e) { 11820 return; 11821 } 11822 return; 11823 } 11824 // The view is not attached to a display so we don't have a context. 11825 // Make a best guess about the display size. 11826 Display d = DisplayManagerGlobal.getInstance().getRealDisplay(Display.DEFAULT_DISPLAY); 11827 d.getRectSize(outRect); 11828 } 11829 11830 /** 11831 * Dispatch a notification about a resource configuration change down 11832 * the view hierarchy. 11833 * ViewGroups should override to route to their children. 11834 * 11835 * @param newConfig The new resource configuration. 11836 * 11837 * @see #onConfigurationChanged(android.content.res.Configuration) 11838 */ 11839 public void dispatchConfigurationChanged(Configuration newConfig) { 11840 onConfigurationChanged(newConfig); 11841 } 11842 11843 /** 11844 * Called when the current configuration of the resources being used 11845 * by the application have changed. You can use this to decide when 11846 * to reload resources that can changed based on orientation and other 11847 * configuration characteristics. You only need to use this if you are 11848 * not relying on the normal {@link android.app.Activity} mechanism of 11849 * recreating the activity instance upon a configuration change. 11850 * 11851 * @param newConfig The new resource configuration. 11852 */ 11853 protected void onConfigurationChanged(Configuration newConfig) { 11854 } 11855 11856 /** 11857 * Private function to aggregate all per-view attributes in to the view 11858 * root. 11859 */ 11860 void dispatchCollectViewAttributes(AttachInfo attachInfo, int visibility) { 11861 performCollectViewAttributes(attachInfo, visibility); 11862 } 11863 11864 void performCollectViewAttributes(AttachInfo attachInfo, int visibility) { 11865 if ((visibility & VISIBILITY_MASK) == VISIBLE) { 11866 if ((mViewFlags & KEEP_SCREEN_ON) == KEEP_SCREEN_ON) { 11867 attachInfo.mKeepScreenOn = true; 11868 } 11869 attachInfo.mSystemUiVisibility |= mSystemUiVisibility; 11870 ListenerInfo li = mListenerInfo; 11871 if (li != null && li.mOnSystemUiVisibilityChangeListener != null) { 11872 attachInfo.mHasSystemUiListeners = true; 11873 } 11874 } 11875 } 11876 11877 void needGlobalAttributesUpdate(boolean force) { 11878 final AttachInfo ai = mAttachInfo; 11879 if (ai != null && !ai.mRecomputeGlobalAttributes) { 11880 if (force || ai.mKeepScreenOn || (ai.mSystemUiVisibility != 0) 11881 || ai.mHasSystemUiListeners) { 11882 ai.mRecomputeGlobalAttributes = true; 11883 } 11884 } 11885 } 11886 11887 /** 11888 * Returns whether the device is currently in touch mode. Touch mode is entered 11889 * once the user begins interacting with the device by touch, and affects various 11890 * things like whether focus is always visible to the user. 11891 * 11892 * @return Whether the device is in touch mode. 11893 */ 11894 @ViewDebug.ExportedProperty 11895 public boolean isInTouchMode() { 11896 if (mAttachInfo != null) { 11897 return mAttachInfo.mInTouchMode; 11898 } else { 11899 return ViewRootImpl.isInTouchMode(); 11900 } 11901 } 11902 11903 /** 11904 * Returns the context the view is running in, through which it can 11905 * access the current theme, resources, etc. 11906 * 11907 * @return The view's Context. 11908 */ 11909 @ViewDebug.CapturedViewProperty 11910 public final Context getContext() { 11911 return mContext; 11912 } 11913 11914 /** 11915 * Handle a key event before it is processed by any input method 11916 * associated with the view hierarchy. This can be used to intercept 11917 * key events in special situations before the IME consumes them; a 11918 * typical example would be handling the BACK key to update the application's 11919 * UI instead of allowing the IME to see it and close itself. 11920 * 11921 * @param keyCode The value in event.getKeyCode(). 11922 * @param event Description of the key event. 11923 * @return If you handled the event, return true. If you want to allow the 11924 * event to be handled by the next receiver, return false. 11925 */ 11926 public boolean onKeyPreIme(int keyCode, KeyEvent event) { 11927 return false; 11928 } 11929 11930 /** 11931 * Default implementation of {@link KeyEvent.Callback#onKeyDown(int, KeyEvent) 11932 * KeyEvent.Callback.onKeyDown()}: perform press of the view 11933 * when {@link KeyEvent#KEYCODE_DPAD_CENTER} or {@link KeyEvent#KEYCODE_ENTER} 11934 * is released, if the view is enabled and clickable. 11935 * <p> 11936 * Key presses in software keyboards will generally NOT trigger this 11937 * listener, although some may elect to do so in some situations. Do not 11938 * rely on this to catch software key presses. 11939 * 11940 * @param keyCode a key code that represents the button pressed, from 11941 * {@link android.view.KeyEvent} 11942 * @param event the KeyEvent object that defines the button action 11943 */ 11944 public boolean onKeyDown(int keyCode, KeyEvent event) { 11945 if (KeyEvent.isConfirmKey(keyCode)) { 11946 if ((mViewFlags & ENABLED_MASK) == DISABLED) { 11947 return true; 11948 } 11949 11950 if (event.getRepeatCount() == 0) { 11951 // Long clickable items don't necessarily have to be clickable. 11952 final boolean clickable = (mViewFlags & CLICKABLE) == CLICKABLE 11953 || (mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE; 11954 if (clickable || (mViewFlags & TOOLTIP) == TOOLTIP) { 11955 // For the purposes of menu anchoring and drawable hotspots, 11956 // key events are considered to be at the center of the view. 11957 final float x = getWidth() / 2f; 11958 final float y = getHeight() / 2f; 11959 if (clickable) { 11960 setPressed(true, x, y); 11961 } 11962 checkForLongClick(0, x, y); 11963 return true; 11964 } 11965 } 11966 } 11967 11968 return false; 11969 } 11970 11971 /** 11972 * Default implementation of {@link KeyEvent.Callback#onKeyLongPress(int, KeyEvent) 11973 * KeyEvent.Callback.onKeyLongPress()}: always returns false (doesn't handle 11974 * the event). 11975 * <p>Key presses in software keyboards will generally NOT trigger this listener, 11976 * although some may elect to do so in some situations. Do not rely on this to 11977 * catch software key presses. 11978 */ 11979 public boolean onKeyLongPress(int keyCode, KeyEvent event) { 11980 return false; 11981 } 11982 11983 /** 11984 * Default implementation of {@link KeyEvent.Callback#onKeyUp(int, KeyEvent) 11985 * KeyEvent.Callback.onKeyUp()}: perform clicking of the view 11986 * when {@link KeyEvent#KEYCODE_DPAD_CENTER}, {@link KeyEvent#KEYCODE_ENTER} 11987 * or {@link KeyEvent#KEYCODE_SPACE} is released. 11988 * <p>Key presses in software keyboards will generally NOT trigger this listener, 11989 * although some may elect to do so in some situations. Do not rely on this to 11990 * catch software key presses. 11991 * 11992 * @param keyCode A key code that represents the button pressed, from 11993 * {@link android.view.KeyEvent}. 11994 * @param event The KeyEvent object that defines the button action. 11995 */ 11996 public boolean onKeyUp(int keyCode, KeyEvent event) { 11997 if (KeyEvent.isConfirmKey(keyCode)) { 11998 if ((mViewFlags & ENABLED_MASK) == DISABLED) { 11999 return true; 12000 } 12001 if ((mViewFlags & CLICKABLE) == CLICKABLE && isPressed()) { 12002 setPressed(false); 12003 12004 if (!mHasPerformedLongPress) { 12005 // This is a tap, so remove the longpress check 12006 removeLongPressCallback(); 12007 if (!event.isCanceled()) { 12008 return performClick(); 12009 } 12010 } 12011 } 12012 } 12013 return false; 12014 } 12015 12016 /** 12017 * Default implementation of {@link KeyEvent.Callback#onKeyMultiple(int, int, KeyEvent) 12018 * KeyEvent.Callback.onKeyMultiple()}: always returns false (doesn't handle 12019 * the event). 12020 * <p>Key presses in software keyboards will generally NOT trigger this listener, 12021 * although some may elect to do so in some situations. Do not rely on this to 12022 * catch software key presses. 12023 * 12024 * @param keyCode A key code that represents the button pressed, from 12025 * {@link android.view.KeyEvent}. 12026 * @param repeatCount The number of times the action was made. 12027 * @param event The KeyEvent object that defines the button action. 12028 */ 12029 public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event) { 12030 return false; 12031 } 12032 12033 /** 12034 * Called on the focused view when a key shortcut event is not handled. 12035 * Override this method to implement local key shortcuts for the View. 12036 * Key shortcuts can also be implemented by setting the 12037 * {@link MenuItem#setShortcut(char, char) shortcut} property of menu items. 12038 * 12039 * @param keyCode The value in event.getKeyCode(). 12040 * @param event Description of the key event. 12041 * @return If you handled the event, return true. If you want to allow the 12042 * event to be handled by the next receiver, return false. 12043 */ 12044 public boolean onKeyShortcut(int keyCode, KeyEvent event) { 12045 return false; 12046 } 12047 12048 /** 12049 * Check whether the called view is a text editor, in which case it 12050 * would make sense to automatically display a soft input window for 12051 * it. Subclasses should override this if they implement 12052 * {@link #onCreateInputConnection(EditorInfo)} to return true if 12053 * a call on that method would return a non-null InputConnection, and 12054 * they are really a first-class editor that the user would normally 12055 * start typing on when the go into a window containing your view. 12056 * 12057 * <p>The default implementation always returns false. This does 12058 * <em>not</em> mean that its {@link #onCreateInputConnection(EditorInfo)} 12059 * will not be called or the user can not otherwise perform edits on your 12060 * view; it is just a hint to the system that this is not the primary 12061 * purpose of this view. 12062 * 12063 * @return Returns true if this view is a text editor, else false. 12064 */ 12065 public boolean onCheckIsTextEditor() { 12066 return false; 12067 } 12068 12069 /** 12070 * Create a new InputConnection for an InputMethod to interact 12071 * with the view. The default implementation returns null, since it doesn't 12072 * support input methods. You can override this to implement such support. 12073 * This is only needed for views that take focus and text input. 12074 * 12075 * <p>When implementing this, you probably also want to implement 12076 * {@link #onCheckIsTextEditor()} to indicate you will return a 12077 * non-null InputConnection.</p> 12078 * 12079 * <p>Also, take good care to fill in the {@link android.view.inputmethod.EditorInfo} 12080 * object correctly and in its entirety, so that the connected IME can rely 12081 * on its values. For example, {@link android.view.inputmethod.EditorInfo#initialSelStart} 12082 * and {@link android.view.inputmethod.EditorInfo#initialSelEnd} members 12083 * must be filled in with the correct cursor position for IMEs to work correctly 12084 * with your application.</p> 12085 * 12086 * @param outAttrs Fill in with attribute information about the connection. 12087 */ 12088 public InputConnection onCreateInputConnection(EditorInfo outAttrs) { 12089 return null; 12090 } 12091 12092 /** 12093 * Called by the {@link android.view.inputmethod.InputMethodManager} 12094 * when a view who is not the current 12095 * input connection target is trying to make a call on the manager. The 12096 * default implementation returns false; you can override this to return 12097 * true for certain views if you are performing InputConnection proxying 12098 * to them. 12099 * @param view The View that is making the InputMethodManager call. 12100 * @return Return true to allow the call, false to reject. 12101 */ 12102 public boolean checkInputConnectionProxy(View view) { 12103 return false; 12104 } 12105 12106 /** 12107 * Show the context menu for this view. It is not safe to hold on to the 12108 * menu after returning from this method. 12109 * 12110 * You should normally not overload this method. Overload 12111 * {@link #onCreateContextMenu(ContextMenu)} or define an 12112 * {@link OnCreateContextMenuListener} to add items to the context menu. 12113 * 12114 * @param menu The context menu to populate 12115 */ 12116 public void createContextMenu(ContextMenu menu) { 12117 ContextMenuInfo menuInfo = getContextMenuInfo(); 12118 12119 // Sets the current menu info so all items added to menu will have 12120 // my extra info set. 12121 ((MenuBuilder)menu).setCurrentMenuInfo(menuInfo); 12122 12123 onCreateContextMenu(menu); 12124 ListenerInfo li = mListenerInfo; 12125 if (li != null && li.mOnCreateContextMenuListener != null) { 12126 li.mOnCreateContextMenuListener.onCreateContextMenu(menu, this, menuInfo); 12127 } 12128 12129 // Clear the extra information so subsequent items that aren't mine don't 12130 // have my extra info. 12131 ((MenuBuilder)menu).setCurrentMenuInfo(null); 12132 12133 if (mParent != null) { 12134 mParent.createContextMenu(menu); 12135 } 12136 } 12137 12138 /** 12139 * Views should implement this if they have extra information to associate 12140 * with the context menu. The return result is supplied as a parameter to 12141 * the {@link OnCreateContextMenuListener#onCreateContextMenu(ContextMenu, View, ContextMenuInfo)} 12142 * callback. 12143 * 12144 * @return Extra information about the item for which the context menu 12145 * should be shown. This information will vary across different 12146 * subclasses of View. 12147 */ 12148 protected ContextMenuInfo getContextMenuInfo() { 12149 return null; 12150 } 12151 12152 /** 12153 * Views should implement this if the view itself is going to add items to 12154 * the context menu. 12155 * 12156 * @param menu the context menu to populate 12157 */ 12158 protected void onCreateContextMenu(ContextMenu menu) { 12159 } 12160 12161 /** 12162 * Implement this method to handle trackball motion events. The 12163 * <em>relative</em> movement of the trackball since the last event 12164 * can be retrieve with {@link MotionEvent#getX MotionEvent.getX()} and 12165 * {@link MotionEvent#getY MotionEvent.getY()}. These are normalized so 12166 * that a movement of 1 corresponds to the user pressing one DPAD key (so 12167 * they will often be fractional values, representing the more fine-grained 12168 * movement information available from a trackball). 12169 * 12170 * @param event The motion event. 12171 * @return True if the event was handled, false otherwise. 12172 */ 12173 public boolean onTrackballEvent(MotionEvent event) { 12174 return false; 12175 } 12176 12177 /** 12178 * Implement this method to handle generic motion events. 12179 * <p> 12180 * Generic motion events describe joystick movements, mouse hovers, track pad 12181 * touches, scroll wheel movements and other input events. The 12182 * {@link MotionEvent#getSource() source} of the motion event specifies 12183 * the class of input that was received. Implementations of this method 12184 * must examine the bits in the source before processing the event. 12185 * The following code example shows how this is done. 12186 * </p><p> 12187 * Generic motion events with source class {@link InputDevice#SOURCE_CLASS_POINTER} 12188 * are delivered to the view under the pointer. All other generic motion events are 12189 * delivered to the focused view. 12190 * </p> 12191 * <pre> public boolean onGenericMotionEvent(MotionEvent event) { 12192 * if (event.isFromSource(InputDevice.SOURCE_CLASS_JOYSTICK)) { 12193 * if (event.getAction() == MotionEvent.ACTION_MOVE) { 12194 * // process the joystick movement... 12195 * return true; 12196 * } 12197 * } 12198 * if (event.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) { 12199 * switch (event.getAction()) { 12200 * case MotionEvent.ACTION_HOVER_MOVE: 12201 * // process the mouse hover movement... 12202 * return true; 12203 * case MotionEvent.ACTION_SCROLL: 12204 * // process the scroll wheel movement... 12205 * return true; 12206 * } 12207 * } 12208 * return super.onGenericMotionEvent(event); 12209 * }</pre> 12210 * 12211 * @param event The generic motion event being processed. 12212 * @return True if the event was handled, false otherwise. 12213 */ 12214 public boolean onGenericMotionEvent(MotionEvent event) { 12215 return false; 12216 } 12217 12218 /** 12219 * Implement this method to handle hover events. 12220 * <p> 12221 * This method is called whenever a pointer is hovering into, over, or out of the 12222 * bounds of a view and the view is not currently being touched. 12223 * Hover events are represented as pointer events with action 12224 * {@link MotionEvent#ACTION_HOVER_ENTER}, {@link MotionEvent#ACTION_HOVER_MOVE}, 12225 * or {@link MotionEvent#ACTION_HOVER_EXIT}. 12226 * </p> 12227 * <ul> 12228 * <li>The view receives a hover event with action {@link MotionEvent#ACTION_HOVER_ENTER} 12229 * when the pointer enters the bounds of the view.</li> 12230 * <li>The view receives a hover event with action {@link MotionEvent#ACTION_HOVER_MOVE} 12231 * when the pointer has already entered the bounds of the view and has moved.</li> 12232 * <li>The view receives a hover event with action {@link MotionEvent#ACTION_HOVER_EXIT} 12233 * when the pointer has exited the bounds of the view or when the pointer is 12234 * about to go down due to a button click, tap, or similar user action that 12235 * causes the view to be touched.</li> 12236 * </ul> 12237 * <p> 12238 * The view should implement this method to return true to indicate that it is 12239 * handling the hover event, such as by changing its drawable state. 12240 * </p><p> 12241 * The default implementation calls {@link #setHovered} to update the hovered state 12242 * of the view when a hover enter or hover exit event is received, if the view 12243 * is enabled and is clickable. The default implementation also sends hover 12244 * accessibility events. 12245 * </p> 12246 * 12247 * @param event The motion event that describes the hover. 12248 * @return True if the view handled the hover event. 12249 * 12250 * @see #isHovered 12251 * @see #setHovered 12252 * @see #onHoverChanged 12253 */ 12254 public boolean onHoverEvent(MotionEvent event) { 12255 // The root view may receive hover (or touch) events that are outside the bounds of 12256 // the window. This code ensures that we only send accessibility events for 12257 // hovers that are actually within the bounds of the root view. 12258 final int action = event.getActionMasked(); 12259 if (!mSendingHoverAccessibilityEvents) { 12260 if ((action == MotionEvent.ACTION_HOVER_ENTER 12261 || action == MotionEvent.ACTION_HOVER_MOVE) 12262 && !hasHoveredChild() 12263 && pointInView(event.getX(), event.getY())) { 12264 sendAccessibilityHoverEvent(AccessibilityEvent.TYPE_VIEW_HOVER_ENTER); 12265 mSendingHoverAccessibilityEvents = true; 12266 } 12267 } else { 12268 if (action == MotionEvent.ACTION_HOVER_EXIT 12269 || (action == MotionEvent.ACTION_MOVE 12270 && !pointInView(event.getX(), event.getY()))) { 12271 mSendingHoverAccessibilityEvents = false; 12272 sendAccessibilityHoverEvent(AccessibilityEvent.TYPE_VIEW_HOVER_EXIT); 12273 } 12274 } 12275 12276 if ((action == MotionEvent.ACTION_HOVER_ENTER || action == MotionEvent.ACTION_HOVER_MOVE) 12277 && event.isFromSource(InputDevice.SOURCE_MOUSE) 12278 && isOnScrollbar(event.getX(), event.getY())) { 12279 awakenScrollBars(); 12280 } 12281 12282 // If we consider ourself hoverable, or if we we're already hovered, 12283 // handle changing state in response to ENTER and EXIT events. 12284 if (isHoverable() || isHovered()) { 12285 switch (action) { 12286 case MotionEvent.ACTION_HOVER_ENTER: 12287 setHovered(true); 12288 break; 12289 case MotionEvent.ACTION_HOVER_EXIT: 12290 setHovered(false); 12291 break; 12292 } 12293 12294 // Dispatch the event to onGenericMotionEvent before returning true. 12295 // This is to provide compatibility with existing applications that 12296 // handled HOVER_MOVE events in onGenericMotionEvent and that would 12297 // break because of the new default handling for hoverable views 12298 // in onHoverEvent. 12299 // Note that onGenericMotionEvent will be called by default when 12300 // onHoverEvent returns false (refer to dispatchGenericMotionEvent). 12301 dispatchGenericMotionEventInternal(event); 12302 // The event was already handled by calling setHovered(), so always 12303 // return true. 12304 return true; 12305 } 12306 12307 return false; 12308 } 12309 12310 /** 12311 * Returns true if the view should handle {@link #onHoverEvent} 12312 * by calling {@link #setHovered} to change its hovered state. 12313 * 12314 * @return True if the view is hoverable. 12315 */ 12316 private boolean isHoverable() { 12317 final int viewFlags = mViewFlags; 12318 if ((viewFlags & ENABLED_MASK) == DISABLED) { 12319 return false; 12320 } 12321 12322 return (viewFlags & CLICKABLE) == CLICKABLE 12323 || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE 12324 || (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE; 12325 } 12326 12327 /** 12328 * Returns true if the view is currently hovered. 12329 * 12330 * @return True if the view is currently hovered. 12331 * 12332 * @see #setHovered 12333 * @see #onHoverChanged 12334 */ 12335 @ViewDebug.ExportedProperty 12336 public boolean isHovered() { 12337 return (mPrivateFlags & PFLAG_HOVERED) != 0; 12338 } 12339 12340 /** 12341 * Sets whether the view is currently hovered. 12342 * <p> 12343 * Calling this method also changes the drawable state of the view. This 12344 * enables the view to react to hover by using different drawable resources 12345 * to change its appearance. 12346 * </p><p> 12347 * The {@link #onHoverChanged} method is called when the hovered state changes. 12348 * </p> 12349 * 12350 * @param hovered True if the view is hovered. 12351 * 12352 * @see #isHovered 12353 * @see #onHoverChanged 12354 */ 12355 public void setHovered(boolean hovered) { 12356 if (hovered) { 12357 if ((mPrivateFlags & PFLAG_HOVERED) == 0) { 12358 mPrivateFlags |= PFLAG_HOVERED; 12359 refreshDrawableState(); 12360 onHoverChanged(true); 12361 } 12362 } else { 12363 if ((mPrivateFlags & PFLAG_HOVERED) != 0) { 12364 mPrivateFlags &= ~PFLAG_HOVERED; 12365 refreshDrawableState(); 12366 onHoverChanged(false); 12367 } 12368 } 12369 } 12370 12371 /** 12372 * Implement this method to handle hover state changes. 12373 * <p> 12374 * This method is called whenever the hover state changes as a result of a 12375 * call to {@link #setHovered}. 12376 * </p> 12377 * 12378 * @param hovered The current hover state, as returned by {@link #isHovered}. 12379 * 12380 * @see #isHovered 12381 * @see #setHovered 12382 */ 12383 public void onHoverChanged(boolean hovered) { 12384 } 12385 12386 /** 12387 * Handles scroll bar dragging by mouse input. 12388 * 12389 * @hide 12390 * @param event The motion event. 12391 * 12392 * @return true if the event was handled as a scroll bar dragging, false otherwise. 12393 */ 12394 protected boolean handleScrollBarDragging(MotionEvent event) { 12395 if (mScrollCache == null) { 12396 return false; 12397 } 12398 final float x = event.getX(); 12399 final float y = event.getY(); 12400 final int action = event.getAction(); 12401 if ((mScrollCache.mScrollBarDraggingState == ScrollabilityCache.NOT_DRAGGING 12402 && action != MotionEvent.ACTION_DOWN) 12403 || !event.isFromSource(InputDevice.SOURCE_MOUSE) 12404 || !event.isButtonPressed(MotionEvent.BUTTON_PRIMARY)) { 12405 mScrollCache.mScrollBarDraggingState = ScrollabilityCache.NOT_DRAGGING; 12406 return false; 12407 } 12408 12409 switch (action) { 12410 case MotionEvent.ACTION_MOVE: 12411 if (mScrollCache.mScrollBarDraggingState == ScrollabilityCache.NOT_DRAGGING) { 12412 return false; 12413 } 12414 if (mScrollCache.mScrollBarDraggingState 12415 == ScrollabilityCache.DRAGGING_VERTICAL_SCROLL_BAR) { 12416 final Rect bounds = mScrollCache.mScrollBarBounds; 12417 getVerticalScrollBarBounds(bounds, null); 12418 final int range = computeVerticalScrollRange(); 12419 final int offset = computeVerticalScrollOffset(); 12420 final int extent = computeVerticalScrollExtent(); 12421 12422 final int thumbLength = ScrollBarUtils.getThumbLength( 12423 bounds.height(), bounds.width(), extent, range); 12424 final int thumbOffset = ScrollBarUtils.getThumbOffset( 12425 bounds.height(), thumbLength, extent, range, offset); 12426 12427 final float diff = y - mScrollCache.mScrollBarDraggingPos; 12428 final float maxThumbOffset = bounds.height() - thumbLength; 12429 final float newThumbOffset = 12430 Math.min(Math.max(thumbOffset + diff, 0.0f), maxThumbOffset); 12431 final int height = getHeight(); 12432 if (Math.round(newThumbOffset) != thumbOffset && maxThumbOffset > 0 12433 && height > 0 && extent > 0) { 12434 final int newY = Math.round((range - extent) 12435 / ((float)extent / height) * (newThumbOffset / maxThumbOffset)); 12436 if (newY != getScrollY()) { 12437 mScrollCache.mScrollBarDraggingPos = y; 12438 setScrollY(newY); 12439 } 12440 } 12441 return true; 12442 } 12443 if (mScrollCache.mScrollBarDraggingState 12444 == ScrollabilityCache.DRAGGING_HORIZONTAL_SCROLL_BAR) { 12445 final Rect bounds = mScrollCache.mScrollBarBounds; 12446 getHorizontalScrollBarBounds(bounds, null); 12447 final int range = computeHorizontalScrollRange(); 12448 final int offset = computeHorizontalScrollOffset(); 12449 final int extent = computeHorizontalScrollExtent(); 12450 12451 final int thumbLength = ScrollBarUtils.getThumbLength( 12452 bounds.width(), bounds.height(), extent, range); 12453 final int thumbOffset = ScrollBarUtils.getThumbOffset( 12454 bounds.width(), thumbLength, extent, range, offset); 12455 12456 final float diff = x - mScrollCache.mScrollBarDraggingPos; 12457 final float maxThumbOffset = bounds.width() - thumbLength; 12458 final float newThumbOffset = 12459 Math.min(Math.max(thumbOffset + diff, 0.0f), maxThumbOffset); 12460 final int width = getWidth(); 12461 if (Math.round(newThumbOffset) != thumbOffset && maxThumbOffset > 0 12462 && width > 0 && extent > 0) { 12463 final int newX = Math.round((range - extent) 12464 / ((float)extent / width) * (newThumbOffset / maxThumbOffset)); 12465 if (newX != getScrollX()) { 12466 mScrollCache.mScrollBarDraggingPos = x; 12467 setScrollX(newX); 12468 } 12469 } 12470 return true; 12471 } 12472 case MotionEvent.ACTION_DOWN: 12473 if (mScrollCache.state == ScrollabilityCache.OFF) { 12474 return false; 12475 } 12476 if (isOnVerticalScrollbarThumb(x, y)) { 12477 mScrollCache.mScrollBarDraggingState = 12478 ScrollabilityCache.DRAGGING_VERTICAL_SCROLL_BAR; 12479 mScrollCache.mScrollBarDraggingPos = y; 12480 return true; 12481 } 12482 if (isOnHorizontalScrollbarThumb(x, y)) { 12483 mScrollCache.mScrollBarDraggingState = 12484 ScrollabilityCache.DRAGGING_HORIZONTAL_SCROLL_BAR; 12485 mScrollCache.mScrollBarDraggingPos = x; 12486 return true; 12487 } 12488 } 12489 mScrollCache.mScrollBarDraggingState = ScrollabilityCache.NOT_DRAGGING; 12490 return false; 12491 } 12492 12493 /** 12494 * Implement this method to handle touch screen motion events. 12495 * <p> 12496 * If this method is used to detect click actions, it is recommended that 12497 * the actions be performed by implementing and calling 12498 * {@link #performClick()}. This will ensure consistent system behavior, 12499 * including: 12500 * <ul> 12501 * <li>obeying click sound preferences 12502 * <li>dispatching OnClickListener calls 12503 * <li>handling {@link AccessibilityNodeInfo#ACTION_CLICK ACTION_CLICK} when 12504 * accessibility features are enabled 12505 * </ul> 12506 * 12507 * @param event The motion event. 12508 * @return True if the event was handled, false otherwise. 12509 */ 12510 public boolean onTouchEvent(MotionEvent event) { 12511 final float x = event.getX(); 12512 final float y = event.getY(); 12513 final int viewFlags = mViewFlags; 12514 final int action = event.getAction(); 12515 12516 final boolean clickable = ((viewFlags & CLICKABLE) == CLICKABLE 12517 || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE) 12518 || (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE; 12519 12520 if ((viewFlags & ENABLED_MASK) == DISABLED) { 12521 if (action == MotionEvent.ACTION_UP && (mPrivateFlags & PFLAG_PRESSED) != 0) { 12522 setPressed(false); 12523 } 12524 mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN; 12525 // A disabled view that is clickable still consumes the touch 12526 // events, it just doesn't respond to them. 12527 return clickable; 12528 } 12529 if (mTouchDelegate != null) { 12530 if (mTouchDelegate.onTouchEvent(event)) { 12531 return true; 12532 } 12533 } 12534 12535 if (clickable || (viewFlags & TOOLTIP) == TOOLTIP) { 12536 switch (action) { 12537 case MotionEvent.ACTION_UP: 12538 mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN; 12539 if ((viewFlags & TOOLTIP) == TOOLTIP) { 12540 handleTooltipUp(); 12541 } 12542 if (!clickable) { 12543 removeTapCallback(); 12544 removeLongPressCallback(); 12545 mInContextButtonPress = false; 12546 mHasPerformedLongPress = false; 12547 mIgnoreNextUpEvent = false; 12548 break; 12549 } 12550 boolean prepressed = (mPrivateFlags & PFLAG_PREPRESSED) != 0; 12551 if ((mPrivateFlags & PFLAG_PRESSED) != 0 || prepressed) { 12552 // take focus if we don't have it already and we should in 12553 // touch mode. 12554 boolean focusTaken = false; 12555 if (isFocusable() && isFocusableInTouchMode() && !isFocused()) { 12556 focusTaken = requestFocus(); 12557 } 12558 12559 if (prepressed) { 12560 // The button is being released before we actually 12561 // showed it as pressed. Make it show the pressed 12562 // state now (before scheduling the click) to ensure 12563 // the user sees it. 12564 setPressed(true, x, y); 12565 } 12566 12567 if (!mHasPerformedLongPress && !mIgnoreNextUpEvent) { 12568 // This is a tap, so remove the longpress check 12569 removeLongPressCallback(); 12570 12571 // Only perform take click actions if we were in the pressed state 12572 if (!focusTaken) { 12573 // Use a Runnable and post this rather than calling 12574 // performClick directly. This lets other visual state 12575 // of the view update before click actions start. 12576 if (mPerformClick == null) { 12577 mPerformClick = new PerformClick(); 12578 } 12579 if (!post(mPerformClick)) { 12580 performClick(); 12581 } 12582 } 12583 } 12584 12585 if (mUnsetPressedState == null) { 12586 mUnsetPressedState = new UnsetPressedState(); 12587 } 12588 12589 if (prepressed) { 12590 postDelayed(mUnsetPressedState, 12591 ViewConfiguration.getPressedStateDuration()); 12592 } else if (!post(mUnsetPressedState)) { 12593 // If the post failed, unpress right now 12594 mUnsetPressedState.run(); 12595 } 12596 12597 removeTapCallback(); 12598 } 12599 mIgnoreNextUpEvent = false; 12600 break; 12601 12602 case MotionEvent.ACTION_DOWN: 12603 if (event.getSource() == InputDevice.SOURCE_TOUCHSCREEN) { 12604 mPrivateFlags3 |= PFLAG3_FINGER_DOWN; 12605 } 12606 mHasPerformedLongPress = false; 12607 12608 if (!clickable) { 12609 checkForLongClick(0, x, y); 12610 break; 12611 } 12612 12613 if (performButtonActionOnTouchDown(event)) { 12614 break; 12615 } 12616 12617 // Walk up the hierarchy to determine if we're inside a scrolling container. 12618 boolean isInScrollingContainer = isInScrollingContainer(); 12619 12620 // For views inside a scrolling container, delay the pressed feedback for 12621 // a short period in case this is a scroll. 12622 if (isInScrollingContainer) { 12623 mPrivateFlags |= PFLAG_PREPRESSED; 12624 if (mPendingCheckForTap == null) { 12625 mPendingCheckForTap = new CheckForTap(); 12626 } 12627 mPendingCheckForTap.x = event.getX(); 12628 mPendingCheckForTap.y = event.getY(); 12629 postDelayed(mPendingCheckForTap, ViewConfiguration.getTapTimeout()); 12630 } else { 12631 // Not inside a scrolling container, so show the feedback right away 12632 setPressed(true, x, y); 12633 checkForLongClick(0, x, y); 12634 } 12635 break; 12636 12637 case MotionEvent.ACTION_CANCEL: 12638 if (clickable) { 12639 setPressed(false); 12640 } 12641 removeTapCallback(); 12642 removeLongPressCallback(); 12643 mInContextButtonPress = false; 12644 mHasPerformedLongPress = false; 12645 mIgnoreNextUpEvent = false; 12646 mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN; 12647 break; 12648 12649 case MotionEvent.ACTION_MOVE: 12650 if (clickable) { 12651 drawableHotspotChanged(x, y); 12652 } 12653 12654 // Be lenient about moving outside of buttons 12655 if (!pointInView(x, y, mTouchSlop)) { 12656 // Outside button 12657 // Remove any future long press/tap checks 12658 removeTapCallback(); 12659 removeLongPressCallback(); 12660 if ((mPrivateFlags & PFLAG_PRESSED) != 0) { 12661 setPressed(false); 12662 } 12663 mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN; 12664 } 12665 break; 12666 } 12667 12668 return true; 12669 } 12670 12671 return false; 12672 } 12673 12674 /** 12675 * @hide 12676 */ 12677 public boolean isInScrollingContainer() { 12678 ViewParent p = getParent(); 12679 while (p != null && p instanceof ViewGroup) { 12680 if (((ViewGroup) p).shouldDelayChildPressedState()) { 12681 return true; 12682 } 12683 p = p.getParent(); 12684 } 12685 return false; 12686 } 12687 12688 /** 12689 * Remove the longpress detection timer. 12690 */ 12691 private void removeLongPressCallback() { 12692 if (mPendingCheckForLongPress != null) { 12693 removeCallbacks(mPendingCheckForLongPress); 12694 } 12695 } 12696 12697 /** 12698 * Remove the pending click action 12699 */ 12700 private void removePerformClickCallback() { 12701 if (mPerformClick != null) { 12702 removeCallbacks(mPerformClick); 12703 } 12704 } 12705 12706 /** 12707 * Remove the prepress detection timer. 12708 */ 12709 private void removeUnsetPressCallback() { 12710 if ((mPrivateFlags & PFLAG_PRESSED) != 0 && mUnsetPressedState != null) { 12711 setPressed(false); 12712 removeCallbacks(mUnsetPressedState); 12713 } 12714 } 12715 12716 /** 12717 * Remove the tap detection timer. 12718 */ 12719 private void removeTapCallback() { 12720 if (mPendingCheckForTap != null) { 12721 mPrivateFlags &= ~PFLAG_PREPRESSED; 12722 removeCallbacks(mPendingCheckForTap); 12723 } 12724 } 12725 12726 /** 12727 * Cancels a pending long press. Your subclass can use this if you 12728 * want the context menu to come up if the user presses and holds 12729 * at the same place, but you don't want it to come up if they press 12730 * and then move around enough to cause scrolling. 12731 */ 12732 public void cancelLongPress() { 12733 removeLongPressCallback(); 12734 12735 /* 12736 * The prepressed state handled by the tap callback is a display 12737 * construct, but the tap callback will post a long press callback 12738 * less its own timeout. Remove it here. 12739 */ 12740 removeTapCallback(); 12741 } 12742 12743 /** 12744 * Remove the pending callback for sending a 12745 * {@link AccessibilityEvent#TYPE_VIEW_SCROLLED} accessibility event. 12746 */ 12747 private void removeSendViewScrolledAccessibilityEventCallback() { 12748 if (mSendViewScrolledAccessibilityEvent != null) { 12749 removeCallbacks(mSendViewScrolledAccessibilityEvent); 12750 mSendViewScrolledAccessibilityEvent.mIsPending = false; 12751 } 12752 } 12753 12754 /** 12755 * Sets the TouchDelegate for this View. 12756 */ 12757 public void setTouchDelegate(TouchDelegate delegate) { 12758 mTouchDelegate = delegate; 12759 } 12760 12761 /** 12762 * Gets the TouchDelegate for this View. 12763 */ 12764 public TouchDelegate getTouchDelegate() { 12765 return mTouchDelegate; 12766 } 12767 12768 /** 12769 * Request unbuffered dispatch of the given stream of MotionEvents to this View. 12770 * 12771 * Until this View receives a corresponding {@link MotionEvent#ACTION_UP}, ask that the input 12772 * system not batch {@link MotionEvent}s but instead deliver them as soon as they're 12773 * available. This method should only be called for touch events. 12774 * 12775 * <p class="note">This api is not intended for most applications. Buffered dispatch 12776 * provides many of benefits, and just requesting unbuffered dispatch on most MotionEvent 12777 * streams will not improve your input latency. Side effects include: increased latency, 12778 * jittery scrolls and inability to take advantage of system resampling. Talk to your input 12779 * professional to see if {@link #requestUnbufferedDispatch(MotionEvent)} is right for 12780 * you.</p> 12781 */ 12782 public final void requestUnbufferedDispatch(MotionEvent event) { 12783 final int action = event.getAction(); 12784 if (mAttachInfo == null 12785 || action != MotionEvent.ACTION_DOWN && action != MotionEvent.ACTION_MOVE 12786 || !event.isTouchEvent()) { 12787 return; 12788 } 12789 mAttachInfo.mUnbufferedDispatchRequested = true; 12790 } 12791 12792 /** 12793 * Set flags controlling behavior of this view. 12794 * 12795 * @param flags Constant indicating the value which should be set 12796 * @param mask Constant indicating the bit range that should be changed 12797 */ 12798 void setFlags(int flags, int mask) { 12799 final boolean accessibilityEnabled = 12800 AccessibilityManager.getInstance(mContext).isEnabled(); 12801 final boolean oldIncludeForAccessibility = accessibilityEnabled && includeForAccessibility(); 12802 12803 int old = mViewFlags; 12804 mViewFlags = (mViewFlags & ~mask) | (flags & mask); 12805 12806 int changed = mViewFlags ^ old; 12807 if (changed == 0) { 12808 return; 12809 } 12810 int privateFlags = mPrivateFlags; 12811 12812 // If focusable is auto, update the FOCUSABLE bit. 12813 int focusableChangedByAuto = 0; 12814 if (((mViewFlags & FOCUSABLE_AUTO) != 0) 12815 && (changed & (FOCUSABLE_MASK | CLICKABLE)) != 0) { 12816 // Heuristic only takes into account whether view is clickable. 12817 final int newFocus; 12818 if ((mViewFlags & CLICKABLE) != 0) { 12819 newFocus = FOCUSABLE; 12820 } else { 12821 newFocus = NOT_FOCUSABLE; 12822 } 12823 mViewFlags = (mViewFlags & ~FOCUSABLE) | newFocus; 12824 focusableChangedByAuto = (old & FOCUSABLE) ^ (newFocus & FOCUSABLE); 12825 changed = (changed & ~FOCUSABLE) | focusableChangedByAuto; 12826 } 12827 12828 /* Check if the FOCUSABLE bit has changed */ 12829 if (((changed & FOCUSABLE) != 0) && ((privateFlags & PFLAG_HAS_BOUNDS) != 0)) { 12830 if (((old & FOCUSABLE) == FOCUSABLE) 12831 && ((privateFlags & PFLAG_FOCUSED) != 0)) { 12832 /* Give up focus if we are no longer focusable */ 12833 clearFocus(); 12834 } else if (((old & FOCUSABLE) == NOT_FOCUSABLE) 12835 && ((privateFlags & PFLAG_FOCUSED) == 0)) { 12836 /* 12837 * Tell the view system that we are now available to take focus 12838 * if no one else already has it. 12839 */ 12840 if (mParent != null) { 12841 ViewRootImpl viewRootImpl = getViewRootImpl(); 12842 if (!sAutoFocusableOffUIThreadWontNotifyParents 12843 || focusableChangedByAuto == 0 12844 || viewRootImpl == null 12845 || viewRootImpl.mThread == Thread.currentThread()) { 12846 mParent.focusableViewAvailable(this); 12847 } 12848 } 12849 } 12850 } 12851 12852 final int newVisibility = flags & VISIBILITY_MASK; 12853 if (newVisibility == VISIBLE) { 12854 if ((changed & VISIBILITY_MASK) != 0) { 12855 /* 12856 * If this view is becoming visible, invalidate it in case it changed while 12857 * it was not visible. Marking it drawn ensures that the invalidation will 12858 * go through. 12859 */ 12860 mPrivateFlags |= PFLAG_DRAWN; 12861 invalidate(true); 12862 12863 needGlobalAttributesUpdate(true); 12864 12865 // a view becoming visible is worth notifying the parent 12866 // about in case nothing has focus. even if this specific view 12867 // isn't focusable, it may contain something that is, so let 12868 // the root view try to give this focus if nothing else does. 12869 if ((mParent != null) && (mBottom > mTop) && (mRight > mLeft)) { 12870 mParent.focusableViewAvailable(this); 12871 } 12872 } 12873 } 12874 12875 /* Check if the GONE bit has changed */ 12876 if ((changed & GONE) != 0) { 12877 needGlobalAttributesUpdate(false); 12878 requestLayout(); 12879 12880 if (((mViewFlags & VISIBILITY_MASK) == GONE)) { 12881 if (hasFocus()) clearFocus(); 12882 clearAccessibilityFocus(); 12883 destroyDrawingCache(); 12884 if (mParent instanceof View) { 12885 // GONE views noop invalidation, so invalidate the parent 12886 ((View) mParent).invalidate(true); 12887 } 12888 // Mark the view drawn to ensure that it gets invalidated properly the next 12889 // time it is visible and gets invalidated 12890 mPrivateFlags |= PFLAG_DRAWN; 12891 } 12892 if (mAttachInfo != null) { 12893 mAttachInfo.mViewVisibilityChanged = true; 12894 } 12895 } 12896 12897 /* Check if the VISIBLE bit has changed */ 12898 if ((changed & INVISIBLE) != 0) { 12899 needGlobalAttributesUpdate(false); 12900 /* 12901 * If this view is becoming invisible, set the DRAWN flag so that 12902 * the next invalidate() will not be skipped. 12903 */ 12904 mPrivateFlags |= PFLAG_DRAWN; 12905 12906 if (((mViewFlags & VISIBILITY_MASK) == INVISIBLE)) { 12907 // root view becoming invisible shouldn't clear focus and accessibility focus 12908 if (getRootView() != this) { 12909 if (hasFocus()) clearFocus(); 12910 clearAccessibilityFocus(); 12911 } 12912 } 12913 if (mAttachInfo != null) { 12914 mAttachInfo.mViewVisibilityChanged = true; 12915 } 12916 } 12917 12918 if ((changed & VISIBILITY_MASK) != 0) { 12919 // If the view is invisible, cleanup its display list to free up resources 12920 if (newVisibility != VISIBLE && mAttachInfo != null) { 12921 cleanupDraw(); 12922 } 12923 12924 if (mParent instanceof ViewGroup) { 12925 ((ViewGroup) mParent).onChildVisibilityChanged(this, 12926 (changed & VISIBILITY_MASK), newVisibility); 12927 ((View) mParent).invalidate(true); 12928 } else if (mParent != null) { 12929 mParent.invalidateChild(this, null); 12930 } 12931 12932 if (mAttachInfo != null) { 12933 dispatchVisibilityChanged(this, newVisibility); 12934 12935 // Aggregated visibility changes are dispatched to attached views 12936 // in visible windows where the parent is currently shown/drawn 12937 // or the parent is not a ViewGroup (and therefore assumed to be a ViewRoot), 12938 // discounting clipping or overlapping. This makes it a good place 12939 // to change animation states. 12940 if (mParent != null && getWindowVisibility() == VISIBLE && 12941 ((!(mParent instanceof ViewGroup)) || ((ViewGroup) mParent).isShown())) { 12942 dispatchVisibilityAggregated(newVisibility == VISIBLE); 12943 } 12944 notifySubtreeAccessibilityStateChangedIfNeeded(); 12945 } 12946 } 12947 12948 if ((changed & WILL_NOT_CACHE_DRAWING) != 0) { 12949 destroyDrawingCache(); 12950 } 12951 12952 if ((changed & DRAWING_CACHE_ENABLED) != 0) { 12953 destroyDrawingCache(); 12954 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; 12955 invalidateParentCaches(); 12956 } 12957 12958 if ((changed & DRAWING_CACHE_QUALITY_MASK) != 0) { 12959 destroyDrawingCache(); 12960 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; 12961 } 12962 12963 if ((changed & DRAW_MASK) != 0) { 12964 if ((mViewFlags & WILL_NOT_DRAW) != 0) { 12965 if (mBackground != null 12966 || mDefaultFocusHighlight != null 12967 || (mForegroundInfo != null && mForegroundInfo.mDrawable != null)) { 12968 mPrivateFlags &= ~PFLAG_SKIP_DRAW; 12969 } else { 12970 mPrivateFlags |= PFLAG_SKIP_DRAW; 12971 } 12972 } else { 12973 mPrivateFlags &= ~PFLAG_SKIP_DRAW; 12974 } 12975 requestLayout(); 12976 invalidate(true); 12977 } 12978 12979 if ((changed & KEEP_SCREEN_ON) != 0) { 12980 if (mParent != null && mAttachInfo != null && !mAttachInfo.mRecomputeGlobalAttributes) { 12981 mParent.recomputeViewAttributes(this); 12982 } 12983 } 12984 12985 if (accessibilityEnabled) { 12986 if ((changed & FOCUSABLE) != 0 || (changed & VISIBILITY_MASK) != 0 12987 || (changed & CLICKABLE) != 0 || (changed & LONG_CLICKABLE) != 0 12988 || (changed & CONTEXT_CLICKABLE) != 0) { 12989 if (oldIncludeForAccessibility != includeForAccessibility()) { 12990 notifySubtreeAccessibilityStateChangedIfNeeded(); 12991 } else { 12992 notifyViewAccessibilityStateChangedIfNeeded( 12993 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 12994 } 12995 } else if ((changed & ENABLED_MASK) != 0) { 12996 notifyViewAccessibilityStateChangedIfNeeded( 12997 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 12998 } 12999 } 13000 } 13001 13002 /** 13003 * Change the view's z order in the tree, so it's on top of other sibling 13004 * views. This ordering change may affect layout, if the parent container 13005 * uses an order-dependent layout scheme (e.g., LinearLayout). Prior 13006 * to {@link android.os.Build.VERSION_CODES#KITKAT} this 13007 * method should be followed by calls to {@link #requestLayout()} and 13008 * {@link View#invalidate()} on the view's parent to force the parent to redraw 13009 * with the new child ordering. 13010 * 13011 * @see ViewGroup#bringChildToFront(View) 13012 */ 13013 public void bringToFront() { 13014 if (mParent != null) { 13015 mParent.bringChildToFront(this); 13016 } 13017 } 13018 13019 /** 13020 * This is called in response to an internal scroll in this view (i.e., the 13021 * view scrolled its own contents). This is typically as a result of 13022 * {@link #scrollBy(int, int)} or {@link #scrollTo(int, int)} having been 13023 * called. 13024 * 13025 * @param l Current horizontal scroll origin. 13026 * @param t Current vertical scroll origin. 13027 * @param oldl Previous horizontal scroll origin. 13028 * @param oldt Previous vertical scroll origin. 13029 */ 13030 protected void onScrollChanged(int l, int t, int oldl, int oldt) { 13031 notifySubtreeAccessibilityStateChangedIfNeeded(); 13032 13033 if (AccessibilityManager.getInstance(mContext).isEnabled()) { 13034 postSendViewScrolledAccessibilityEventCallback(); 13035 } 13036 13037 mBackgroundSizeChanged = true; 13038 mDefaultFocusHighlightSizeChanged = true; 13039 if (mForegroundInfo != null) { 13040 mForegroundInfo.mBoundsChanged = true; 13041 } 13042 13043 final AttachInfo ai = mAttachInfo; 13044 if (ai != null) { 13045 ai.mViewScrollChanged = true; 13046 } 13047 13048 if (mListenerInfo != null && mListenerInfo.mOnScrollChangeListener != null) { 13049 mListenerInfo.mOnScrollChangeListener.onScrollChange(this, l, t, oldl, oldt); 13050 } 13051 } 13052 13053 /** 13054 * Interface definition for a callback to be invoked when the scroll 13055 * X or Y positions of a view change. 13056 * <p> 13057 * <b>Note:</b> Some views handle scrolling independently from View and may 13058 * have their own separate listeners for scroll-type events. For example, 13059 * {@link android.widget.ListView ListView} allows clients to register an 13060 * {@link android.widget.ListView#setOnScrollListener(android.widget.AbsListView.OnScrollListener) AbsListView.OnScrollListener} 13061 * to listen for changes in list scroll position. 13062 * 13063 * @see #setOnScrollChangeListener(View.OnScrollChangeListener) 13064 */ 13065 public interface OnScrollChangeListener { 13066 /** 13067 * Called when the scroll position of a view changes. 13068 * 13069 * @param v The view whose scroll position has changed. 13070 * @param scrollX Current horizontal scroll origin. 13071 * @param scrollY Current vertical scroll origin. 13072 * @param oldScrollX Previous horizontal scroll origin. 13073 * @param oldScrollY Previous vertical scroll origin. 13074 */ 13075 void onScrollChange(View v, int scrollX, int scrollY, int oldScrollX, int oldScrollY); 13076 } 13077 13078 /** 13079 * Interface definition for a callback to be invoked when the layout bounds of a view 13080 * changes due to layout processing. 13081 */ 13082 public interface OnLayoutChangeListener { 13083 /** 13084 * Called when the layout bounds of a view changes due to layout processing. 13085 * 13086 * @param v The view whose bounds have changed. 13087 * @param left The new value of the view's left property. 13088 * @param top The new value of the view's top property. 13089 * @param right The new value of the view's right property. 13090 * @param bottom The new value of the view's bottom property. 13091 * @param oldLeft The previous value of the view's left property. 13092 * @param oldTop The previous value of the view's top property. 13093 * @param oldRight The previous value of the view's right property. 13094 * @param oldBottom The previous value of the view's bottom property. 13095 */ 13096 void onLayoutChange(View v, int left, int top, int right, int bottom, 13097 int oldLeft, int oldTop, int oldRight, int oldBottom); 13098 } 13099 13100 /** 13101 * This is called during layout when the size of this view has changed. If 13102 * you were just added to the view hierarchy, you're called with the old 13103 * values of 0. 13104 * 13105 * @param w Current width of this view. 13106 * @param h Current height of this view. 13107 * @param oldw Old width of this view. 13108 * @param oldh Old height of this view. 13109 */ 13110 protected void onSizeChanged(int w, int h, int oldw, int oldh) { 13111 } 13112 13113 /** 13114 * Called by draw to draw the child views. This may be overridden 13115 * by derived classes to gain control just before its children are drawn 13116 * (but after its own view has been drawn). 13117 * @param canvas the canvas on which to draw the view 13118 */ 13119 protected void dispatchDraw(Canvas canvas) { 13120 13121 } 13122 13123 /** 13124 * Gets the parent of this view. Note that the parent is a 13125 * ViewParent and not necessarily a View. 13126 * 13127 * @return Parent of this view. 13128 */ 13129 public final ViewParent getParent() { 13130 return mParent; 13131 } 13132 13133 /** 13134 * Set the horizontal scrolled position of your view. This will cause a call to 13135 * {@link #onScrollChanged(int, int, int, int)} and the view will be 13136 * invalidated. 13137 * @param value the x position to scroll to 13138 */ 13139 public void setScrollX(int value) { 13140 scrollTo(value, mScrollY); 13141 } 13142 13143 /** 13144 * Set the vertical scrolled position of your view. This will cause a call to 13145 * {@link #onScrollChanged(int, int, int, int)} and the view will be 13146 * invalidated. 13147 * @param value the y position to scroll to 13148 */ 13149 public void setScrollY(int value) { 13150 scrollTo(mScrollX, value); 13151 } 13152 13153 /** 13154 * Return the scrolled left position of this view. This is the left edge of 13155 * the displayed part of your view. You do not need to draw any pixels 13156 * farther left, since those are outside of the frame of your view on 13157 * screen. 13158 * 13159 * @return The left edge of the displayed part of your view, in pixels. 13160 */ 13161 public final int getScrollX() { 13162 return mScrollX; 13163 } 13164 13165 /** 13166 * Return the scrolled top position of this view. This is the top edge of 13167 * the displayed part of your view. You do not need to draw any pixels above 13168 * it, since those are outside of the frame of your view on screen. 13169 * 13170 * @return The top edge of the displayed part of your view, in pixels. 13171 */ 13172 public final int getScrollY() { 13173 return mScrollY; 13174 } 13175 13176 /** 13177 * Return the width of the your view. 13178 * 13179 * @return The width of your view, in pixels. 13180 */ 13181 @ViewDebug.ExportedProperty(category = "layout") 13182 public final int getWidth() { 13183 return mRight - mLeft; 13184 } 13185 13186 /** 13187 * Return the height of your view. 13188 * 13189 * @return The height of your view, in pixels. 13190 */ 13191 @ViewDebug.ExportedProperty(category = "layout") 13192 public final int getHeight() { 13193 return mBottom - mTop; 13194 } 13195 13196 /** 13197 * Return the visible drawing bounds of your view. Fills in the output 13198 * rectangle with the values from getScrollX(), getScrollY(), 13199 * getWidth(), and getHeight(). These bounds do not account for any 13200 * transformation properties currently set on the view, such as 13201 * {@link #setScaleX(float)} or {@link #setRotation(float)}. 13202 * 13203 * @param outRect The (scrolled) drawing bounds of the view. 13204 */ 13205 public void getDrawingRect(Rect outRect) { 13206 outRect.left = mScrollX; 13207 outRect.top = mScrollY; 13208 outRect.right = mScrollX + (mRight - mLeft); 13209 outRect.bottom = mScrollY + (mBottom - mTop); 13210 } 13211 13212 /** 13213 * Like {@link #getMeasuredWidthAndState()}, but only returns the 13214 * raw width component (that is the result is masked by 13215 * {@link #MEASURED_SIZE_MASK}). 13216 * 13217 * @return The raw measured width of this view. 13218 */ 13219 public final int getMeasuredWidth() { 13220 return mMeasuredWidth & MEASURED_SIZE_MASK; 13221 } 13222 13223 /** 13224 * Return the full width measurement information for this view as computed 13225 * by the most recent call to {@link #measure(int, int)}. This result is a bit mask 13226 * as defined by {@link #MEASURED_SIZE_MASK} and {@link #MEASURED_STATE_TOO_SMALL}. 13227 * This should be used during measurement and layout calculations only. Use 13228 * {@link #getWidth()} to see how wide a view is after layout. 13229 * 13230 * @return The measured width of this view as a bit mask. 13231 */ 13232 @ViewDebug.ExportedProperty(category = "measurement", flagMapping = { 13233 @ViewDebug.FlagToString(mask = MEASURED_STATE_MASK, equals = MEASURED_STATE_TOO_SMALL, 13234 name = "MEASURED_STATE_TOO_SMALL"), 13235 }) 13236 public final int getMeasuredWidthAndState() { 13237 return mMeasuredWidth; 13238 } 13239 13240 /** 13241 * Like {@link #getMeasuredHeightAndState()}, but only returns the 13242 * raw height component (that is the result is masked by 13243 * {@link #MEASURED_SIZE_MASK}). 13244 * 13245 * @return The raw measured height of this view. 13246 */ 13247 public final int getMeasuredHeight() { 13248 return mMeasuredHeight & MEASURED_SIZE_MASK; 13249 } 13250 13251 /** 13252 * Return the full height measurement information for this view as computed 13253 * by the most recent call to {@link #measure(int, int)}. This result is a bit mask 13254 * as defined by {@link #MEASURED_SIZE_MASK} and {@link #MEASURED_STATE_TOO_SMALL}. 13255 * This should be used during measurement and layout calculations only. Use 13256 * {@link #getHeight()} to see how wide a view is after layout. 13257 * 13258 * @return The measured height of this view as a bit mask. 13259 */ 13260 @ViewDebug.ExportedProperty(category = "measurement", flagMapping = { 13261 @ViewDebug.FlagToString(mask = MEASURED_STATE_MASK, equals = MEASURED_STATE_TOO_SMALL, 13262 name = "MEASURED_STATE_TOO_SMALL"), 13263 }) 13264 public final int getMeasuredHeightAndState() { 13265 return mMeasuredHeight; 13266 } 13267 13268 /** 13269 * Return only the state bits of {@link #getMeasuredWidthAndState()} 13270 * and {@link #getMeasuredHeightAndState()}, combined into one integer. 13271 * The width component is in the regular bits {@link #MEASURED_STATE_MASK} 13272 * and the height component is at the shifted bits 13273 * {@link #MEASURED_HEIGHT_STATE_SHIFT}>>{@link #MEASURED_STATE_MASK}. 13274 */ 13275 public final int getMeasuredState() { 13276 return (mMeasuredWidth&MEASURED_STATE_MASK) 13277 | ((mMeasuredHeight>>MEASURED_HEIGHT_STATE_SHIFT) 13278 & (MEASURED_STATE_MASK>>MEASURED_HEIGHT_STATE_SHIFT)); 13279 } 13280 13281 /** 13282 * The transform matrix of this view, which is calculated based on the current 13283 * rotation, scale, and pivot properties. 13284 * 13285 * @see #getRotation() 13286 * @see #getScaleX() 13287 * @see #getScaleY() 13288 * @see #getPivotX() 13289 * @see #getPivotY() 13290 * @return The current transform matrix for the view 13291 */ 13292 public Matrix getMatrix() { 13293 ensureTransformationInfo(); 13294 final Matrix matrix = mTransformationInfo.mMatrix; 13295 mRenderNode.getMatrix(matrix); 13296 return matrix; 13297 } 13298 13299 /** 13300 * Returns true if the transform matrix is the identity matrix. 13301 * Recomputes the matrix if necessary. 13302 * 13303 * @return True if the transform matrix is the identity matrix, false otherwise. 13304 */ 13305 final boolean hasIdentityMatrix() { 13306 return mRenderNode.hasIdentityMatrix(); 13307 } 13308 13309 void ensureTransformationInfo() { 13310 if (mTransformationInfo == null) { 13311 mTransformationInfo = new TransformationInfo(); 13312 } 13313 } 13314 13315 /** 13316 * Utility method to retrieve the inverse of the current mMatrix property. 13317 * We cache the matrix to avoid recalculating it when transform properties 13318 * have not changed. 13319 * 13320 * @return The inverse of the current matrix of this view. 13321 * @hide 13322 */ 13323 public final Matrix getInverseMatrix() { 13324 ensureTransformationInfo(); 13325 if (mTransformationInfo.mInverseMatrix == null) { 13326 mTransformationInfo.mInverseMatrix = new Matrix(); 13327 } 13328 final Matrix matrix = mTransformationInfo.mInverseMatrix; 13329 mRenderNode.getInverseMatrix(matrix); 13330 return matrix; 13331 } 13332 13333 /** 13334 * Gets the distance along the Z axis from the camera to this view. 13335 * 13336 * @see #setCameraDistance(float) 13337 * 13338 * @return The distance along the Z axis. 13339 */ 13340 public float getCameraDistance() { 13341 final float dpi = mResources.getDisplayMetrics().densityDpi; 13342 return -(mRenderNode.getCameraDistance() * dpi); 13343 } 13344 13345 /** 13346 * <p>Sets the distance along the Z axis (orthogonal to the X/Y plane on which 13347 * views are drawn) from the camera to this view. The camera's distance 13348 * affects 3D transformations, for instance rotations around the X and Y 13349 * axis. If the rotationX or rotationY properties are changed and this view is 13350 * large (more than half the size of the screen), it is recommended to always 13351 * use a camera distance that's greater than the height (X axis rotation) or 13352 * the width (Y axis rotation) of this view.</p> 13353 * 13354 * <p>The distance of the camera from the view plane can have an affect on the 13355 * perspective distortion of the view when it is rotated around the x or y axis. 13356 * For example, a large distance will result in a large viewing angle, and there 13357 * will not be much perspective distortion of the view as it rotates. A short 13358 * distance may cause much more perspective distortion upon rotation, and can 13359 * also result in some drawing artifacts if the rotated view ends up partially 13360 * behind the camera (which is why the recommendation is to use a distance at 13361 * least as far as the size of the view, if the view is to be rotated.)</p> 13362 * 13363 * <p>The distance is expressed in "depth pixels." The default distance depends 13364 * on the screen density. For instance, on a medium density display, the 13365 * default distance is 1280. On a high density display, the default distance 13366 * is 1920.</p> 13367 * 13368 * <p>If you want to specify a distance that leads to visually consistent 13369 * results across various densities, use the following formula:</p> 13370 * <pre> 13371 * float scale = context.getResources().getDisplayMetrics().density; 13372 * view.setCameraDistance(distance * scale); 13373 * </pre> 13374 * 13375 * <p>The density scale factor of a high density display is 1.5, 13376 * and 1920 = 1280 * 1.5.</p> 13377 * 13378 * @param distance The distance in "depth pixels", if negative the opposite 13379 * value is used 13380 * 13381 * @see #setRotationX(float) 13382 * @see #setRotationY(float) 13383 */ 13384 public void setCameraDistance(float distance) { 13385 final float dpi = mResources.getDisplayMetrics().densityDpi; 13386 13387 invalidateViewProperty(true, false); 13388 mRenderNode.setCameraDistance(-Math.abs(distance) / dpi); 13389 invalidateViewProperty(false, false); 13390 13391 invalidateParentIfNeededAndWasQuickRejected(); 13392 } 13393 13394 /** 13395 * The degrees that the view is rotated around the pivot point. 13396 * 13397 * @see #setRotation(float) 13398 * @see #getPivotX() 13399 * @see #getPivotY() 13400 * 13401 * @return The degrees of rotation. 13402 */ 13403 @ViewDebug.ExportedProperty(category = "drawing") 13404 public float getRotation() { 13405 return mRenderNode.getRotation(); 13406 } 13407 13408 /** 13409 * Sets the degrees that the view is rotated around the pivot point. Increasing values 13410 * result in clockwise rotation. 13411 * 13412 * @param rotation The degrees of rotation. 13413 * 13414 * @see #getRotation() 13415 * @see #getPivotX() 13416 * @see #getPivotY() 13417 * @see #setRotationX(float) 13418 * @see #setRotationY(float) 13419 * 13420 * @attr ref android.R.styleable#View_rotation 13421 */ 13422 public void setRotation(float rotation) { 13423 if (rotation != getRotation()) { 13424 // Double-invalidation is necessary to capture view's old and new areas 13425 invalidateViewProperty(true, false); 13426 mRenderNode.setRotation(rotation); 13427 invalidateViewProperty(false, true); 13428 13429 invalidateParentIfNeededAndWasQuickRejected(); 13430 notifySubtreeAccessibilityStateChangedIfNeeded(); 13431 } 13432 } 13433 13434 /** 13435 * The degrees that the view is rotated around the vertical axis through the pivot point. 13436 * 13437 * @see #getPivotX() 13438 * @see #getPivotY() 13439 * @see #setRotationY(float) 13440 * 13441 * @return The degrees of Y rotation. 13442 */ 13443 @ViewDebug.ExportedProperty(category = "drawing") 13444 public float getRotationY() { 13445 return mRenderNode.getRotationY(); 13446 } 13447 13448 /** 13449 * Sets the degrees that the view is rotated around the vertical axis through the pivot point. 13450 * Increasing values result in counter-clockwise rotation from the viewpoint of looking 13451 * down the y axis. 13452 * 13453 * When rotating large views, it is recommended to adjust the camera distance 13454 * accordingly. Refer to {@link #setCameraDistance(float)} for more information. 13455 * 13456 * @param rotationY The degrees of Y rotation. 13457 * 13458 * @see #getRotationY() 13459 * @see #getPivotX() 13460 * @see #getPivotY() 13461 * @see #setRotation(float) 13462 * @see #setRotationX(float) 13463 * @see #setCameraDistance(float) 13464 * 13465 * @attr ref android.R.styleable#View_rotationY 13466 */ 13467 public void setRotationY(float rotationY) { 13468 if (rotationY != getRotationY()) { 13469 invalidateViewProperty(true, false); 13470 mRenderNode.setRotationY(rotationY); 13471 invalidateViewProperty(false, true); 13472 13473 invalidateParentIfNeededAndWasQuickRejected(); 13474 notifySubtreeAccessibilityStateChangedIfNeeded(); 13475 } 13476 } 13477 13478 /** 13479 * The degrees that the view is rotated around the horizontal axis through the pivot point. 13480 * 13481 * @see #getPivotX() 13482 * @see #getPivotY() 13483 * @see #setRotationX(float) 13484 * 13485 * @return The degrees of X rotation. 13486 */ 13487 @ViewDebug.ExportedProperty(category = "drawing") 13488 public float getRotationX() { 13489 return mRenderNode.getRotationX(); 13490 } 13491 13492 /** 13493 * Sets the degrees that the view is rotated around the horizontal axis through the pivot point. 13494 * Increasing values result in clockwise rotation from the viewpoint of looking down the 13495 * x axis. 13496 * 13497 * When rotating large views, it is recommended to adjust the camera distance 13498 * accordingly. Refer to {@link #setCameraDistance(float)} for more information. 13499 * 13500 * @param rotationX The degrees of X rotation. 13501 * 13502 * @see #getRotationX() 13503 * @see #getPivotX() 13504 * @see #getPivotY() 13505 * @see #setRotation(float) 13506 * @see #setRotationY(float) 13507 * @see #setCameraDistance(float) 13508 * 13509 * @attr ref android.R.styleable#View_rotationX 13510 */ 13511 public void setRotationX(float rotationX) { 13512 if (rotationX != getRotationX()) { 13513 invalidateViewProperty(true, false); 13514 mRenderNode.setRotationX(rotationX); 13515 invalidateViewProperty(false, true); 13516 13517 invalidateParentIfNeededAndWasQuickRejected(); 13518 notifySubtreeAccessibilityStateChangedIfNeeded(); 13519 } 13520 } 13521 13522 /** 13523 * The amount that the view is scaled in x around the pivot point, as a proportion of 13524 * the view's unscaled width. A value of 1, the default, means that no scaling is applied. 13525 * 13526 * <p>By default, this is 1.0f. 13527 * 13528 * @see #getPivotX() 13529 * @see #getPivotY() 13530 * @return The scaling factor. 13531 */ 13532 @ViewDebug.ExportedProperty(category = "drawing") 13533 public float getScaleX() { 13534 return mRenderNode.getScaleX(); 13535 } 13536 13537 /** 13538 * Sets the amount that the view is scaled in x around the pivot point, as a proportion of 13539 * the view's unscaled width. A value of 1 means that no scaling is applied. 13540 * 13541 * @param scaleX The scaling factor. 13542 * @see #getPivotX() 13543 * @see #getPivotY() 13544 * 13545 * @attr ref android.R.styleable#View_scaleX 13546 */ 13547 public void setScaleX(float scaleX) { 13548 if (scaleX != getScaleX()) { 13549 invalidateViewProperty(true, false); 13550 mRenderNode.setScaleX(scaleX); 13551 invalidateViewProperty(false, true); 13552 13553 invalidateParentIfNeededAndWasQuickRejected(); 13554 notifySubtreeAccessibilityStateChangedIfNeeded(); 13555 } 13556 } 13557 13558 /** 13559 * The amount that the view is scaled in y around the pivot point, as a proportion of 13560 * the view's unscaled height. A value of 1, the default, means that no scaling is applied. 13561 * 13562 * <p>By default, this is 1.0f. 13563 * 13564 * @see #getPivotX() 13565 * @see #getPivotY() 13566 * @return The scaling factor. 13567 */ 13568 @ViewDebug.ExportedProperty(category = "drawing") 13569 public float getScaleY() { 13570 return mRenderNode.getScaleY(); 13571 } 13572 13573 /** 13574 * Sets the amount that the view is scaled in Y around the pivot point, as a proportion of 13575 * the view's unscaled width. A value of 1 means that no scaling is applied. 13576 * 13577 * @param scaleY The scaling factor. 13578 * @see #getPivotX() 13579 * @see #getPivotY() 13580 * 13581 * @attr ref android.R.styleable#View_scaleY 13582 */ 13583 public void setScaleY(float scaleY) { 13584 if (scaleY != getScaleY()) { 13585 invalidateViewProperty(true, false); 13586 mRenderNode.setScaleY(scaleY); 13587 invalidateViewProperty(false, true); 13588 13589 invalidateParentIfNeededAndWasQuickRejected(); 13590 notifySubtreeAccessibilityStateChangedIfNeeded(); 13591 } 13592 } 13593 13594 /** 13595 * The x location of the point around which the view is {@link #setRotation(float) rotated} 13596 * and {@link #setScaleX(float) scaled}. 13597 * 13598 * @see #getRotation() 13599 * @see #getScaleX() 13600 * @see #getScaleY() 13601 * @see #getPivotY() 13602 * @return The x location of the pivot point. 13603 * 13604 * @attr ref android.R.styleable#View_transformPivotX 13605 */ 13606 @ViewDebug.ExportedProperty(category = "drawing") 13607 public float getPivotX() { 13608 return mRenderNode.getPivotX(); 13609 } 13610 13611 /** 13612 * Sets the x location of the point around which the view is 13613 * {@link #setRotation(float) rotated} and {@link #setScaleX(float) scaled}. 13614 * By default, the pivot point is centered on the object. 13615 * Setting this property disables this behavior and causes the view to use only the 13616 * explicitly set pivotX and pivotY values. 13617 * 13618 * @param pivotX The x location of the pivot point. 13619 * @see #getRotation() 13620 * @see #getScaleX() 13621 * @see #getScaleY() 13622 * @see #getPivotY() 13623 * 13624 * @attr ref android.R.styleable#View_transformPivotX 13625 */ 13626 public void setPivotX(float pivotX) { 13627 if (!mRenderNode.isPivotExplicitlySet() || pivotX != getPivotX()) { 13628 invalidateViewProperty(true, false); 13629 mRenderNode.setPivotX(pivotX); 13630 invalidateViewProperty(false, true); 13631 13632 invalidateParentIfNeededAndWasQuickRejected(); 13633 } 13634 } 13635 13636 /** 13637 * The y location of the point around which the view is {@link #setRotation(float) rotated} 13638 * and {@link #setScaleY(float) scaled}. 13639 * 13640 * @see #getRotation() 13641 * @see #getScaleX() 13642 * @see #getScaleY() 13643 * @see #getPivotY() 13644 * @return The y location of the pivot point. 13645 * 13646 * @attr ref android.R.styleable#View_transformPivotY 13647 */ 13648 @ViewDebug.ExportedProperty(category = "drawing") 13649 public float getPivotY() { 13650 return mRenderNode.getPivotY(); 13651 } 13652 13653 /** 13654 * Sets the y location of the point around which the view is {@link #setRotation(float) rotated} 13655 * and {@link #setScaleY(float) scaled}. By default, the pivot point is centered on the object. 13656 * Setting this property disables this behavior and causes the view to use only the 13657 * explicitly set pivotX and pivotY values. 13658 * 13659 * @param pivotY The y location of the pivot point. 13660 * @see #getRotation() 13661 * @see #getScaleX() 13662 * @see #getScaleY() 13663 * @see #getPivotY() 13664 * 13665 * @attr ref android.R.styleable#View_transformPivotY 13666 */ 13667 public void setPivotY(float pivotY) { 13668 if (!mRenderNode.isPivotExplicitlySet() || pivotY != getPivotY()) { 13669 invalidateViewProperty(true, false); 13670 mRenderNode.setPivotY(pivotY); 13671 invalidateViewProperty(false, true); 13672 13673 invalidateParentIfNeededAndWasQuickRejected(); 13674 } 13675 } 13676 13677 /** 13678 * The opacity of the view. This is a value from 0 to 1, where 0 means the view is 13679 * completely transparent and 1 means the view is completely opaque. 13680 * 13681 * <p>By default this is 1.0f. 13682 * @return The opacity of the view. 13683 */ 13684 @ViewDebug.ExportedProperty(category = "drawing") 13685 public float getAlpha() { 13686 return mTransformationInfo != null ? mTransformationInfo.mAlpha : 1; 13687 } 13688 13689 /** 13690 * Sets the behavior for overlapping rendering for this view (see {@link 13691 * #hasOverlappingRendering()} for more details on this behavior). Calling this method 13692 * is an alternative to overriding {@link #hasOverlappingRendering()} in a subclass, 13693 * providing the value which is then used internally. That is, when {@link 13694 * #forceHasOverlappingRendering(boolean)} is called, the value of {@link 13695 * #hasOverlappingRendering()} is ignored and the value passed into this method is used 13696 * instead. 13697 * 13698 * @param hasOverlappingRendering The value for overlapping rendering to be used internally 13699 * instead of that returned by {@link #hasOverlappingRendering()}. 13700 * 13701 * @attr ref android.R.styleable#View_forceHasOverlappingRendering 13702 */ 13703 public void forceHasOverlappingRendering(boolean hasOverlappingRendering) { 13704 mPrivateFlags3 |= PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED; 13705 if (hasOverlappingRendering) { 13706 mPrivateFlags3 |= PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE; 13707 } else { 13708 mPrivateFlags3 &= ~PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE; 13709 } 13710 } 13711 13712 /** 13713 * Returns the value for overlapping rendering that is used internally. This is either 13714 * the value passed into {@link #forceHasOverlappingRendering(boolean)}, if called, or 13715 * the return value of {@link #hasOverlappingRendering()}, otherwise. 13716 * 13717 * @return The value for overlapping rendering being used internally. 13718 */ 13719 public final boolean getHasOverlappingRendering() { 13720 return (mPrivateFlags3 & PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED) != 0 ? 13721 (mPrivateFlags3 & PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE) != 0 : 13722 hasOverlappingRendering(); 13723 } 13724 13725 /** 13726 * Returns whether this View has content which overlaps. 13727 * 13728 * <p>This function, intended to be overridden by specific View types, is an optimization when 13729 * alpha is set on a view. If rendering overlaps in a view with alpha < 1, that view is drawn to 13730 * an offscreen buffer and then composited into place, which can be expensive. If the view has 13731 * no overlapping rendering, the view can draw each primitive with the appropriate alpha value 13732 * directly. An example of overlapping rendering is a TextView with a background image, such as 13733 * a Button. An example of non-overlapping rendering is a TextView with no background, or an 13734 * ImageView with only the foreground image. The default implementation returns true; subclasses 13735 * should override if they have cases which can be optimized.</p> 13736 * 13737 * <p>The current implementation of the saveLayer and saveLayerAlpha methods in {@link Canvas} 13738 * necessitates that a View return true if it uses the methods internally without passing the 13739 * {@link Canvas#CLIP_TO_LAYER_SAVE_FLAG}.</p> 13740 * 13741 * <p><strong>Note:</strong> The return value of this method is ignored if {@link 13742 * #forceHasOverlappingRendering(boolean)} has been called on this view.</p> 13743 * 13744 * @return true if the content in this view might overlap, false otherwise. 13745 */ 13746 @ViewDebug.ExportedProperty(category = "drawing") 13747 public boolean hasOverlappingRendering() { 13748 return true; 13749 } 13750 13751 /** 13752 * Sets the opacity of the view to a value from 0 to 1, where 0 means the view is 13753 * completely transparent and 1 means the view is completely opaque. 13754 * 13755 * <p class="note"><strong>Note:</strong> setting alpha to a translucent value (0 < alpha < 1) 13756 * can have significant performance implications, especially for large views. It is best to use 13757 * the alpha property sparingly and transiently, as in the case of fading animations.</p> 13758 * 13759 * <p>For a view with a frequently changing alpha, such as during a fading animation, it is 13760 * strongly recommended for performance reasons to either override 13761 * {@link #hasOverlappingRendering()} to return <code>false</code> if appropriate, or setting a 13762 * {@link #setLayerType(int, android.graphics.Paint) layer type} on the view for the duration 13763 * of the animation. On versions {@link android.os.Build.VERSION_CODES#M} and below, 13764 * the default path for rendering an unlayered View with alpha could add multiple milliseconds 13765 * of rendering cost, even for simple or small views. Starting with 13766 * {@link android.os.Build.VERSION_CODES#M}, {@link #LAYER_TYPE_HARDWARE} is automatically 13767 * applied to the view at the rendering level.</p> 13768 * 13769 * <p>If this view overrides {@link #onSetAlpha(int)} to return true, then this view is 13770 * responsible for applying the opacity itself.</p> 13771 * 13772 * <p>On versions {@link android.os.Build.VERSION_CODES#LOLLIPOP_MR1} and below, note that if 13773 * the view is backed by a {@link #setLayerType(int, android.graphics.Paint) layer} and is 13774 * associated with a {@link #setLayerPaint(android.graphics.Paint) layer paint}, setting an 13775 * alpha value less than 1.0 will supersede the alpha of the layer paint.</p> 13776 * 13777 * <p>Starting with {@link android.os.Build.VERSION_CODES#M}, setting a translucent alpha 13778 * value will clip a View to its bounds, unless the View returns <code>false</code> from 13779 * {@link #hasOverlappingRendering}.</p> 13780 * 13781 * @param alpha The opacity of the view. 13782 * 13783 * @see #hasOverlappingRendering() 13784 * @see #setLayerType(int, android.graphics.Paint) 13785 * 13786 * @attr ref android.R.styleable#View_alpha 13787 */ 13788 public void setAlpha(@FloatRange(from=0.0, to=1.0) float alpha) { 13789 ensureTransformationInfo(); 13790 if (mTransformationInfo.mAlpha != alpha) { 13791 // Report visibility changes, which can affect children, to accessibility 13792 if ((alpha == 0) ^ (mTransformationInfo.mAlpha == 0)) { 13793 notifySubtreeAccessibilityStateChangedIfNeeded(); 13794 } 13795 mTransformationInfo.mAlpha = alpha; 13796 if (onSetAlpha((int) (alpha * 255))) { 13797 mPrivateFlags |= PFLAG_ALPHA_SET; 13798 // subclass is handling alpha - don't optimize rendering cache invalidation 13799 invalidateParentCaches(); 13800 invalidate(true); 13801 } else { 13802 mPrivateFlags &= ~PFLAG_ALPHA_SET; 13803 invalidateViewProperty(true, false); 13804 mRenderNode.setAlpha(getFinalAlpha()); 13805 } 13806 } 13807 } 13808 13809 /** 13810 * Faster version of setAlpha() which performs the same steps except there are 13811 * no calls to invalidate(). The caller of this function should perform proper invalidation 13812 * on the parent and this object. The return value indicates whether the subclass handles 13813 * alpha (the return value for onSetAlpha()). 13814 * 13815 * @param alpha The new value for the alpha property 13816 * @return true if the View subclass handles alpha (the return value for onSetAlpha()) and 13817 * the new value for the alpha property is different from the old value 13818 */ 13819 boolean setAlphaNoInvalidation(float alpha) { 13820 ensureTransformationInfo(); 13821 if (mTransformationInfo.mAlpha != alpha) { 13822 mTransformationInfo.mAlpha = alpha; 13823 boolean subclassHandlesAlpha = onSetAlpha((int) (alpha * 255)); 13824 if (subclassHandlesAlpha) { 13825 mPrivateFlags |= PFLAG_ALPHA_SET; 13826 return true; 13827 } else { 13828 mPrivateFlags &= ~PFLAG_ALPHA_SET; 13829 mRenderNode.setAlpha(getFinalAlpha()); 13830 } 13831 } 13832 return false; 13833 } 13834 13835 /** 13836 * This property is hidden and intended only for use by the Fade transition, which 13837 * animates it to produce a visual translucency that does not side-effect (or get 13838 * affected by) the real alpha property. This value is composited with the other 13839 * alpha value (and the AlphaAnimation value, when that is present) to produce 13840 * a final visual translucency result, which is what is passed into the DisplayList. 13841 * 13842 * @hide 13843 */ 13844 public void setTransitionAlpha(float alpha) { 13845 ensureTransformationInfo(); 13846 if (mTransformationInfo.mTransitionAlpha != alpha) { 13847 mTransformationInfo.mTransitionAlpha = alpha; 13848 mPrivateFlags &= ~PFLAG_ALPHA_SET; 13849 invalidateViewProperty(true, false); 13850 mRenderNode.setAlpha(getFinalAlpha()); 13851 } 13852 } 13853 13854 /** 13855 * Calculates the visual alpha of this view, which is a combination of the actual 13856 * alpha value and the transitionAlpha value (if set). 13857 */ 13858 private float getFinalAlpha() { 13859 if (mTransformationInfo != null) { 13860 return mTransformationInfo.mAlpha * mTransformationInfo.mTransitionAlpha; 13861 } 13862 return 1; 13863 } 13864 13865 /** 13866 * This property is hidden and intended only for use by the Fade transition, which 13867 * animates it to produce a visual translucency that does not side-effect (or get 13868 * affected by) the real alpha property. This value is composited with the other 13869 * alpha value (and the AlphaAnimation value, when that is present) to produce 13870 * a final visual translucency result, which is what is passed into the DisplayList. 13871 * 13872 * @hide 13873 */ 13874 @ViewDebug.ExportedProperty(category = "drawing") 13875 public float getTransitionAlpha() { 13876 return mTransformationInfo != null ? mTransformationInfo.mTransitionAlpha : 1; 13877 } 13878 13879 /** 13880 * Top position of this view relative to its parent. 13881 * 13882 * @return The top of this view, in pixels. 13883 */ 13884 @ViewDebug.CapturedViewProperty 13885 public final int getTop() { 13886 return mTop; 13887 } 13888 13889 /** 13890 * Sets the top position of this view relative to its parent. This method is meant to be called 13891 * by the layout system and should not generally be called otherwise, because the property 13892 * may be changed at any time by the layout. 13893 * 13894 * @param top The top of this view, in pixels. 13895 */ 13896 public final void setTop(int top) { 13897 if (top != mTop) { 13898 final boolean matrixIsIdentity = hasIdentityMatrix(); 13899 if (matrixIsIdentity) { 13900 if (mAttachInfo != null) { 13901 int minTop; 13902 int yLoc; 13903 if (top < mTop) { 13904 minTop = top; 13905 yLoc = top - mTop; 13906 } else { 13907 minTop = mTop; 13908 yLoc = 0; 13909 } 13910 invalidate(0, yLoc, mRight - mLeft, mBottom - minTop); 13911 } 13912 } else { 13913 // Double-invalidation is necessary to capture view's old and new areas 13914 invalidate(true); 13915 } 13916 13917 int width = mRight - mLeft; 13918 int oldHeight = mBottom - mTop; 13919 13920 mTop = top; 13921 mRenderNode.setTop(mTop); 13922 13923 sizeChange(width, mBottom - mTop, width, oldHeight); 13924 13925 if (!matrixIsIdentity) { 13926 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 13927 invalidate(true); 13928 } 13929 mBackgroundSizeChanged = true; 13930 mDefaultFocusHighlightSizeChanged = true; 13931 if (mForegroundInfo != null) { 13932 mForegroundInfo.mBoundsChanged = true; 13933 } 13934 invalidateParentIfNeeded(); 13935 if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) { 13936 // View was rejected last time it was drawn by its parent; this may have changed 13937 invalidateParentIfNeeded(); 13938 } 13939 } 13940 } 13941 13942 /** 13943 * Bottom position of this view relative to its parent. 13944 * 13945 * @return The bottom of this view, in pixels. 13946 */ 13947 @ViewDebug.CapturedViewProperty 13948 public final int getBottom() { 13949 return mBottom; 13950 } 13951 13952 /** 13953 * True if this view has changed since the last time being drawn. 13954 * 13955 * @return The dirty state of this view. 13956 */ 13957 public boolean isDirty() { 13958 return (mPrivateFlags & PFLAG_DIRTY_MASK) != 0; 13959 } 13960 13961 /** 13962 * Sets the bottom position of this view relative to its parent. This method is meant to be 13963 * called by the layout system and should not generally be called otherwise, because the 13964 * property may be changed at any time by the layout. 13965 * 13966 * @param bottom The bottom of this view, in pixels. 13967 */ 13968 public final void setBottom(int bottom) { 13969 if (bottom != mBottom) { 13970 final boolean matrixIsIdentity = hasIdentityMatrix(); 13971 if (matrixIsIdentity) { 13972 if (mAttachInfo != null) { 13973 int maxBottom; 13974 if (bottom < mBottom) { 13975 maxBottom = mBottom; 13976 } else { 13977 maxBottom = bottom; 13978 } 13979 invalidate(0, 0, mRight - mLeft, maxBottom - mTop); 13980 } 13981 } else { 13982 // Double-invalidation is necessary to capture view's old and new areas 13983 invalidate(true); 13984 } 13985 13986 int width = mRight - mLeft; 13987 int oldHeight = mBottom - mTop; 13988 13989 mBottom = bottom; 13990 mRenderNode.setBottom(mBottom); 13991 13992 sizeChange(width, mBottom - mTop, width, oldHeight); 13993 13994 if (!matrixIsIdentity) { 13995 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 13996 invalidate(true); 13997 } 13998 mBackgroundSizeChanged = true; 13999 mDefaultFocusHighlightSizeChanged = true; 14000 if (mForegroundInfo != null) { 14001 mForegroundInfo.mBoundsChanged = true; 14002 } 14003 invalidateParentIfNeeded(); 14004 if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) { 14005 // View was rejected last time it was drawn by its parent; this may have changed 14006 invalidateParentIfNeeded(); 14007 } 14008 } 14009 } 14010 14011 /** 14012 * Left position of this view relative to its parent. 14013 * 14014 * @return The left edge of this view, in pixels. 14015 */ 14016 @ViewDebug.CapturedViewProperty 14017 public final int getLeft() { 14018 return mLeft; 14019 } 14020 14021 /** 14022 * Sets the left position of this view relative to its parent. This method is meant to be called 14023 * by the layout system and should not generally be called otherwise, because the property 14024 * may be changed at any time by the layout. 14025 * 14026 * @param left The left of this view, in pixels. 14027 */ 14028 public final void setLeft(int left) { 14029 if (left != mLeft) { 14030 final boolean matrixIsIdentity = hasIdentityMatrix(); 14031 if (matrixIsIdentity) { 14032 if (mAttachInfo != null) { 14033 int minLeft; 14034 int xLoc; 14035 if (left < mLeft) { 14036 minLeft = left; 14037 xLoc = left - mLeft; 14038 } else { 14039 minLeft = mLeft; 14040 xLoc = 0; 14041 } 14042 invalidate(xLoc, 0, mRight - minLeft, mBottom - mTop); 14043 } 14044 } else { 14045 // Double-invalidation is necessary to capture view's old and new areas 14046 invalidate(true); 14047 } 14048 14049 int oldWidth = mRight - mLeft; 14050 int height = mBottom - mTop; 14051 14052 mLeft = left; 14053 mRenderNode.setLeft(left); 14054 14055 sizeChange(mRight - mLeft, height, oldWidth, height); 14056 14057 if (!matrixIsIdentity) { 14058 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 14059 invalidate(true); 14060 } 14061 mBackgroundSizeChanged = true; 14062 mDefaultFocusHighlightSizeChanged = true; 14063 if (mForegroundInfo != null) { 14064 mForegroundInfo.mBoundsChanged = true; 14065 } 14066 invalidateParentIfNeeded(); 14067 if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) { 14068 // View was rejected last time it was drawn by its parent; this may have changed 14069 invalidateParentIfNeeded(); 14070 } 14071 } 14072 } 14073 14074 /** 14075 * Right position of this view relative to its parent. 14076 * 14077 * @return The right edge of this view, in pixels. 14078 */ 14079 @ViewDebug.CapturedViewProperty 14080 public final int getRight() { 14081 return mRight; 14082 } 14083 14084 /** 14085 * Sets the right position of this view relative to its parent. This method is meant to be called 14086 * by the layout system and should not generally be called otherwise, because the property 14087 * may be changed at any time by the layout. 14088 * 14089 * @param right The right of this view, in pixels. 14090 */ 14091 public final void setRight(int right) { 14092 if (right != mRight) { 14093 final boolean matrixIsIdentity = hasIdentityMatrix(); 14094 if (matrixIsIdentity) { 14095 if (mAttachInfo != null) { 14096 int maxRight; 14097 if (right < mRight) { 14098 maxRight = mRight; 14099 } else { 14100 maxRight = right; 14101 } 14102 invalidate(0, 0, maxRight - mLeft, mBottom - mTop); 14103 } 14104 } else { 14105 // Double-invalidation is necessary to capture view's old and new areas 14106 invalidate(true); 14107 } 14108 14109 int oldWidth = mRight - mLeft; 14110 int height = mBottom - mTop; 14111 14112 mRight = right; 14113 mRenderNode.setRight(mRight); 14114 14115 sizeChange(mRight - mLeft, height, oldWidth, height); 14116 14117 if (!matrixIsIdentity) { 14118 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 14119 invalidate(true); 14120 } 14121 mBackgroundSizeChanged = true; 14122 mDefaultFocusHighlightSizeChanged = true; 14123 if (mForegroundInfo != null) { 14124 mForegroundInfo.mBoundsChanged = true; 14125 } 14126 invalidateParentIfNeeded(); 14127 if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) { 14128 // View was rejected last time it was drawn by its parent; this may have changed 14129 invalidateParentIfNeeded(); 14130 } 14131 } 14132 } 14133 14134 /** 14135 * The visual x position of this view, in pixels. This is equivalent to the 14136 * {@link #setTranslationX(float) translationX} property plus the current 14137 * {@link #getLeft() left} property. 14138 * 14139 * @return The visual x position of this view, in pixels. 14140 */ 14141 @ViewDebug.ExportedProperty(category = "drawing") 14142 public float getX() { 14143 return mLeft + getTranslationX(); 14144 } 14145 14146 /** 14147 * Sets the visual x position of this view, in pixels. This is equivalent to setting the 14148 * {@link #setTranslationX(float) translationX} property to be the difference between 14149 * the x value passed in and the current {@link #getLeft() left} property. 14150 * 14151 * @param x The visual x position of this view, in pixels. 14152 */ 14153 public void setX(float x) { 14154 setTranslationX(x - mLeft); 14155 } 14156 14157 /** 14158 * The visual y position of this view, in pixels. This is equivalent to the 14159 * {@link #setTranslationY(float) translationY} property plus the current 14160 * {@link #getTop() top} property. 14161 * 14162 * @return The visual y position of this view, in pixels. 14163 */ 14164 @ViewDebug.ExportedProperty(category = "drawing") 14165 public float getY() { 14166 return mTop + getTranslationY(); 14167 } 14168 14169 /** 14170 * Sets the visual y position of this view, in pixels. This is equivalent to setting the 14171 * {@link #setTranslationY(float) translationY} property to be the difference between 14172 * the y value passed in and the current {@link #getTop() top} property. 14173 * 14174 * @param y The visual y position of this view, in pixels. 14175 */ 14176 public void setY(float y) { 14177 setTranslationY(y - mTop); 14178 } 14179 14180 /** 14181 * The visual z position of this view, in pixels. This is equivalent to the 14182 * {@link #setTranslationZ(float) translationZ} property plus the current 14183 * {@link #getElevation() elevation} property. 14184 * 14185 * @return The visual z position of this view, in pixels. 14186 */ 14187 @ViewDebug.ExportedProperty(category = "drawing") 14188 public float getZ() { 14189 return getElevation() + getTranslationZ(); 14190 } 14191 14192 /** 14193 * Sets the visual z position of this view, in pixels. This is equivalent to setting the 14194 * {@link #setTranslationZ(float) translationZ} property to be the difference between 14195 * the x value passed in and the current {@link #getElevation() elevation} property. 14196 * 14197 * @param z The visual z position of this view, in pixels. 14198 */ 14199 public void setZ(float z) { 14200 setTranslationZ(z - getElevation()); 14201 } 14202 14203 /** 14204 * The base elevation of this view relative to its parent, in pixels. 14205 * 14206 * @return The base depth position of the view, in pixels. 14207 */ 14208 @ViewDebug.ExportedProperty(category = "drawing") 14209 public float getElevation() { 14210 return mRenderNode.getElevation(); 14211 } 14212 14213 /** 14214 * Sets the base elevation of this view, in pixels. 14215 * 14216 * @attr ref android.R.styleable#View_elevation 14217 */ 14218 public void setElevation(float elevation) { 14219 if (elevation != getElevation()) { 14220 invalidateViewProperty(true, false); 14221 mRenderNode.setElevation(elevation); 14222 invalidateViewProperty(false, true); 14223 14224 invalidateParentIfNeededAndWasQuickRejected(); 14225 } 14226 } 14227 14228 /** 14229 * The horizontal location of this view relative to its {@link #getLeft() left} position. 14230 * This position is post-layout, in addition to wherever the object's 14231 * layout placed it. 14232 * 14233 * @return The horizontal position of this view relative to its left position, in pixels. 14234 */ 14235 @ViewDebug.ExportedProperty(category = "drawing") 14236 public float getTranslationX() { 14237 return mRenderNode.getTranslationX(); 14238 } 14239 14240 /** 14241 * Sets the horizontal location of this view relative to its {@link #getLeft() left} position. 14242 * This effectively positions the object post-layout, in addition to wherever the object's 14243 * layout placed it. 14244 * 14245 * @param translationX The horizontal position of this view relative to its left position, 14246 * in pixels. 14247 * 14248 * @attr ref android.R.styleable#View_translationX 14249 */ 14250 public void setTranslationX(float translationX) { 14251 if (translationX != getTranslationX()) { 14252 invalidateViewProperty(true, false); 14253 mRenderNode.setTranslationX(translationX); 14254 invalidateViewProperty(false, true); 14255 14256 invalidateParentIfNeededAndWasQuickRejected(); 14257 notifySubtreeAccessibilityStateChangedIfNeeded(); 14258 } 14259 } 14260 14261 /** 14262 * The vertical location of this view relative to its {@link #getTop() top} position. 14263 * This position is post-layout, in addition to wherever the object's 14264 * layout placed it. 14265 * 14266 * @return The vertical position of this view relative to its top position, 14267 * in pixels. 14268 */ 14269 @ViewDebug.ExportedProperty(category = "drawing") 14270 public float getTranslationY() { 14271 return mRenderNode.getTranslationY(); 14272 } 14273 14274 /** 14275 * Sets the vertical location of this view relative to its {@link #getTop() top} position. 14276 * This effectively positions the object post-layout, in addition to wherever the object's 14277 * layout placed it. 14278 * 14279 * @param translationY The vertical position of this view relative to its top position, 14280 * in pixels. 14281 * 14282 * @attr ref android.R.styleable#View_translationY 14283 */ 14284 public void setTranslationY(float translationY) { 14285 if (translationY != getTranslationY()) { 14286 invalidateViewProperty(true, false); 14287 mRenderNode.setTranslationY(translationY); 14288 invalidateViewProperty(false, true); 14289 14290 invalidateParentIfNeededAndWasQuickRejected(); 14291 notifySubtreeAccessibilityStateChangedIfNeeded(); 14292 } 14293 } 14294 14295 /** 14296 * The depth location of this view relative to its {@link #getElevation() elevation}. 14297 * 14298 * @return The depth of this view relative to its elevation. 14299 */ 14300 @ViewDebug.ExportedProperty(category = "drawing") 14301 public float getTranslationZ() { 14302 return mRenderNode.getTranslationZ(); 14303 } 14304 14305 /** 14306 * Sets the depth location of this view relative to its {@link #getElevation() elevation}. 14307 * 14308 * @attr ref android.R.styleable#View_translationZ 14309 */ 14310 public void setTranslationZ(float translationZ) { 14311 if (translationZ != getTranslationZ()) { 14312 invalidateViewProperty(true, false); 14313 mRenderNode.setTranslationZ(translationZ); 14314 invalidateViewProperty(false, true); 14315 14316 invalidateParentIfNeededAndWasQuickRejected(); 14317 } 14318 } 14319 14320 /** @hide */ 14321 public void setAnimationMatrix(Matrix matrix) { 14322 invalidateViewProperty(true, false); 14323 mRenderNode.setAnimationMatrix(matrix); 14324 invalidateViewProperty(false, true); 14325 14326 invalidateParentIfNeededAndWasQuickRejected(); 14327 } 14328 14329 /** 14330 * Returns the current StateListAnimator if exists. 14331 * 14332 * @return StateListAnimator or null if it does not exists 14333 * @see #setStateListAnimator(android.animation.StateListAnimator) 14334 */ 14335 public StateListAnimator getStateListAnimator() { 14336 return mStateListAnimator; 14337 } 14338 14339 /** 14340 * Attaches the provided StateListAnimator to this View. 14341 * <p> 14342 * Any previously attached StateListAnimator will be detached. 14343 * 14344 * @param stateListAnimator The StateListAnimator to update the view 14345 * @see android.animation.StateListAnimator 14346 */ 14347 public void setStateListAnimator(StateListAnimator stateListAnimator) { 14348 if (mStateListAnimator == stateListAnimator) { 14349 return; 14350 } 14351 if (mStateListAnimator != null) { 14352 mStateListAnimator.setTarget(null); 14353 } 14354 mStateListAnimator = stateListAnimator; 14355 if (stateListAnimator != null) { 14356 stateListAnimator.setTarget(this); 14357 if (isAttachedToWindow()) { 14358 stateListAnimator.setState(getDrawableState()); 14359 } 14360 } 14361 } 14362 14363 /** 14364 * Returns whether the Outline should be used to clip the contents of the View. 14365 * <p> 14366 * Note that this flag will only be respected if the View's Outline returns true from 14367 * {@link Outline#canClip()}. 14368 * 14369 * @see #setOutlineProvider(ViewOutlineProvider) 14370 * @see #setClipToOutline(boolean) 14371 */ 14372 public final boolean getClipToOutline() { 14373 return mRenderNode.getClipToOutline(); 14374 } 14375 14376 /** 14377 * Sets whether the View's Outline should be used to clip the contents of the View. 14378 * <p> 14379 * Only a single non-rectangular clip can be applied on a View at any time. 14380 * Circular clips from a {@link ViewAnimationUtils#createCircularReveal(View, int, int, float, float) 14381 * circular reveal} animation take priority over Outline clipping, and 14382 * child Outline clipping takes priority over Outline clipping done by a 14383 * parent. 14384 * <p> 14385 * Note that this flag will only be respected if the View's Outline returns true from 14386 * {@link Outline#canClip()}. 14387 * 14388 * @see #setOutlineProvider(ViewOutlineProvider) 14389 * @see #getClipToOutline() 14390 */ 14391 public void setClipToOutline(boolean clipToOutline) { 14392 damageInParent(); 14393 if (getClipToOutline() != clipToOutline) { 14394 mRenderNode.setClipToOutline(clipToOutline); 14395 } 14396 } 14397 14398 // correspond to the enum values of View_outlineProvider 14399 private static final int PROVIDER_BACKGROUND = 0; 14400 private static final int PROVIDER_NONE = 1; 14401 private static final int PROVIDER_BOUNDS = 2; 14402 private static final int PROVIDER_PADDED_BOUNDS = 3; 14403 private void setOutlineProviderFromAttribute(int providerInt) { 14404 switch (providerInt) { 14405 case PROVIDER_BACKGROUND: 14406 setOutlineProvider(ViewOutlineProvider.BACKGROUND); 14407 break; 14408 case PROVIDER_NONE: 14409 setOutlineProvider(null); 14410 break; 14411 case PROVIDER_BOUNDS: 14412 setOutlineProvider(ViewOutlineProvider.BOUNDS); 14413 break; 14414 case PROVIDER_PADDED_BOUNDS: 14415 setOutlineProvider(ViewOutlineProvider.PADDED_BOUNDS); 14416 break; 14417 } 14418 } 14419 14420 /** 14421 * Sets the {@link ViewOutlineProvider} of the view, which generates the Outline that defines 14422 * the shape of the shadow it casts, and enables outline clipping. 14423 * <p> 14424 * The default ViewOutlineProvider, {@link ViewOutlineProvider#BACKGROUND}, queries the Outline 14425 * from the View's background drawable, via {@link Drawable#getOutline(Outline)}. Changing the 14426 * outline provider with this method allows this behavior to be overridden. 14427 * <p> 14428 * If the ViewOutlineProvider is null, if querying it for an outline returns false, 14429 * or if the produced Outline is {@link Outline#isEmpty()}, shadows will not be cast. 14430 * <p> 14431 * Only outlines that return true from {@link Outline#canClip()} may be used for clipping. 14432 * 14433 * @see #setClipToOutline(boolean) 14434 * @see #getClipToOutline() 14435 * @see #getOutlineProvider() 14436 */ 14437 public void setOutlineProvider(ViewOutlineProvider provider) { 14438 mOutlineProvider = provider; 14439 invalidateOutline(); 14440 } 14441 14442 /** 14443 * Returns the current {@link ViewOutlineProvider} of the view, which generates the Outline 14444 * that defines the shape of the shadow it casts, and enables outline clipping. 14445 * 14446 * @see #setOutlineProvider(ViewOutlineProvider) 14447 */ 14448 public ViewOutlineProvider getOutlineProvider() { 14449 return mOutlineProvider; 14450 } 14451 14452 /** 14453 * Called to rebuild this View's Outline from its {@link ViewOutlineProvider outline provider} 14454 * 14455 * @see #setOutlineProvider(ViewOutlineProvider) 14456 */ 14457 public void invalidateOutline() { 14458 rebuildOutline(); 14459 14460 notifySubtreeAccessibilityStateChangedIfNeeded(); 14461 invalidateViewProperty(false, false); 14462 } 14463 14464 /** 14465 * Internal version of {@link #invalidateOutline()} which invalidates the 14466 * outline without invalidating the view itself. This is intended to be called from 14467 * within methods in the View class itself which are the result of the view being 14468 * invalidated already. For example, when we are drawing the background of a View, 14469 * we invalidate the outline in case it changed in the meantime, but we do not 14470 * need to invalidate the view because we're already drawing the background as part 14471 * of drawing the view in response to an earlier invalidation of the view. 14472 */ 14473 private void rebuildOutline() { 14474 // Unattached views ignore this signal, and outline is recomputed in onAttachedToWindow() 14475 if (mAttachInfo == null) return; 14476 14477 if (mOutlineProvider == null) { 14478 // no provider, remove outline 14479 mRenderNode.setOutline(null); 14480 } else { 14481 final Outline outline = mAttachInfo.mTmpOutline; 14482 outline.setEmpty(); 14483 outline.setAlpha(1.0f); 14484 14485 mOutlineProvider.getOutline(this, outline); 14486 mRenderNode.setOutline(outline); 14487 } 14488 } 14489 14490 /** 14491 * HierarchyViewer only 14492 * 14493 * @hide 14494 */ 14495 @ViewDebug.ExportedProperty(category = "drawing") 14496 public boolean hasShadow() { 14497 return mRenderNode.hasShadow(); 14498 } 14499 14500 14501 /** @hide */ 14502 public void setRevealClip(boolean shouldClip, float x, float y, float radius) { 14503 mRenderNode.setRevealClip(shouldClip, x, y, radius); 14504 invalidateViewProperty(false, false); 14505 } 14506 14507 /** 14508 * Hit rectangle in parent's coordinates 14509 * 14510 * @param outRect The hit rectangle of the view. 14511 */ 14512 public void getHitRect(Rect outRect) { 14513 if (hasIdentityMatrix() || mAttachInfo == null) { 14514 outRect.set(mLeft, mTop, mRight, mBottom); 14515 } else { 14516 final RectF tmpRect = mAttachInfo.mTmpTransformRect; 14517 tmpRect.set(0, 0, getWidth(), getHeight()); 14518 getMatrix().mapRect(tmpRect); // TODO: mRenderNode.mapRect(tmpRect) 14519 outRect.set((int) tmpRect.left + mLeft, (int) tmpRect.top + mTop, 14520 (int) tmpRect.right + mLeft, (int) tmpRect.bottom + mTop); 14521 } 14522 } 14523 14524 /** 14525 * Determines whether the given point, in local coordinates is inside the view. 14526 */ 14527 /*package*/ final boolean pointInView(float localX, float localY) { 14528 return pointInView(localX, localY, 0); 14529 } 14530 14531 /** 14532 * Utility method to determine whether the given point, in local coordinates, 14533 * is inside the view, where the area of the view is expanded by the slop factor. 14534 * This method is called while processing touch-move events to determine if the event 14535 * is still within the view. 14536 * 14537 * @hide 14538 */ 14539 public boolean pointInView(float localX, float localY, float slop) { 14540 return localX >= -slop && localY >= -slop && localX < ((mRight - mLeft) + slop) && 14541 localY < ((mBottom - mTop) + slop); 14542 } 14543 14544 /** 14545 * When a view has focus and the user navigates away from it, the next view is searched for 14546 * starting from the rectangle filled in by this method. 14547 * 14548 * By default, the rectangle is the {@link #getDrawingRect(android.graphics.Rect)}) 14549 * of the view. However, if your view maintains some idea of internal selection, 14550 * such as a cursor, or a selected row or column, you should override this method and 14551 * fill in a more specific rectangle. 14552 * 14553 * @param r The rectangle to fill in, in this view's coordinates. 14554 */ 14555 public void getFocusedRect(Rect r) { 14556 getDrawingRect(r); 14557 } 14558 14559 /** 14560 * If some part of this view is not clipped by any of its parents, then 14561 * return that area in r in global (root) coordinates. To convert r to local 14562 * coordinates (without taking possible View rotations into account), offset 14563 * it by -globalOffset (e.g. r.offset(-globalOffset.x, -globalOffset.y)). 14564 * If the view is completely clipped or translated out, return false. 14565 * 14566 * @param r If true is returned, r holds the global coordinates of the 14567 * visible portion of this view. 14568 * @param globalOffset If true is returned, globalOffset holds the dx,dy 14569 * between this view and its root. globalOffet may be null. 14570 * @return true if r is non-empty (i.e. part of the view is visible at the 14571 * root level. 14572 */ 14573 public boolean getGlobalVisibleRect(Rect r, Point globalOffset) { 14574 int width = mRight - mLeft; 14575 int height = mBottom - mTop; 14576 if (width > 0 && height > 0) { 14577 r.set(0, 0, width, height); 14578 if (globalOffset != null) { 14579 globalOffset.set(-mScrollX, -mScrollY); 14580 } 14581 return mParent == null || mParent.getChildVisibleRect(this, r, globalOffset); 14582 } 14583 return false; 14584 } 14585 14586 public final boolean getGlobalVisibleRect(Rect r) { 14587 return getGlobalVisibleRect(r, null); 14588 } 14589 14590 public final boolean getLocalVisibleRect(Rect r) { 14591 final Point offset = mAttachInfo != null ? mAttachInfo.mPoint : new Point(); 14592 if (getGlobalVisibleRect(r, offset)) { 14593 r.offset(-offset.x, -offset.y); // make r local 14594 return true; 14595 } 14596 return false; 14597 } 14598 14599 /** 14600 * Offset this view's vertical location by the specified number of pixels. 14601 * 14602 * @param offset the number of pixels to offset the view by 14603 */ 14604 public void offsetTopAndBottom(int offset) { 14605 if (offset != 0) { 14606 final boolean matrixIsIdentity = hasIdentityMatrix(); 14607 if (matrixIsIdentity) { 14608 if (isHardwareAccelerated()) { 14609 invalidateViewProperty(false, false); 14610 } else { 14611 final ViewParent p = mParent; 14612 if (p != null && mAttachInfo != null) { 14613 final Rect r = mAttachInfo.mTmpInvalRect; 14614 int minTop; 14615 int maxBottom; 14616 int yLoc; 14617 if (offset < 0) { 14618 minTop = mTop + offset; 14619 maxBottom = mBottom; 14620 yLoc = offset; 14621 } else { 14622 minTop = mTop; 14623 maxBottom = mBottom + offset; 14624 yLoc = 0; 14625 } 14626 r.set(0, yLoc, mRight - mLeft, maxBottom - minTop); 14627 p.invalidateChild(this, r); 14628 } 14629 } 14630 } else { 14631 invalidateViewProperty(false, false); 14632 } 14633 14634 mTop += offset; 14635 mBottom += offset; 14636 mRenderNode.offsetTopAndBottom(offset); 14637 if (isHardwareAccelerated()) { 14638 invalidateViewProperty(false, false); 14639 invalidateParentIfNeededAndWasQuickRejected(); 14640 } else { 14641 if (!matrixIsIdentity) { 14642 invalidateViewProperty(false, true); 14643 } 14644 invalidateParentIfNeeded(); 14645 } 14646 notifySubtreeAccessibilityStateChangedIfNeeded(); 14647 } 14648 } 14649 14650 /** 14651 * Offset this view's horizontal location by the specified amount of pixels. 14652 * 14653 * @param offset the number of pixels to offset the view by 14654 */ 14655 public void offsetLeftAndRight(int offset) { 14656 if (offset != 0) { 14657 final boolean matrixIsIdentity = hasIdentityMatrix(); 14658 if (matrixIsIdentity) { 14659 if (isHardwareAccelerated()) { 14660 invalidateViewProperty(false, false); 14661 } else { 14662 final ViewParent p = mParent; 14663 if (p != null && mAttachInfo != null) { 14664 final Rect r = mAttachInfo.mTmpInvalRect; 14665 int minLeft; 14666 int maxRight; 14667 if (offset < 0) { 14668 minLeft = mLeft + offset; 14669 maxRight = mRight; 14670 } else { 14671 minLeft = mLeft; 14672 maxRight = mRight + offset; 14673 } 14674 r.set(0, 0, maxRight - minLeft, mBottom - mTop); 14675 p.invalidateChild(this, r); 14676 } 14677 } 14678 } else { 14679 invalidateViewProperty(false, false); 14680 } 14681 14682 mLeft += offset; 14683 mRight += offset; 14684 mRenderNode.offsetLeftAndRight(offset); 14685 if (isHardwareAccelerated()) { 14686 invalidateViewProperty(false, false); 14687 invalidateParentIfNeededAndWasQuickRejected(); 14688 } else { 14689 if (!matrixIsIdentity) { 14690 invalidateViewProperty(false, true); 14691 } 14692 invalidateParentIfNeeded(); 14693 } 14694 notifySubtreeAccessibilityStateChangedIfNeeded(); 14695 } 14696 } 14697 14698 /** 14699 * Get the LayoutParams associated with this view. All views should have 14700 * layout parameters. These supply parameters to the <i>parent</i> of this 14701 * view specifying how it should be arranged. There are many subclasses of 14702 * ViewGroup.LayoutParams, and these correspond to the different subclasses 14703 * of ViewGroup that are responsible for arranging their children. 14704 * 14705 * This method may return null if this View is not attached to a parent 14706 * ViewGroup or {@link #setLayoutParams(android.view.ViewGroup.LayoutParams)} 14707 * was not invoked successfully. When a View is attached to a parent 14708 * ViewGroup, this method must not return null. 14709 * 14710 * @return The LayoutParams associated with this view, or null if no 14711 * parameters have been set yet 14712 */ 14713 @ViewDebug.ExportedProperty(deepExport = true, prefix = "layout_") 14714 public ViewGroup.LayoutParams getLayoutParams() { 14715 return mLayoutParams; 14716 } 14717 14718 /** 14719 * Set the layout parameters associated with this view. These supply 14720 * parameters to the <i>parent</i> of this view specifying how it should be 14721 * arranged. There are many subclasses of ViewGroup.LayoutParams, and these 14722 * correspond to the different subclasses of ViewGroup that are responsible 14723 * for arranging their children. 14724 * 14725 * @param params The layout parameters for this view, cannot be null 14726 */ 14727 public void setLayoutParams(ViewGroup.LayoutParams params) { 14728 if (params == null) { 14729 throw new NullPointerException("Layout parameters cannot be null"); 14730 } 14731 mLayoutParams = params; 14732 resolveLayoutParams(); 14733 if (mParent instanceof ViewGroup) { 14734 ((ViewGroup) mParent).onSetLayoutParams(this, params); 14735 } 14736 requestLayout(); 14737 } 14738 14739 /** 14740 * Resolve the layout parameters depending on the resolved layout direction 14741 * 14742 * @hide 14743 */ 14744 public void resolveLayoutParams() { 14745 if (mLayoutParams != null) { 14746 mLayoutParams.resolveLayoutDirection(getLayoutDirection()); 14747 } 14748 } 14749 14750 /** 14751 * Set the scrolled position of your view. This will cause a call to 14752 * {@link #onScrollChanged(int, int, int, int)} and the view will be 14753 * invalidated. 14754 * @param x the x position to scroll to 14755 * @param y the y position to scroll to 14756 */ 14757 public void scrollTo(int x, int y) { 14758 if (mScrollX != x || mScrollY != y) { 14759 int oldX = mScrollX; 14760 int oldY = mScrollY; 14761 mScrollX = x; 14762 mScrollY = y; 14763 invalidateParentCaches(); 14764 onScrollChanged(mScrollX, mScrollY, oldX, oldY); 14765 if (!awakenScrollBars()) { 14766 postInvalidateOnAnimation(); 14767 } 14768 } 14769 } 14770 14771 /** 14772 * Move the scrolled position of your view. This will cause a call to 14773 * {@link #onScrollChanged(int, int, int, int)} and the view will be 14774 * invalidated. 14775 * @param x the amount of pixels to scroll by horizontally 14776 * @param y the amount of pixels to scroll by vertically 14777 */ 14778 public void scrollBy(int x, int y) { 14779 scrollTo(mScrollX + x, mScrollY + y); 14780 } 14781 14782 /** 14783 * <p>Trigger the scrollbars to draw. When invoked this method starts an 14784 * animation to fade the scrollbars out after a default delay. If a subclass 14785 * provides animated scrolling, the start delay should equal the duration 14786 * of the scrolling animation.</p> 14787 * 14788 * <p>The animation starts only if at least one of the scrollbars is 14789 * enabled, as specified by {@link #isHorizontalScrollBarEnabled()} and 14790 * {@link #isVerticalScrollBarEnabled()}. When the animation is started, 14791 * this method returns true, and false otherwise. If the animation is 14792 * started, this method calls {@link #invalidate()}; in that case the 14793 * caller should not call {@link #invalidate()}.</p> 14794 * 14795 * <p>This method should be invoked every time a subclass directly updates 14796 * the scroll parameters.</p> 14797 * 14798 * <p>This method is automatically invoked by {@link #scrollBy(int, int)} 14799 * and {@link #scrollTo(int, int)}.</p> 14800 * 14801 * @return true if the animation is played, false otherwise 14802 * 14803 * @see #awakenScrollBars(int) 14804 * @see #scrollBy(int, int) 14805 * @see #scrollTo(int, int) 14806 * @see #isHorizontalScrollBarEnabled() 14807 * @see #isVerticalScrollBarEnabled() 14808 * @see #setHorizontalScrollBarEnabled(boolean) 14809 * @see #setVerticalScrollBarEnabled(boolean) 14810 */ 14811 protected boolean awakenScrollBars() { 14812 return mScrollCache != null && 14813 awakenScrollBars(mScrollCache.scrollBarDefaultDelayBeforeFade, true); 14814 } 14815 14816 /** 14817 * Trigger the scrollbars to draw. 14818 * This method differs from awakenScrollBars() only in its default duration. 14819 * initialAwakenScrollBars() will show the scroll bars for longer than 14820 * usual to give the user more of a chance to notice them. 14821 * 14822 * @return true if the animation is played, false otherwise. 14823 */ 14824 private boolean initialAwakenScrollBars() { 14825 return mScrollCache != null && 14826 awakenScrollBars(mScrollCache.scrollBarDefaultDelayBeforeFade * 4, true); 14827 } 14828 14829 /** 14830 * <p> 14831 * Trigger the scrollbars to draw. When invoked this method starts an 14832 * animation to fade the scrollbars out after a fixed delay. If a subclass 14833 * provides animated scrolling, the start delay should equal the duration of 14834 * the scrolling animation. 14835 * </p> 14836 * 14837 * <p> 14838 * The animation starts only if at least one of the scrollbars is enabled, 14839 * as specified by {@link #isHorizontalScrollBarEnabled()} and 14840 * {@link #isVerticalScrollBarEnabled()}. When the animation is started, 14841 * this method returns true, and false otherwise. If the animation is 14842 * started, this method calls {@link #invalidate()}; in that case the caller 14843 * should not call {@link #invalidate()}. 14844 * </p> 14845 * 14846 * <p> 14847 * This method should be invoked every time a subclass directly updates the 14848 * scroll parameters. 14849 * </p> 14850 * 14851 * @param startDelay the delay, in milliseconds, after which the animation 14852 * should start; when the delay is 0, the animation starts 14853 * immediately 14854 * @return true if the animation is played, false otherwise 14855 * 14856 * @see #scrollBy(int, int) 14857 * @see #scrollTo(int, int) 14858 * @see #isHorizontalScrollBarEnabled() 14859 * @see #isVerticalScrollBarEnabled() 14860 * @see #setHorizontalScrollBarEnabled(boolean) 14861 * @see #setVerticalScrollBarEnabled(boolean) 14862 */ 14863 protected boolean awakenScrollBars(int startDelay) { 14864 return awakenScrollBars(startDelay, true); 14865 } 14866 14867 /** 14868 * <p> 14869 * Trigger the scrollbars to draw. When invoked this method starts an 14870 * animation to fade the scrollbars out after a fixed delay. If a subclass 14871 * provides animated scrolling, the start delay should equal the duration of 14872 * the scrolling animation. 14873 * </p> 14874 * 14875 * <p> 14876 * The animation starts only if at least one of the scrollbars is enabled, 14877 * as specified by {@link #isHorizontalScrollBarEnabled()} and 14878 * {@link #isVerticalScrollBarEnabled()}. When the animation is started, 14879 * this method returns true, and false otherwise. If the animation is 14880 * started, this method calls {@link #invalidate()} if the invalidate parameter 14881 * is set to true; in that case the caller 14882 * should not call {@link #invalidate()}. 14883 * </p> 14884 * 14885 * <p> 14886 * This method should be invoked every time a subclass directly updates the 14887 * scroll parameters. 14888 * </p> 14889 * 14890 * @param startDelay the delay, in milliseconds, after which the animation 14891 * should start; when the delay is 0, the animation starts 14892 * immediately 14893 * 14894 * @param invalidate Whether this method should call invalidate 14895 * 14896 * @return true if the animation is played, false otherwise 14897 * 14898 * @see #scrollBy(int, int) 14899 * @see #scrollTo(int, int) 14900 * @see #isHorizontalScrollBarEnabled() 14901 * @see #isVerticalScrollBarEnabled() 14902 * @see #setHorizontalScrollBarEnabled(boolean) 14903 * @see #setVerticalScrollBarEnabled(boolean) 14904 */ 14905 protected boolean awakenScrollBars(int startDelay, boolean invalidate) { 14906 final ScrollabilityCache scrollCache = mScrollCache; 14907 14908 if (scrollCache == null || !scrollCache.fadeScrollBars) { 14909 return false; 14910 } 14911 14912 if (scrollCache.scrollBar == null) { 14913 scrollCache.scrollBar = new ScrollBarDrawable(); 14914 scrollCache.scrollBar.setState(getDrawableState()); 14915 scrollCache.scrollBar.setCallback(this); 14916 } 14917 14918 if (isHorizontalScrollBarEnabled() || isVerticalScrollBarEnabled()) { 14919 14920 if (invalidate) { 14921 // Invalidate to show the scrollbars 14922 postInvalidateOnAnimation(); 14923 } 14924 14925 if (scrollCache.state == ScrollabilityCache.OFF) { 14926 // FIXME: this is copied from WindowManagerService. 14927 // We should get this value from the system when it 14928 // is possible to do so. 14929 final int KEY_REPEAT_FIRST_DELAY = 750; 14930 startDelay = Math.max(KEY_REPEAT_FIRST_DELAY, startDelay); 14931 } 14932 14933 // Tell mScrollCache when we should start fading. This may 14934 // extend the fade start time if one was already scheduled 14935 long fadeStartTime = AnimationUtils.currentAnimationTimeMillis() + startDelay; 14936 scrollCache.fadeStartTime = fadeStartTime; 14937 scrollCache.state = ScrollabilityCache.ON; 14938 14939 // Schedule our fader to run, unscheduling any old ones first 14940 if (mAttachInfo != null) { 14941 mAttachInfo.mHandler.removeCallbacks(scrollCache); 14942 mAttachInfo.mHandler.postAtTime(scrollCache, fadeStartTime); 14943 } 14944 14945 return true; 14946 } 14947 14948 return false; 14949 } 14950 14951 /** 14952 * Do not invalidate views which are not visible and which are not running an animation. They 14953 * will not get drawn and they should not set dirty flags as if they will be drawn 14954 */ 14955 private boolean skipInvalidate() { 14956 return (mViewFlags & VISIBILITY_MASK) != VISIBLE && mCurrentAnimation == null && 14957 (!(mParent instanceof ViewGroup) || 14958 !((ViewGroup) mParent).isViewTransitioning(this)); 14959 } 14960 14961 /** 14962 * Mark the area defined by dirty as needing to be drawn. If the view is 14963 * visible, {@link #onDraw(android.graphics.Canvas)} will be called at some 14964 * point in the future. 14965 * <p> 14966 * This must be called from a UI thread. To call from a non-UI thread, call 14967 * {@link #postInvalidate()}. 14968 * <p> 14969 * <b>WARNING:</b> In API 19 and below, this method may be destructive to 14970 * {@code dirty}. 14971 * 14972 * @param dirty the rectangle representing the bounds of the dirty region 14973 */ 14974 public void invalidate(Rect dirty) { 14975 final int scrollX = mScrollX; 14976 final int scrollY = mScrollY; 14977 invalidateInternal(dirty.left - scrollX, dirty.top - scrollY, 14978 dirty.right - scrollX, dirty.bottom - scrollY, true, false); 14979 } 14980 14981 /** 14982 * Mark the area defined by the rect (l,t,r,b) as needing to be drawn. The 14983 * coordinates of the dirty rect are relative to the view. If the view is 14984 * visible, {@link #onDraw(android.graphics.Canvas)} will be called at some 14985 * point in the future. 14986 * <p> 14987 * This must be called from a UI thread. To call from a non-UI thread, call 14988 * {@link #postInvalidate()}. 14989 * 14990 * @param l the left position of the dirty region 14991 * @param t the top position of the dirty region 14992 * @param r the right position of the dirty region 14993 * @param b the bottom position of the dirty region 14994 */ 14995 public void invalidate(int l, int t, int r, int b) { 14996 final int scrollX = mScrollX; 14997 final int scrollY = mScrollY; 14998 invalidateInternal(l - scrollX, t - scrollY, r - scrollX, b - scrollY, true, false); 14999 } 15000 15001 /** 15002 * Invalidate the whole view. If the view is visible, 15003 * {@link #onDraw(android.graphics.Canvas)} will be called at some point in 15004 * the future. 15005 * <p> 15006 * This must be called from a UI thread. To call from a non-UI thread, call 15007 * {@link #postInvalidate()}. 15008 */ 15009 public void invalidate() { 15010 invalidate(true); 15011 } 15012 15013 /** 15014 * This is where the invalidate() work actually happens. A full invalidate() 15015 * causes the drawing cache to be invalidated, but this function can be 15016 * called with invalidateCache set to false to skip that invalidation step 15017 * for cases that do not need it (for example, a component that remains at 15018 * the same dimensions with the same content). 15019 * 15020 * @param invalidateCache Whether the drawing cache for this view should be 15021 * invalidated as well. This is usually true for a full 15022 * invalidate, but may be set to false if the View's contents or 15023 * dimensions have not changed. 15024 * @hide 15025 */ 15026 public void invalidate(boolean invalidateCache) { 15027 invalidateInternal(0, 0, mRight - mLeft, mBottom - mTop, invalidateCache, true); 15028 } 15029 15030 void invalidateInternal(int l, int t, int r, int b, boolean invalidateCache, 15031 boolean fullInvalidate) { 15032 if (mGhostView != null) { 15033 mGhostView.invalidate(true); 15034 return; 15035 } 15036 15037 if (skipInvalidate()) { 15038 return; 15039 } 15040 15041 if ((mPrivateFlags & (PFLAG_DRAWN | PFLAG_HAS_BOUNDS)) == (PFLAG_DRAWN | PFLAG_HAS_BOUNDS) 15042 || (invalidateCache && (mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == PFLAG_DRAWING_CACHE_VALID) 15043 || (mPrivateFlags & PFLAG_INVALIDATED) != PFLAG_INVALIDATED 15044 || (fullInvalidate && isOpaque() != mLastIsOpaque)) { 15045 if (fullInvalidate) { 15046 mLastIsOpaque = isOpaque(); 15047 mPrivateFlags &= ~PFLAG_DRAWN; 15048 } 15049 15050 mPrivateFlags |= PFLAG_DIRTY; 15051 15052 if (invalidateCache) { 15053 mPrivateFlags |= PFLAG_INVALIDATED; 15054 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; 15055 } 15056 15057 // Propagate the damage rectangle to the parent view. 15058 final AttachInfo ai = mAttachInfo; 15059 final ViewParent p = mParent; 15060 if (p != null && ai != null && l < r && t < b) { 15061 final Rect damage = ai.mTmpInvalRect; 15062 damage.set(l, t, r, b); 15063 p.invalidateChild(this, damage); 15064 } 15065 15066 // Damage the entire projection receiver, if necessary. 15067 if (mBackground != null && mBackground.isProjected()) { 15068 final View receiver = getProjectionReceiver(); 15069 if (receiver != null) { 15070 receiver.damageInParent(); 15071 } 15072 } 15073 } 15074 } 15075 15076 /** 15077 * @return this view's projection receiver, or {@code null} if none exists 15078 */ 15079 private View getProjectionReceiver() { 15080 ViewParent p = getParent(); 15081 while (p != null && p instanceof View) { 15082 final View v = (View) p; 15083 if (v.isProjectionReceiver()) { 15084 return v; 15085 } 15086 p = p.getParent(); 15087 } 15088 15089 return null; 15090 } 15091 15092 /** 15093 * @return whether the view is a projection receiver 15094 */ 15095 private boolean isProjectionReceiver() { 15096 return mBackground != null; 15097 } 15098 15099 /** 15100 * Quick invalidation for View property changes (alpha, translationXY, etc.). We don't want to 15101 * set any flags or handle all of the cases handled by the default invalidation methods. 15102 * Instead, we just want to schedule a traversal in ViewRootImpl with the appropriate 15103 * dirty rect. This method calls into fast invalidation methods in ViewGroup that 15104 * walk up the hierarchy, transforming the dirty rect as necessary. 15105 * 15106 * The method also handles normal invalidation logic if display list properties are not 15107 * being used in this view. The invalidateParent and forceRedraw flags are used by that 15108 * backup approach, to handle these cases used in the various property-setting methods. 15109 * 15110 * @param invalidateParent Force a call to invalidateParentCaches() if display list properties 15111 * are not being used in this view 15112 * @param forceRedraw Mark the view as DRAWN to force the invalidation to propagate, if display 15113 * list properties are not being used in this view 15114 */ 15115 void invalidateViewProperty(boolean invalidateParent, boolean forceRedraw) { 15116 if (!isHardwareAccelerated() 15117 || !mRenderNode.isValid() 15118 || (mPrivateFlags & PFLAG_DRAW_ANIMATION) != 0) { 15119 if (invalidateParent) { 15120 invalidateParentCaches(); 15121 } 15122 if (forceRedraw) { 15123 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 15124 } 15125 invalidate(false); 15126 } else { 15127 damageInParent(); 15128 } 15129 } 15130 15131 /** 15132 * Tells the parent view to damage this view's bounds. 15133 * 15134 * @hide 15135 */ 15136 protected void damageInParent() { 15137 if (mParent != null && mAttachInfo != null) { 15138 mParent.onDescendantInvalidated(this, this); 15139 } 15140 } 15141 15142 /** 15143 * Utility method to transform a given Rect by the current matrix of this view. 15144 */ 15145 void transformRect(final Rect rect) { 15146 if (!getMatrix().isIdentity()) { 15147 RectF boundingRect = mAttachInfo.mTmpTransformRect; 15148 boundingRect.set(rect); 15149 getMatrix().mapRect(boundingRect); 15150 rect.set((int) Math.floor(boundingRect.left), 15151 (int) Math.floor(boundingRect.top), 15152 (int) Math.ceil(boundingRect.right), 15153 (int) Math.ceil(boundingRect.bottom)); 15154 } 15155 } 15156 15157 /** 15158 * Used to indicate that the parent of this view should clear its caches. This functionality 15159 * is used to force the parent to rebuild its display list (when hardware-accelerated), 15160 * which is necessary when various parent-managed properties of the view change, such as 15161 * alpha, translationX/Y, scrollX/Y, scaleX/Y, and rotation/X/Y. This method only 15162 * clears the parent caches and does not causes an invalidate event. 15163 * 15164 * @hide 15165 */ 15166 protected void invalidateParentCaches() { 15167 if (mParent instanceof View) { 15168 ((View) mParent).mPrivateFlags |= PFLAG_INVALIDATED; 15169 } 15170 } 15171 15172 /** 15173 * Used to indicate that the parent of this view should be invalidated. This functionality 15174 * is used to force the parent to rebuild its display list (when hardware-accelerated), 15175 * which is necessary when various parent-managed properties of the view change, such as 15176 * alpha, translationX/Y, scrollX/Y, scaleX/Y, and rotation/X/Y. This method will propagate 15177 * an invalidation event to the parent. 15178 * 15179 * @hide 15180 */ 15181 protected void invalidateParentIfNeeded() { 15182 if (isHardwareAccelerated() && mParent instanceof View) { 15183 ((View) mParent).invalidate(true); 15184 } 15185 } 15186 15187 /** 15188 * @hide 15189 */ 15190 protected void invalidateParentIfNeededAndWasQuickRejected() { 15191 if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) != 0) { 15192 // View was rejected last time it was drawn by its parent; this may have changed 15193 invalidateParentIfNeeded(); 15194 } 15195 } 15196 15197 /** 15198 * Indicates whether this View is opaque. An opaque View guarantees that it will 15199 * draw all the pixels overlapping its bounds using a fully opaque color. 15200 * 15201 * Subclasses of View should override this method whenever possible to indicate 15202 * whether an instance is opaque. Opaque Views are treated in a special way by 15203 * the View hierarchy, possibly allowing it to perform optimizations during 15204 * invalidate/draw passes. 15205 * 15206 * @return True if this View is guaranteed to be fully opaque, false otherwise. 15207 */ 15208 @ViewDebug.ExportedProperty(category = "drawing") 15209 public boolean isOpaque() { 15210 return (mPrivateFlags & PFLAG_OPAQUE_MASK) == PFLAG_OPAQUE_MASK && 15211 getFinalAlpha() >= 1.0f; 15212 } 15213 15214 /** 15215 * @hide 15216 */ 15217 protected void computeOpaqueFlags() { 15218 // Opaque if: 15219 // - Has a background 15220 // - Background is opaque 15221 // - Doesn't have scrollbars or scrollbars overlay 15222 15223 if (mBackground != null && mBackground.getOpacity() == PixelFormat.OPAQUE) { 15224 mPrivateFlags |= PFLAG_OPAQUE_BACKGROUND; 15225 } else { 15226 mPrivateFlags &= ~PFLAG_OPAQUE_BACKGROUND; 15227 } 15228 15229 final int flags = mViewFlags; 15230 if (((flags & SCROLLBARS_VERTICAL) == 0 && (flags & SCROLLBARS_HORIZONTAL) == 0) || 15231 (flags & SCROLLBARS_STYLE_MASK) == SCROLLBARS_INSIDE_OVERLAY || 15232 (flags & SCROLLBARS_STYLE_MASK) == SCROLLBARS_OUTSIDE_OVERLAY) { 15233 mPrivateFlags |= PFLAG_OPAQUE_SCROLLBARS; 15234 } else { 15235 mPrivateFlags &= ~PFLAG_OPAQUE_SCROLLBARS; 15236 } 15237 } 15238 15239 /** 15240 * @hide 15241 */ 15242 protected boolean hasOpaqueScrollbars() { 15243 return (mPrivateFlags & PFLAG_OPAQUE_SCROLLBARS) == PFLAG_OPAQUE_SCROLLBARS; 15244 } 15245 15246 /** 15247 * @return A handler associated with the thread running the View. This 15248 * handler can be used to pump events in the UI events queue. 15249 */ 15250 public Handler getHandler() { 15251 final AttachInfo attachInfo = mAttachInfo; 15252 if (attachInfo != null) { 15253 return attachInfo.mHandler; 15254 } 15255 return null; 15256 } 15257 15258 /** 15259 * Returns the queue of runnable for this view. 15260 * 15261 * @return the queue of runnables for this view 15262 */ 15263 private HandlerActionQueue getRunQueue() { 15264 if (mRunQueue == null) { 15265 mRunQueue = new HandlerActionQueue(); 15266 } 15267 return mRunQueue; 15268 } 15269 15270 /** 15271 * Gets the view root associated with the View. 15272 * @return The view root, or null if none. 15273 * @hide 15274 */ 15275 public ViewRootImpl getViewRootImpl() { 15276 if (mAttachInfo != null) { 15277 return mAttachInfo.mViewRootImpl; 15278 } 15279 return null; 15280 } 15281 15282 /** 15283 * @hide 15284 */ 15285 public ThreadedRenderer getThreadedRenderer() { 15286 return mAttachInfo != null ? mAttachInfo.mThreadedRenderer : null; 15287 } 15288 15289 /** 15290 * <p>Causes the Runnable to be added to the message queue. 15291 * The runnable will be run on the user interface thread.</p> 15292 * 15293 * @param action The Runnable that will be executed. 15294 * 15295 * @return Returns true if the Runnable was successfully placed in to the 15296 * message queue. Returns false on failure, usually because the 15297 * looper processing the message queue is exiting. 15298 * 15299 * @see #postDelayed 15300 * @see #removeCallbacks 15301 */ 15302 public boolean post(Runnable action) { 15303 final AttachInfo attachInfo = mAttachInfo; 15304 if (attachInfo != null) { 15305 return attachInfo.mHandler.post(action); 15306 } 15307 15308 // Postpone the runnable until we know on which thread it needs to run. 15309 // Assume that the runnable will be successfully placed after attach. 15310 getRunQueue().post(action); 15311 return true; 15312 } 15313 15314 /** 15315 * <p>Causes the Runnable to be added to the message queue, to be run 15316 * after the specified amount of time elapses. 15317 * The runnable will be run on the user interface thread.</p> 15318 * 15319 * @param action The Runnable that will be executed. 15320 * @param delayMillis The delay (in milliseconds) until the Runnable 15321 * will be executed. 15322 * 15323 * @return true if the Runnable was successfully placed in to the 15324 * message queue. Returns false on failure, usually because the 15325 * looper processing the message queue is exiting. Note that a 15326 * result of true does not mean the Runnable will be processed -- 15327 * if the looper is quit before the delivery time of the message 15328 * occurs then the message will be dropped. 15329 * 15330 * @see #post 15331 * @see #removeCallbacks 15332 */ 15333 public boolean postDelayed(Runnable action, long delayMillis) { 15334 final AttachInfo attachInfo = mAttachInfo; 15335 if (attachInfo != null) { 15336 return attachInfo.mHandler.postDelayed(action, delayMillis); 15337 } 15338 15339 // Postpone the runnable until we know on which thread it needs to run. 15340 // Assume that the runnable will be successfully placed after attach. 15341 getRunQueue().postDelayed(action, delayMillis); 15342 return true; 15343 } 15344 15345 /** 15346 * <p>Causes the Runnable to execute on the next animation time step. 15347 * The runnable will be run on the user interface thread.</p> 15348 * 15349 * @param action The Runnable that will be executed. 15350 * 15351 * @see #postOnAnimationDelayed 15352 * @see #removeCallbacks 15353 */ 15354 public void postOnAnimation(Runnable action) { 15355 final AttachInfo attachInfo = mAttachInfo; 15356 if (attachInfo != null) { 15357 attachInfo.mViewRootImpl.mChoreographer.postCallback( 15358 Choreographer.CALLBACK_ANIMATION, action, null); 15359 } else { 15360 // Postpone the runnable until we know 15361 // on which thread it needs to run. 15362 getRunQueue().post(action); 15363 } 15364 } 15365 15366 /** 15367 * <p>Causes the Runnable to execute on the next animation time step, 15368 * after the specified amount of time elapses. 15369 * The runnable will be run on the user interface thread.</p> 15370 * 15371 * @param action The Runnable that will be executed. 15372 * @param delayMillis The delay (in milliseconds) until the Runnable 15373 * will be executed. 15374 * 15375 * @see #postOnAnimation 15376 * @see #removeCallbacks 15377 */ 15378 public void postOnAnimationDelayed(Runnable action, long delayMillis) { 15379 final AttachInfo attachInfo = mAttachInfo; 15380 if (attachInfo != null) { 15381 attachInfo.mViewRootImpl.mChoreographer.postCallbackDelayed( 15382 Choreographer.CALLBACK_ANIMATION, action, null, delayMillis); 15383 } else { 15384 // Postpone the runnable until we know 15385 // on which thread it needs to run. 15386 getRunQueue().postDelayed(action, delayMillis); 15387 } 15388 } 15389 15390 /** 15391 * <p>Removes the specified Runnable from the message queue.</p> 15392 * 15393 * @param action The Runnable to remove from the message handling queue 15394 * 15395 * @return true if this view could ask the Handler to remove the Runnable, 15396 * false otherwise. When the returned value is true, the Runnable 15397 * may or may not have been actually removed from the message queue 15398 * (for instance, if the Runnable was not in the queue already.) 15399 * 15400 * @see #post 15401 * @see #postDelayed 15402 * @see #postOnAnimation 15403 * @see #postOnAnimationDelayed 15404 */ 15405 public boolean removeCallbacks(Runnable action) { 15406 if (action != null) { 15407 final AttachInfo attachInfo = mAttachInfo; 15408 if (attachInfo != null) { 15409 attachInfo.mHandler.removeCallbacks(action); 15410 attachInfo.mViewRootImpl.mChoreographer.removeCallbacks( 15411 Choreographer.CALLBACK_ANIMATION, action, null); 15412 } 15413 getRunQueue().removeCallbacks(action); 15414 } 15415 return true; 15416 } 15417 15418 /** 15419 * <p>Cause an invalidate to happen on a subsequent cycle through the event loop. 15420 * Use this to invalidate the View from a non-UI thread.</p> 15421 * 15422 * <p>This method can be invoked from outside of the UI thread 15423 * only when this View is attached to a window.</p> 15424 * 15425 * @see #invalidate() 15426 * @see #postInvalidateDelayed(long) 15427 */ 15428 public void postInvalidate() { 15429 postInvalidateDelayed(0); 15430 } 15431 15432 /** 15433 * <p>Cause an invalidate of the specified area to happen on a subsequent cycle 15434 * through the event loop. Use this to invalidate the View from a non-UI thread.</p> 15435 * 15436 * <p>This method can be invoked from outside of the UI thread 15437 * only when this View is attached to a window.</p> 15438 * 15439 * @param left The left coordinate of the rectangle to invalidate. 15440 * @param top The top coordinate of the rectangle to invalidate. 15441 * @param right The right coordinate of the rectangle to invalidate. 15442 * @param bottom The bottom coordinate of the rectangle to invalidate. 15443 * 15444 * @see #invalidate(int, int, int, int) 15445 * @see #invalidate(Rect) 15446 * @see #postInvalidateDelayed(long, int, int, int, int) 15447 */ 15448 public void postInvalidate(int left, int top, int right, int bottom) { 15449 postInvalidateDelayed(0, left, top, right, bottom); 15450 } 15451 15452 /** 15453 * <p>Cause an invalidate to happen on a subsequent cycle through the event 15454 * loop. Waits for the specified amount of time.</p> 15455 * 15456 * <p>This method can be invoked from outside of the UI thread 15457 * only when this View is attached to a window.</p> 15458 * 15459 * @param delayMilliseconds the duration in milliseconds to delay the 15460 * invalidation by 15461 * 15462 * @see #invalidate() 15463 * @see #postInvalidate() 15464 */ 15465 public void postInvalidateDelayed(long delayMilliseconds) { 15466 // We try only with the AttachInfo because there's no point in invalidating 15467 // if we are not attached to our window 15468 final AttachInfo attachInfo = mAttachInfo; 15469 if (attachInfo != null) { 15470 attachInfo.mViewRootImpl.dispatchInvalidateDelayed(this, delayMilliseconds); 15471 } 15472 } 15473 15474 /** 15475 * <p>Cause an invalidate of the specified area to happen on a subsequent cycle 15476 * through the event loop. Waits for the specified amount of time.</p> 15477 * 15478 * <p>This method can be invoked from outside of the UI thread 15479 * only when this View is attached to a window.</p> 15480 * 15481 * @param delayMilliseconds the duration in milliseconds to delay the 15482 * invalidation by 15483 * @param left The left coordinate of the rectangle to invalidate. 15484 * @param top The top coordinate of the rectangle to invalidate. 15485 * @param right The right coordinate of the rectangle to invalidate. 15486 * @param bottom The bottom coordinate of the rectangle to invalidate. 15487 * 15488 * @see #invalidate(int, int, int, int) 15489 * @see #invalidate(Rect) 15490 * @see #postInvalidate(int, int, int, int) 15491 */ 15492 public void postInvalidateDelayed(long delayMilliseconds, int left, int top, 15493 int right, int bottom) { 15494 15495 // We try only with the AttachInfo because there's no point in invalidating 15496 // if we are not attached to our window 15497 final AttachInfo attachInfo = mAttachInfo; 15498 if (attachInfo != null) { 15499 final AttachInfo.InvalidateInfo info = AttachInfo.InvalidateInfo.obtain(); 15500 info.target = this; 15501 info.left = left; 15502 info.top = top; 15503 info.right = right; 15504 info.bottom = bottom; 15505 15506 attachInfo.mViewRootImpl.dispatchInvalidateRectDelayed(info, delayMilliseconds); 15507 } 15508 } 15509 15510 /** 15511 * <p>Cause an invalidate to happen on the next animation time step, typically the 15512 * next display frame.</p> 15513 * 15514 * <p>This method can be invoked from outside of the UI thread 15515 * only when this View is attached to a window.</p> 15516 * 15517 * @see #invalidate() 15518 */ 15519 public void postInvalidateOnAnimation() { 15520 // We try only with the AttachInfo because there's no point in invalidating 15521 // if we are not attached to our window 15522 final AttachInfo attachInfo = mAttachInfo; 15523 if (attachInfo != null) { 15524 attachInfo.mViewRootImpl.dispatchInvalidateOnAnimation(this); 15525 } 15526 } 15527 15528 /** 15529 * <p>Cause an invalidate of the specified area to happen on the next animation 15530 * time step, typically the next display frame.</p> 15531 * 15532 * <p>This method can be invoked from outside of the UI thread 15533 * only when this View is attached to a window.</p> 15534 * 15535 * @param left The left coordinate of the rectangle to invalidate. 15536 * @param top The top coordinate of the rectangle to invalidate. 15537 * @param right The right coordinate of the rectangle to invalidate. 15538 * @param bottom The bottom coordinate of the rectangle to invalidate. 15539 * 15540 * @see #invalidate(int, int, int, int) 15541 * @see #invalidate(Rect) 15542 */ 15543 public void postInvalidateOnAnimation(int left, int top, int right, int bottom) { 15544 // We try only with the AttachInfo because there's no point in invalidating 15545 // if we are not attached to our window 15546 final AttachInfo attachInfo = mAttachInfo; 15547 if (attachInfo != null) { 15548 final AttachInfo.InvalidateInfo info = AttachInfo.InvalidateInfo.obtain(); 15549 info.target = this; 15550 info.left = left; 15551 info.top = top; 15552 info.right = right; 15553 info.bottom = bottom; 15554 15555 attachInfo.mViewRootImpl.dispatchInvalidateRectOnAnimation(info); 15556 } 15557 } 15558 15559 /** 15560 * Post a callback to send a {@link AccessibilityEvent#TYPE_VIEW_SCROLLED} event. 15561 * This event is sent at most once every 15562 * {@link ViewConfiguration#getSendRecurringAccessibilityEventsInterval()}. 15563 */ 15564 private void postSendViewScrolledAccessibilityEventCallback() { 15565 if (mSendViewScrolledAccessibilityEvent == null) { 15566 mSendViewScrolledAccessibilityEvent = new SendViewScrolledAccessibilityEvent(); 15567 } 15568 if (!mSendViewScrolledAccessibilityEvent.mIsPending) { 15569 mSendViewScrolledAccessibilityEvent.mIsPending = true; 15570 postDelayed(mSendViewScrolledAccessibilityEvent, 15571 ViewConfiguration.getSendRecurringAccessibilityEventsInterval()); 15572 } 15573 } 15574 15575 /** 15576 * Called by a parent to request that a child update its values for mScrollX 15577 * and mScrollY if necessary. This will typically be done if the child is 15578 * animating a scroll using a {@link android.widget.Scroller Scroller} 15579 * object. 15580 */ 15581 public void computeScroll() { 15582 } 15583 15584 /** 15585 * <p>Indicate whether the horizontal edges are faded when the view is 15586 * scrolled horizontally.</p> 15587 * 15588 * @return true if the horizontal edges should are faded on scroll, false 15589 * otherwise 15590 * 15591 * @see #setHorizontalFadingEdgeEnabled(boolean) 15592 * 15593 * @attr ref android.R.styleable#View_requiresFadingEdge 15594 */ 15595 public boolean isHorizontalFadingEdgeEnabled() { 15596 return (mViewFlags & FADING_EDGE_HORIZONTAL) == FADING_EDGE_HORIZONTAL; 15597 } 15598 15599 /** 15600 * <p>Define whether the horizontal edges should be faded when this view 15601 * is scrolled horizontally.</p> 15602 * 15603 * @param horizontalFadingEdgeEnabled true if the horizontal edges should 15604 * be faded when the view is scrolled 15605 * horizontally 15606 * 15607 * @see #isHorizontalFadingEdgeEnabled() 15608 * 15609 * @attr ref android.R.styleable#View_requiresFadingEdge 15610 */ 15611 public void setHorizontalFadingEdgeEnabled(boolean horizontalFadingEdgeEnabled) { 15612 if (isHorizontalFadingEdgeEnabled() != horizontalFadingEdgeEnabled) { 15613 if (horizontalFadingEdgeEnabled) { 15614 initScrollCache(); 15615 } 15616 15617 mViewFlags ^= FADING_EDGE_HORIZONTAL; 15618 } 15619 } 15620 15621 /** 15622 * <p>Indicate whether the vertical edges are faded when the view is 15623 * scrolled horizontally.</p> 15624 * 15625 * @return true if the vertical edges should are faded on scroll, false 15626 * otherwise 15627 * 15628 * @see #setVerticalFadingEdgeEnabled(boolean) 15629 * 15630 * @attr ref android.R.styleable#View_requiresFadingEdge 15631 */ 15632 public boolean isVerticalFadingEdgeEnabled() { 15633 return (mViewFlags & FADING_EDGE_VERTICAL) == FADING_EDGE_VERTICAL; 15634 } 15635 15636 /** 15637 * <p>Define whether the vertical edges should be faded when this view 15638 * is scrolled vertically.</p> 15639 * 15640 * @param verticalFadingEdgeEnabled true if the vertical edges should 15641 * be faded when the view is scrolled 15642 * vertically 15643 * 15644 * @see #isVerticalFadingEdgeEnabled() 15645 * 15646 * @attr ref android.R.styleable#View_requiresFadingEdge 15647 */ 15648 public void setVerticalFadingEdgeEnabled(boolean verticalFadingEdgeEnabled) { 15649 if (isVerticalFadingEdgeEnabled() != verticalFadingEdgeEnabled) { 15650 if (verticalFadingEdgeEnabled) { 15651 initScrollCache(); 15652 } 15653 15654 mViewFlags ^= FADING_EDGE_VERTICAL; 15655 } 15656 } 15657 15658 /** 15659 * Returns the strength, or intensity, of the top faded edge. The strength is 15660 * a value between 0.0 (no fade) and 1.0 (full fade). The default implementation 15661 * returns 0.0 or 1.0 but no value in between. 15662 * 15663 * Subclasses should override this method to provide a smoother fade transition 15664 * when scrolling occurs. 15665 * 15666 * @return the intensity of the top fade as a float between 0.0f and 1.0f 15667 */ 15668 protected float getTopFadingEdgeStrength() { 15669 return computeVerticalScrollOffset() > 0 ? 1.0f : 0.0f; 15670 } 15671 15672 /** 15673 * Returns the strength, or intensity, of the bottom faded edge. The strength is 15674 * a value between 0.0 (no fade) and 1.0 (full fade). The default implementation 15675 * returns 0.0 or 1.0 but no value in between. 15676 * 15677 * Subclasses should override this method to provide a smoother fade transition 15678 * when scrolling occurs. 15679 * 15680 * @return the intensity of the bottom fade as a float between 0.0f and 1.0f 15681 */ 15682 protected float getBottomFadingEdgeStrength() { 15683 return computeVerticalScrollOffset() + computeVerticalScrollExtent() < 15684 computeVerticalScrollRange() ? 1.0f : 0.0f; 15685 } 15686 15687 /** 15688 * Returns the strength, or intensity, of the left faded edge. The strength is 15689 * a value between 0.0 (no fade) and 1.0 (full fade). The default implementation 15690 * returns 0.0 or 1.0 but no value in between. 15691 * 15692 * Subclasses should override this method to provide a smoother fade transition 15693 * when scrolling occurs. 15694 * 15695 * @return the intensity of the left fade as a float between 0.0f and 1.0f 15696 */ 15697 protected float getLeftFadingEdgeStrength() { 15698 return computeHorizontalScrollOffset() > 0 ? 1.0f : 0.0f; 15699 } 15700 15701 /** 15702 * Returns the strength, or intensity, of the right faded edge. The strength is 15703 * a value between 0.0 (no fade) and 1.0 (full fade). The default implementation 15704 * returns 0.0 or 1.0 but no value in between. 15705 * 15706 * Subclasses should override this method to provide a smoother fade transition 15707 * when scrolling occurs. 15708 * 15709 * @return the intensity of the right fade as a float between 0.0f and 1.0f 15710 */ 15711 protected float getRightFadingEdgeStrength() { 15712 return computeHorizontalScrollOffset() + computeHorizontalScrollExtent() < 15713 computeHorizontalScrollRange() ? 1.0f : 0.0f; 15714 } 15715 15716 /** 15717 * <p>Indicate whether the horizontal scrollbar should be drawn or not. The 15718 * scrollbar is not drawn by default.</p> 15719 * 15720 * @return true if the horizontal scrollbar should be painted, false 15721 * otherwise 15722 * 15723 * @see #setHorizontalScrollBarEnabled(boolean) 15724 */ 15725 public boolean isHorizontalScrollBarEnabled() { 15726 return (mViewFlags & SCROLLBARS_HORIZONTAL) == SCROLLBARS_HORIZONTAL; 15727 } 15728 15729 /** 15730 * <p>Define whether the horizontal scrollbar should be drawn or not. The 15731 * scrollbar is not drawn by default.</p> 15732 * 15733 * @param horizontalScrollBarEnabled true if the horizontal scrollbar should 15734 * be painted 15735 * 15736 * @see #isHorizontalScrollBarEnabled() 15737 */ 15738 public void setHorizontalScrollBarEnabled(boolean horizontalScrollBarEnabled) { 15739 if (isHorizontalScrollBarEnabled() != horizontalScrollBarEnabled) { 15740 mViewFlags ^= SCROLLBARS_HORIZONTAL; 15741 computeOpaqueFlags(); 15742 resolvePadding(); 15743 } 15744 } 15745 15746 /** 15747 * <p>Indicate whether the vertical scrollbar should be drawn or not. The 15748 * scrollbar is not drawn by default.</p> 15749 * 15750 * @return true if the vertical scrollbar should be painted, false 15751 * otherwise 15752 * 15753 * @see #setVerticalScrollBarEnabled(boolean) 15754 */ 15755 public boolean isVerticalScrollBarEnabled() { 15756 return (mViewFlags & SCROLLBARS_VERTICAL) == SCROLLBARS_VERTICAL; 15757 } 15758 15759 /** 15760 * <p>Define whether the vertical scrollbar should be drawn or not. The 15761 * scrollbar is not drawn by default.</p> 15762 * 15763 * @param verticalScrollBarEnabled true if the vertical scrollbar should 15764 * be painted 15765 * 15766 * @see #isVerticalScrollBarEnabled() 15767 */ 15768 public void setVerticalScrollBarEnabled(boolean verticalScrollBarEnabled) { 15769 if (isVerticalScrollBarEnabled() != verticalScrollBarEnabled) { 15770 mViewFlags ^= SCROLLBARS_VERTICAL; 15771 computeOpaqueFlags(); 15772 resolvePadding(); 15773 } 15774 } 15775 15776 /** 15777 * @hide 15778 */ 15779 protected void recomputePadding() { 15780 internalSetPadding(mUserPaddingLeft, mPaddingTop, mUserPaddingRight, mUserPaddingBottom); 15781 } 15782 15783 /** 15784 * Define whether scrollbars will fade when the view is not scrolling. 15785 * 15786 * @param fadeScrollbars whether to enable fading 15787 * 15788 * @attr ref android.R.styleable#View_fadeScrollbars 15789 */ 15790 public void setScrollbarFadingEnabled(boolean fadeScrollbars) { 15791 initScrollCache(); 15792 final ScrollabilityCache scrollabilityCache = mScrollCache; 15793 scrollabilityCache.fadeScrollBars = fadeScrollbars; 15794 if (fadeScrollbars) { 15795 scrollabilityCache.state = ScrollabilityCache.OFF; 15796 } else { 15797 scrollabilityCache.state = ScrollabilityCache.ON; 15798 } 15799 } 15800 15801 /** 15802 * 15803 * Returns true if scrollbars will fade when this view is not scrolling 15804 * 15805 * @return true if scrollbar fading is enabled 15806 * 15807 * @attr ref android.R.styleable#View_fadeScrollbars 15808 */ 15809 public boolean isScrollbarFadingEnabled() { 15810 return mScrollCache != null && mScrollCache.fadeScrollBars; 15811 } 15812 15813 /** 15814 * 15815 * Returns the delay before scrollbars fade. 15816 * 15817 * @return the delay before scrollbars fade 15818 * 15819 * @attr ref android.R.styleable#View_scrollbarDefaultDelayBeforeFade 15820 */ 15821 public int getScrollBarDefaultDelayBeforeFade() { 15822 return mScrollCache == null ? ViewConfiguration.getScrollDefaultDelay() : 15823 mScrollCache.scrollBarDefaultDelayBeforeFade; 15824 } 15825 15826 /** 15827 * Define the delay before scrollbars fade. 15828 * 15829 * @param scrollBarDefaultDelayBeforeFade - the delay before scrollbars fade 15830 * 15831 * @attr ref android.R.styleable#View_scrollbarDefaultDelayBeforeFade 15832 */ 15833 public void setScrollBarDefaultDelayBeforeFade(int scrollBarDefaultDelayBeforeFade) { 15834 getScrollCache().scrollBarDefaultDelayBeforeFade = scrollBarDefaultDelayBeforeFade; 15835 } 15836 15837 /** 15838 * 15839 * Returns the scrollbar fade duration. 15840 * 15841 * @return the scrollbar fade duration, in milliseconds 15842 * 15843 * @attr ref android.R.styleable#View_scrollbarFadeDuration 15844 */ 15845 public int getScrollBarFadeDuration() { 15846 return mScrollCache == null ? ViewConfiguration.getScrollBarFadeDuration() : 15847 mScrollCache.scrollBarFadeDuration; 15848 } 15849 15850 /** 15851 * Define the scrollbar fade duration. 15852 * 15853 * @param scrollBarFadeDuration - the scrollbar fade duration, in milliseconds 15854 * 15855 * @attr ref android.R.styleable#View_scrollbarFadeDuration 15856 */ 15857 public void setScrollBarFadeDuration(int scrollBarFadeDuration) { 15858 getScrollCache().scrollBarFadeDuration = scrollBarFadeDuration; 15859 } 15860 15861 /** 15862 * 15863 * Returns the scrollbar size. 15864 * 15865 * @return the scrollbar size 15866 * 15867 * @attr ref android.R.styleable#View_scrollbarSize 15868 */ 15869 public int getScrollBarSize() { 15870 return mScrollCache == null ? ViewConfiguration.get(mContext).getScaledScrollBarSize() : 15871 mScrollCache.scrollBarSize; 15872 } 15873 15874 /** 15875 * Define the scrollbar size. 15876 * 15877 * @param scrollBarSize - the scrollbar size 15878 * 15879 * @attr ref android.R.styleable#View_scrollbarSize 15880 */ 15881 public void setScrollBarSize(int scrollBarSize) { 15882 getScrollCache().scrollBarSize = scrollBarSize; 15883 } 15884 15885 /** 15886 * <p>Specify the style of the scrollbars. The scrollbars can be overlaid or 15887 * inset. When inset, they add to the padding of the view. And the scrollbars 15888 * can be drawn inside the padding area or on the edge of the view. For example, 15889 * if a view has a background drawable and you want to draw the scrollbars 15890 * inside the padding specified by the drawable, you can use 15891 * SCROLLBARS_INSIDE_OVERLAY or SCROLLBARS_INSIDE_INSET. If you want them to 15892 * appear at the edge of the view, ignoring the padding, then you can use 15893 * SCROLLBARS_OUTSIDE_OVERLAY or SCROLLBARS_OUTSIDE_INSET.</p> 15894 * @param style the style of the scrollbars. Should be one of 15895 * SCROLLBARS_INSIDE_OVERLAY, SCROLLBARS_INSIDE_INSET, 15896 * SCROLLBARS_OUTSIDE_OVERLAY or SCROLLBARS_OUTSIDE_INSET. 15897 * @see #SCROLLBARS_INSIDE_OVERLAY 15898 * @see #SCROLLBARS_INSIDE_INSET 15899 * @see #SCROLLBARS_OUTSIDE_OVERLAY 15900 * @see #SCROLLBARS_OUTSIDE_INSET 15901 * 15902 * @attr ref android.R.styleable#View_scrollbarStyle 15903 */ 15904 public void setScrollBarStyle(@ScrollBarStyle int style) { 15905 if (style != (mViewFlags & SCROLLBARS_STYLE_MASK)) { 15906 mViewFlags = (mViewFlags & ~SCROLLBARS_STYLE_MASK) | (style & SCROLLBARS_STYLE_MASK); 15907 computeOpaqueFlags(); 15908 resolvePadding(); 15909 } 15910 } 15911 15912 /** 15913 * <p>Returns the current scrollbar style.</p> 15914 * @return the current scrollbar style 15915 * @see #SCROLLBARS_INSIDE_OVERLAY 15916 * @see #SCROLLBARS_INSIDE_INSET 15917 * @see #SCROLLBARS_OUTSIDE_OVERLAY 15918 * @see #SCROLLBARS_OUTSIDE_INSET 15919 * 15920 * @attr ref android.R.styleable#View_scrollbarStyle 15921 */ 15922 @ViewDebug.ExportedProperty(mapping = { 15923 @ViewDebug.IntToString(from = SCROLLBARS_INSIDE_OVERLAY, to = "INSIDE_OVERLAY"), 15924 @ViewDebug.IntToString(from = SCROLLBARS_INSIDE_INSET, to = "INSIDE_INSET"), 15925 @ViewDebug.IntToString(from = SCROLLBARS_OUTSIDE_OVERLAY, to = "OUTSIDE_OVERLAY"), 15926 @ViewDebug.IntToString(from = SCROLLBARS_OUTSIDE_INSET, to = "OUTSIDE_INSET") 15927 }) 15928 @ScrollBarStyle 15929 public int getScrollBarStyle() { 15930 return mViewFlags & SCROLLBARS_STYLE_MASK; 15931 } 15932 15933 /** 15934 * <p>Compute the horizontal range that the horizontal scrollbar 15935 * represents.</p> 15936 * 15937 * <p>The range is expressed in arbitrary units that must be the same as the 15938 * units used by {@link #computeHorizontalScrollExtent()} and 15939 * {@link #computeHorizontalScrollOffset()}.</p> 15940 * 15941 * <p>The default range is the drawing width of this view.</p> 15942 * 15943 * @return the total horizontal range represented by the horizontal 15944 * scrollbar 15945 * 15946 * @see #computeHorizontalScrollExtent() 15947 * @see #computeHorizontalScrollOffset() 15948 * @see android.widget.ScrollBarDrawable 15949 */ 15950 protected int computeHorizontalScrollRange() { 15951 return getWidth(); 15952 } 15953 15954 /** 15955 * <p>Compute the horizontal offset of the horizontal scrollbar's thumb 15956 * within the horizontal range. This value is used to compute the position 15957 * of the thumb within the scrollbar's track.</p> 15958 * 15959 * <p>The range is expressed in arbitrary units that must be the same as the 15960 * units used by {@link #computeHorizontalScrollRange()} and 15961 * {@link #computeHorizontalScrollExtent()}.</p> 15962 * 15963 * <p>The default offset is the scroll offset of this view.</p> 15964 * 15965 * @return the horizontal offset of the scrollbar's thumb 15966 * 15967 * @see #computeHorizontalScrollRange() 15968 * @see #computeHorizontalScrollExtent() 15969 * @see android.widget.ScrollBarDrawable 15970 */ 15971 protected int computeHorizontalScrollOffset() { 15972 return mScrollX; 15973 } 15974 15975 /** 15976 * <p>Compute the horizontal extent of the horizontal scrollbar's thumb 15977 * within the horizontal range. This value is used to compute the length 15978 * of the thumb within the scrollbar's track.</p> 15979 * 15980 * <p>The range is expressed in arbitrary units that must be the same as the 15981 * units used by {@link #computeHorizontalScrollRange()} and 15982 * {@link #computeHorizontalScrollOffset()}.</p> 15983 * 15984 * <p>The default extent is the drawing width of this view.</p> 15985 * 15986 * @return the horizontal extent of the scrollbar's thumb 15987 * 15988 * @see #computeHorizontalScrollRange() 15989 * @see #computeHorizontalScrollOffset() 15990 * @see android.widget.ScrollBarDrawable 15991 */ 15992 protected int computeHorizontalScrollExtent() { 15993 return getWidth(); 15994 } 15995 15996 /** 15997 * <p>Compute the vertical range that the vertical scrollbar represents.</p> 15998 * 15999 * <p>The range is expressed in arbitrary units that must be the same as the 16000 * units used by {@link #computeVerticalScrollExtent()} and 16001 * {@link #computeVerticalScrollOffset()}.</p> 16002 * 16003 * @return the total vertical range represented by the vertical scrollbar 16004 * 16005 * <p>The default range is the drawing height of this view.</p> 16006 * 16007 * @see #computeVerticalScrollExtent() 16008 * @see #computeVerticalScrollOffset() 16009 * @see android.widget.ScrollBarDrawable 16010 */ 16011 protected int computeVerticalScrollRange() { 16012 return getHeight(); 16013 } 16014 16015 /** 16016 * <p>Compute the vertical offset of the vertical scrollbar's thumb 16017 * within the horizontal range. This value is used to compute the position 16018 * of the thumb within the scrollbar's track.</p> 16019 * 16020 * <p>The range is expressed in arbitrary units that must be the same as the 16021 * units used by {@link #computeVerticalScrollRange()} and 16022 * {@link #computeVerticalScrollExtent()}.</p> 16023 * 16024 * <p>The default offset is the scroll offset of this view.</p> 16025 * 16026 * @return the vertical offset of the scrollbar's thumb 16027 * 16028 * @see #computeVerticalScrollRange() 16029 * @see #computeVerticalScrollExtent() 16030 * @see android.widget.ScrollBarDrawable 16031 */ 16032 protected int computeVerticalScrollOffset() { 16033 return mScrollY; 16034 } 16035 16036 /** 16037 * <p>Compute the vertical extent of the vertical scrollbar's thumb 16038 * within the vertical range. This value is used to compute the length 16039 * of the thumb within the scrollbar's track.</p> 16040 * 16041 * <p>The range is expressed in arbitrary units that must be the same as the 16042 * units used by {@link #computeVerticalScrollRange()} and 16043 * {@link #computeVerticalScrollOffset()}.</p> 16044 * 16045 * <p>The default extent is the drawing height of this view.</p> 16046 * 16047 * @return the vertical extent of the scrollbar's thumb 16048 * 16049 * @see #computeVerticalScrollRange() 16050 * @see #computeVerticalScrollOffset() 16051 * @see android.widget.ScrollBarDrawable 16052 */ 16053 protected int computeVerticalScrollExtent() { 16054 return getHeight(); 16055 } 16056 16057 /** 16058 * Check if this view can be scrolled horizontally in a certain direction. 16059 * 16060 * @param direction Negative to check scrolling left, positive to check scrolling right. 16061 * @return true if this view can be scrolled in the specified direction, false otherwise. 16062 */ 16063 public boolean canScrollHorizontally(int direction) { 16064 final int offset = computeHorizontalScrollOffset(); 16065 final int range = computeHorizontalScrollRange() - computeHorizontalScrollExtent(); 16066 if (range == 0) return false; 16067 if (direction < 0) { 16068 return offset > 0; 16069 } else { 16070 return offset < range - 1; 16071 } 16072 } 16073 16074 /** 16075 * Check if this view can be scrolled vertically in a certain direction. 16076 * 16077 * @param direction Negative to check scrolling up, positive to check scrolling down. 16078 * @return true if this view can be scrolled in the specified direction, false otherwise. 16079 */ 16080 public boolean canScrollVertically(int direction) { 16081 final int offset = computeVerticalScrollOffset(); 16082 final int range = computeVerticalScrollRange() - computeVerticalScrollExtent(); 16083 if (range == 0) return false; 16084 if (direction < 0) { 16085 return offset > 0; 16086 } else { 16087 return offset < range - 1; 16088 } 16089 } 16090 16091 void getScrollIndicatorBounds(@NonNull Rect out) { 16092 out.left = mScrollX; 16093 out.right = mScrollX + mRight - mLeft; 16094 out.top = mScrollY; 16095 out.bottom = mScrollY + mBottom - mTop; 16096 } 16097 16098 private void onDrawScrollIndicators(Canvas c) { 16099 if ((mPrivateFlags3 & SCROLL_INDICATORS_PFLAG3_MASK) == 0) { 16100 // No scroll indicators enabled. 16101 return; 16102 } 16103 16104 final Drawable dr = mScrollIndicatorDrawable; 16105 if (dr == null) { 16106 // Scroll indicators aren't supported here. 16107 return; 16108 } 16109 16110 final int h = dr.getIntrinsicHeight(); 16111 final int w = dr.getIntrinsicWidth(); 16112 final Rect rect = mAttachInfo.mTmpInvalRect; 16113 getScrollIndicatorBounds(rect); 16114 16115 if ((mPrivateFlags3 & PFLAG3_SCROLL_INDICATOR_TOP) != 0) { 16116 final boolean canScrollUp = canScrollVertically(-1); 16117 if (canScrollUp) { 16118 dr.setBounds(rect.left, rect.top, rect.right, rect.top + h); 16119 dr.draw(c); 16120 } 16121 } 16122 16123 if ((mPrivateFlags3 & PFLAG3_SCROLL_INDICATOR_BOTTOM) != 0) { 16124 final boolean canScrollDown = canScrollVertically(1); 16125 if (canScrollDown) { 16126 dr.setBounds(rect.left, rect.bottom - h, rect.right, rect.bottom); 16127 dr.draw(c); 16128 } 16129 } 16130 16131 final int leftRtl; 16132 final int rightRtl; 16133 if (getLayoutDirection() == LAYOUT_DIRECTION_RTL) { 16134 leftRtl = PFLAG3_SCROLL_INDICATOR_END; 16135 rightRtl = PFLAG3_SCROLL_INDICATOR_START; 16136 } else { 16137 leftRtl = PFLAG3_SCROLL_INDICATOR_START; 16138 rightRtl = PFLAG3_SCROLL_INDICATOR_END; 16139 } 16140 16141 final int leftMask = PFLAG3_SCROLL_INDICATOR_LEFT | leftRtl; 16142 if ((mPrivateFlags3 & leftMask) != 0) { 16143 final boolean canScrollLeft = canScrollHorizontally(-1); 16144 if (canScrollLeft) { 16145 dr.setBounds(rect.left, rect.top, rect.left + w, rect.bottom); 16146 dr.draw(c); 16147 } 16148 } 16149 16150 final int rightMask = PFLAG3_SCROLL_INDICATOR_RIGHT | rightRtl; 16151 if ((mPrivateFlags3 & rightMask) != 0) { 16152 final boolean canScrollRight = canScrollHorizontally(1); 16153 if (canScrollRight) { 16154 dr.setBounds(rect.right - w, rect.top, rect.right, rect.bottom); 16155 dr.draw(c); 16156 } 16157 } 16158 } 16159 16160 private void getHorizontalScrollBarBounds(@Nullable Rect drawBounds, 16161 @Nullable Rect touchBounds) { 16162 final Rect bounds = drawBounds != null ? drawBounds : touchBounds; 16163 if (bounds == null) { 16164 return; 16165 } 16166 final int inside = (mViewFlags & SCROLLBARS_OUTSIDE_MASK) == 0 ? ~0 : 0; 16167 final boolean drawVerticalScrollBar = isVerticalScrollBarEnabled() 16168 && !isVerticalScrollBarHidden(); 16169 final int size = getHorizontalScrollbarHeight(); 16170 final int verticalScrollBarGap = drawVerticalScrollBar ? 16171 getVerticalScrollbarWidth() : 0; 16172 final int width = mRight - mLeft; 16173 final int height = mBottom - mTop; 16174 bounds.top = mScrollY + height - size - (mUserPaddingBottom & inside); 16175 bounds.left = mScrollX + (mPaddingLeft & inside); 16176 bounds.right = mScrollX + width - (mUserPaddingRight & inside) - verticalScrollBarGap; 16177 bounds.bottom = bounds.top + size; 16178 16179 if (touchBounds == null) { 16180 return; 16181 } 16182 if (touchBounds != bounds) { 16183 touchBounds.set(bounds); 16184 } 16185 final int minTouchTarget = mScrollCache.scrollBarMinTouchTarget; 16186 if (touchBounds.height() < minTouchTarget) { 16187 final int adjust = (minTouchTarget - touchBounds.height()) / 2; 16188 touchBounds.bottom = Math.min(touchBounds.bottom + adjust, mScrollY + height); 16189 touchBounds.top = touchBounds.bottom - minTouchTarget; 16190 } 16191 if (touchBounds.width() < minTouchTarget) { 16192 final int adjust = (minTouchTarget - touchBounds.width()) / 2; 16193 touchBounds.left -= adjust; 16194 touchBounds.right = touchBounds.left + minTouchTarget; 16195 } 16196 } 16197 16198 private void getVerticalScrollBarBounds(@Nullable Rect bounds, @Nullable Rect touchBounds) { 16199 if (mRoundScrollbarRenderer == null) { 16200 getStraightVerticalScrollBarBounds(bounds, touchBounds); 16201 } else { 16202 getRoundVerticalScrollBarBounds(bounds != null ? bounds : touchBounds); 16203 } 16204 } 16205 16206 private void getRoundVerticalScrollBarBounds(Rect bounds) { 16207 final int width = mRight - mLeft; 16208 final int height = mBottom - mTop; 16209 // Do not take padding into account as we always want the scrollbars 16210 // to hug the screen for round wearable devices. 16211 bounds.left = mScrollX; 16212 bounds.top = mScrollY; 16213 bounds.right = bounds.left + width; 16214 bounds.bottom = mScrollY + height; 16215 } 16216 16217 private void getStraightVerticalScrollBarBounds(@Nullable Rect drawBounds, 16218 @Nullable Rect touchBounds) { 16219 final Rect bounds = drawBounds != null ? drawBounds : touchBounds; 16220 if (bounds == null) { 16221 return; 16222 } 16223 final int inside = (mViewFlags & SCROLLBARS_OUTSIDE_MASK) == 0 ? ~0 : 0; 16224 final int size = getVerticalScrollbarWidth(); 16225 int verticalScrollbarPosition = mVerticalScrollbarPosition; 16226 if (verticalScrollbarPosition == SCROLLBAR_POSITION_DEFAULT) { 16227 verticalScrollbarPosition = isLayoutRtl() ? 16228 SCROLLBAR_POSITION_LEFT : SCROLLBAR_POSITION_RIGHT; 16229 } 16230 final int width = mRight - mLeft; 16231 final int height = mBottom - mTop; 16232 switch (verticalScrollbarPosition) { 16233 default: 16234 case SCROLLBAR_POSITION_RIGHT: 16235 bounds.left = mScrollX + width - size - (mUserPaddingRight & inside); 16236 break; 16237 case SCROLLBAR_POSITION_LEFT: 16238 bounds.left = mScrollX + (mUserPaddingLeft & inside); 16239 break; 16240 } 16241 bounds.top = mScrollY + (mPaddingTop & inside); 16242 bounds.right = bounds.left + size; 16243 bounds.bottom = mScrollY + height - (mUserPaddingBottom & inside); 16244 16245 if (touchBounds == null) { 16246 return; 16247 } 16248 if (touchBounds != bounds) { 16249 touchBounds.set(bounds); 16250 } 16251 final int minTouchTarget = mScrollCache.scrollBarMinTouchTarget; 16252 if (touchBounds.width() < minTouchTarget) { 16253 final int adjust = (minTouchTarget - touchBounds.width()) / 2; 16254 if (verticalScrollbarPosition == SCROLLBAR_POSITION_RIGHT) { 16255 touchBounds.right = Math.min(touchBounds.right + adjust, mScrollX + width); 16256 touchBounds.left = touchBounds.right - minTouchTarget; 16257 } else { 16258 touchBounds.left = Math.max(touchBounds.left + adjust, mScrollX); 16259 touchBounds.right = touchBounds.left + minTouchTarget; 16260 } 16261 } 16262 if (touchBounds.height() < minTouchTarget) { 16263 final int adjust = (minTouchTarget - touchBounds.height()) / 2; 16264 touchBounds.top -= adjust; 16265 touchBounds.bottom = touchBounds.top + minTouchTarget; 16266 } 16267 } 16268 16269 /** 16270 * <p>Request the drawing of the horizontal and the vertical scrollbar. The 16271 * scrollbars are painted only if they have been awakened first.</p> 16272 * 16273 * @param canvas the canvas on which to draw the scrollbars 16274 * 16275 * @see #awakenScrollBars(int) 16276 */ 16277 protected final void onDrawScrollBars(Canvas canvas) { 16278 // scrollbars are drawn only when the animation is running 16279 final ScrollabilityCache cache = mScrollCache; 16280 16281 if (cache != null) { 16282 16283 int state = cache.state; 16284 16285 if (state == ScrollabilityCache.OFF) { 16286 return; 16287 } 16288 16289 boolean invalidate = false; 16290 16291 if (state == ScrollabilityCache.FADING) { 16292 // We're fading -- get our fade interpolation 16293 if (cache.interpolatorValues == null) { 16294 cache.interpolatorValues = new float[1]; 16295 } 16296 16297 float[] values = cache.interpolatorValues; 16298 16299 // Stops the animation if we're done 16300 if (cache.scrollBarInterpolator.timeToValues(values) == 16301 Interpolator.Result.FREEZE_END) { 16302 cache.state = ScrollabilityCache.OFF; 16303 } else { 16304 cache.scrollBar.mutate().setAlpha(Math.round(values[0])); 16305 } 16306 16307 // This will make the scroll bars inval themselves after 16308 // drawing. We only want this when we're fading so that 16309 // we prevent excessive redraws 16310 invalidate = true; 16311 } else { 16312 // We're just on -- but we may have been fading before so 16313 // reset alpha 16314 cache.scrollBar.mutate().setAlpha(255); 16315 } 16316 16317 final boolean drawHorizontalScrollBar = isHorizontalScrollBarEnabled(); 16318 final boolean drawVerticalScrollBar = isVerticalScrollBarEnabled() 16319 && !isVerticalScrollBarHidden(); 16320 16321 // Fork out the scroll bar drawing for round wearable devices. 16322 if (mRoundScrollbarRenderer != null) { 16323 if (drawVerticalScrollBar) { 16324 final Rect bounds = cache.mScrollBarBounds; 16325 getVerticalScrollBarBounds(bounds, null); 16326 mRoundScrollbarRenderer.drawRoundScrollbars( 16327 canvas, (float) cache.scrollBar.getAlpha() / 255f, bounds); 16328 if (invalidate) { 16329 invalidate(); 16330 } 16331 } 16332 // Do not draw horizontal scroll bars for round wearable devices. 16333 } else if (drawVerticalScrollBar || drawHorizontalScrollBar) { 16334 final ScrollBarDrawable scrollBar = cache.scrollBar; 16335 16336 if (drawHorizontalScrollBar) { 16337 scrollBar.setParameters(computeHorizontalScrollRange(), 16338 computeHorizontalScrollOffset(), 16339 computeHorizontalScrollExtent(), false); 16340 final Rect bounds = cache.mScrollBarBounds; 16341 getHorizontalScrollBarBounds(bounds, null); 16342 onDrawHorizontalScrollBar(canvas, scrollBar, bounds.left, bounds.top, 16343 bounds.right, bounds.bottom); 16344 if (invalidate) { 16345 invalidate(bounds); 16346 } 16347 } 16348 16349 if (drawVerticalScrollBar) { 16350 scrollBar.setParameters(computeVerticalScrollRange(), 16351 computeVerticalScrollOffset(), 16352 computeVerticalScrollExtent(), true); 16353 final Rect bounds = cache.mScrollBarBounds; 16354 getVerticalScrollBarBounds(bounds, null); 16355 onDrawVerticalScrollBar(canvas, scrollBar, bounds.left, bounds.top, 16356 bounds.right, bounds.bottom); 16357 if (invalidate) { 16358 invalidate(bounds); 16359 } 16360 } 16361 } 16362 } 16363 } 16364 16365 /** 16366 * Override this if the vertical scrollbar needs to be hidden in a subclass, like when 16367 * FastScroller is visible. 16368 * @return whether to temporarily hide the vertical scrollbar 16369 * @hide 16370 */ 16371 protected boolean isVerticalScrollBarHidden() { 16372 return false; 16373 } 16374 16375 /** 16376 * <p>Draw the horizontal scrollbar if 16377 * {@link #isHorizontalScrollBarEnabled()} returns true.</p> 16378 * 16379 * @param canvas the canvas on which to draw the scrollbar 16380 * @param scrollBar the scrollbar's drawable 16381 * 16382 * @see #isHorizontalScrollBarEnabled() 16383 * @see #computeHorizontalScrollRange() 16384 * @see #computeHorizontalScrollExtent() 16385 * @see #computeHorizontalScrollOffset() 16386 * @see android.widget.ScrollBarDrawable 16387 * @hide 16388 */ 16389 protected void onDrawHorizontalScrollBar(Canvas canvas, Drawable scrollBar, 16390 int l, int t, int r, int b) { 16391 scrollBar.setBounds(l, t, r, b); 16392 scrollBar.draw(canvas); 16393 } 16394 16395 /** 16396 * <p>Draw the vertical scrollbar if {@link #isVerticalScrollBarEnabled()} 16397 * returns true.</p> 16398 * 16399 * @param canvas the canvas on which to draw the scrollbar 16400 * @param scrollBar the scrollbar's drawable 16401 * 16402 * @see #isVerticalScrollBarEnabled() 16403 * @see #computeVerticalScrollRange() 16404 * @see #computeVerticalScrollExtent() 16405 * @see #computeVerticalScrollOffset() 16406 * @see android.widget.ScrollBarDrawable 16407 * @hide 16408 */ 16409 protected void onDrawVerticalScrollBar(Canvas canvas, Drawable scrollBar, 16410 int l, int t, int r, int b) { 16411 scrollBar.setBounds(l, t, r, b); 16412 scrollBar.draw(canvas); 16413 } 16414 16415 /** 16416 * Implement this to do your drawing. 16417 * 16418 * @param canvas the canvas on which the background will be drawn 16419 */ 16420 protected void onDraw(Canvas canvas) { 16421 } 16422 16423 /* 16424 * Caller is responsible for calling requestLayout if necessary. 16425 * (This allows addViewInLayout to not request a new layout.) 16426 */ 16427 void assignParent(ViewParent parent) { 16428 if (mParent == null) { 16429 mParent = parent; 16430 } else if (parent == null) { 16431 mParent = null; 16432 } else { 16433 throw new RuntimeException("view " + this + " being added, but" 16434 + " it already has a parent"); 16435 } 16436 } 16437 16438 /** 16439 * This is called when the view is attached to a window. At this point it 16440 * has a Surface and will start drawing. Note that this function is 16441 * guaranteed to be called before {@link #onDraw(android.graphics.Canvas)}, 16442 * however it may be called any time before the first onDraw -- including 16443 * before or after {@link #onMeasure(int, int)}. 16444 * 16445 * @see #onDetachedFromWindow() 16446 */ 16447 @CallSuper 16448 protected void onAttachedToWindow() { 16449 if ((mPrivateFlags & PFLAG_REQUEST_TRANSPARENT_REGIONS) != 0) { 16450 mParent.requestTransparentRegion(this); 16451 } 16452 16453 mPrivateFlags3 &= ~PFLAG3_IS_LAID_OUT; 16454 16455 jumpDrawablesToCurrentState(); 16456 16457 resetSubtreeAccessibilityStateChanged(); 16458 16459 // rebuild, since Outline not maintained while View is detached 16460 rebuildOutline(); 16461 16462 if (isFocused()) { 16463 InputMethodManager imm = InputMethodManager.peekInstance(); 16464 if (imm != null) { 16465 imm.focusIn(this); 16466 } 16467 } 16468 } 16469 16470 /** 16471 * Resolve all RTL related properties. 16472 * 16473 * @return true if resolution of RTL properties has been done 16474 * 16475 * @hide 16476 */ 16477 public boolean resolveRtlPropertiesIfNeeded() { 16478 if (!needRtlPropertiesResolution()) return false; 16479 16480 // Order is important here: LayoutDirection MUST be resolved first 16481 if (!isLayoutDirectionResolved()) { 16482 resolveLayoutDirection(); 16483 resolveLayoutParams(); 16484 } 16485 // ... then we can resolve the others properties depending on the resolved LayoutDirection. 16486 if (!isTextDirectionResolved()) { 16487 resolveTextDirection(); 16488 } 16489 if (!isTextAlignmentResolved()) { 16490 resolveTextAlignment(); 16491 } 16492 // Should resolve Drawables before Padding because we need the layout direction of the 16493 // Drawable to correctly resolve Padding. 16494 if (!areDrawablesResolved()) { 16495 resolveDrawables(); 16496 } 16497 if (!isPaddingResolved()) { 16498 resolvePadding(); 16499 } 16500 onRtlPropertiesChanged(getLayoutDirection()); 16501 return true; 16502 } 16503 16504 /** 16505 * Reset resolution of all RTL related properties. 16506 * 16507 * @hide 16508 */ 16509 public void resetRtlProperties() { 16510 resetResolvedLayoutDirection(); 16511 resetResolvedTextDirection(); 16512 resetResolvedTextAlignment(); 16513 resetResolvedPadding(); 16514 resetResolvedDrawables(); 16515 } 16516 16517 /** 16518 * @see #onScreenStateChanged(int) 16519 */ 16520 void dispatchScreenStateChanged(int screenState) { 16521 onScreenStateChanged(screenState); 16522 } 16523 16524 /** 16525 * This method is called whenever the state of the screen this view is 16526 * attached to changes. A state change will usually occurs when the screen 16527 * turns on or off (whether it happens automatically or the user does it 16528 * manually.) 16529 * 16530 * @param screenState The new state of the screen. Can be either 16531 * {@link #SCREEN_STATE_ON} or {@link #SCREEN_STATE_OFF} 16532 */ 16533 public void onScreenStateChanged(int screenState) { 16534 } 16535 16536 /** 16537 * @see #onMovedToDisplay(int, Configuration) 16538 */ 16539 void dispatchMovedToDisplay(Display display, Configuration config) { 16540 mAttachInfo.mDisplay = display; 16541 mAttachInfo.mDisplayState = display.getState(); 16542 onMovedToDisplay(display.getDisplayId(), config); 16543 } 16544 16545 /** 16546 * Called by the system when the hosting activity is moved from one display to another without 16547 * recreation. This means that the activity is declared to handle all changes to configuration 16548 * that happened when it was switched to another display, so it wasn't destroyed and created 16549 * again. 16550 * 16551 * <p>This call will be followed by {@link #onConfigurationChanged(Configuration)} if the 16552 * applied configuration actually changed. It is up to app developer to choose whether to handle 16553 * the change in this method or in the following {@link #onConfigurationChanged(Configuration)} 16554 * call. 16555 * 16556 * <p>Use this callback to track changes to the displays if some functionality relies on an 16557 * association with some display properties. 16558 * 16559 * @param displayId The id of the display to which the view was moved. 16560 * @param config Configuration of the resources on new display after move. 16561 * 16562 * @see #onConfigurationChanged(Configuration) 16563 */ 16564 public void onMovedToDisplay(int displayId, Configuration config) { 16565 } 16566 16567 /** 16568 * Return true if the application tag in the AndroidManifest has set "supportRtl" to true 16569 */ 16570 private boolean hasRtlSupport() { 16571 return mContext.getApplicationInfo().hasRtlSupport(); 16572 } 16573 16574 /** 16575 * Return true if we are in RTL compatibility mode (either before Jelly Bean MR1 or 16576 * RTL not supported) 16577 */ 16578 private boolean isRtlCompatibilityMode() { 16579 final int targetSdkVersion = getContext().getApplicationInfo().targetSdkVersion; 16580 return targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR1 || !hasRtlSupport(); 16581 } 16582 16583 /** 16584 * @return true if RTL properties need resolution. 16585 * 16586 */ 16587 private boolean needRtlPropertiesResolution() { 16588 return (mPrivateFlags2 & ALL_RTL_PROPERTIES_RESOLVED) != ALL_RTL_PROPERTIES_RESOLVED; 16589 } 16590 16591 /** 16592 * Called when any RTL property (layout direction or text direction or text alignment) has 16593 * been changed. 16594 * 16595 * Subclasses need to override this method to take care of cached information that depends on the 16596 * resolved layout direction, or to inform child views that inherit their layout direction. 16597 * 16598 * The default implementation does nothing. 16599 * 16600 * @param layoutDirection the direction of the layout 16601 * 16602 * @see #LAYOUT_DIRECTION_LTR 16603 * @see #LAYOUT_DIRECTION_RTL 16604 */ 16605 public void onRtlPropertiesChanged(@ResolvedLayoutDir int layoutDirection) { 16606 } 16607 16608 /** 16609 * Resolve and cache the layout direction. LTR is set initially. This is implicitly supposing 16610 * that the parent directionality can and will be resolved before its children. 16611 * 16612 * @return true if resolution has been done, false otherwise. 16613 * 16614 * @hide 16615 */ 16616 public boolean resolveLayoutDirection() { 16617 // Clear any previous layout direction resolution 16618 mPrivateFlags2 &= ~PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK; 16619 16620 if (hasRtlSupport()) { 16621 // Set resolved depending on layout direction 16622 switch ((mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_MASK) >> 16623 PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT) { 16624 case LAYOUT_DIRECTION_INHERIT: 16625 // We cannot resolve yet. LTR is by default and let the resolution happen again 16626 // later to get the correct resolved value 16627 if (!canResolveLayoutDirection()) return false; 16628 16629 // Parent has not yet resolved, LTR is still the default 16630 try { 16631 if (!mParent.isLayoutDirectionResolved()) return false; 16632 16633 if (mParent.getLayoutDirection() == LAYOUT_DIRECTION_RTL) { 16634 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL; 16635 } 16636 } catch (AbstractMethodError e) { 16637 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 16638 " does not fully implement ViewParent", e); 16639 } 16640 break; 16641 case LAYOUT_DIRECTION_RTL: 16642 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL; 16643 break; 16644 case LAYOUT_DIRECTION_LOCALE: 16645 if((LAYOUT_DIRECTION_RTL == 16646 TextUtils.getLayoutDirectionFromLocale(Locale.getDefault()))) { 16647 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL; 16648 } 16649 break; 16650 default: 16651 // Nothing to do, LTR by default 16652 } 16653 } 16654 16655 // Set to resolved 16656 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED; 16657 return true; 16658 } 16659 16660 /** 16661 * Check if layout direction resolution can be done. 16662 * 16663 * @return true if layout direction resolution can be done otherwise return false. 16664 */ 16665 public boolean canResolveLayoutDirection() { 16666 switch (getRawLayoutDirection()) { 16667 case LAYOUT_DIRECTION_INHERIT: 16668 if (mParent != null) { 16669 try { 16670 return mParent.canResolveLayoutDirection(); 16671 } catch (AbstractMethodError e) { 16672 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 16673 " does not fully implement ViewParent", e); 16674 } 16675 } 16676 return false; 16677 16678 default: 16679 return true; 16680 } 16681 } 16682 16683 /** 16684 * Reset the resolved layout direction. Layout direction will be resolved during a call to 16685 * {@link #onMeasure(int, int)}. 16686 * 16687 * @hide 16688 */ 16689 public void resetResolvedLayoutDirection() { 16690 // Reset the current resolved bits 16691 mPrivateFlags2 &= ~PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK; 16692 } 16693 16694 /** 16695 * @return true if the layout direction is inherited. 16696 * 16697 * @hide 16698 */ 16699 public boolean isLayoutDirectionInherited() { 16700 return (getRawLayoutDirection() == LAYOUT_DIRECTION_INHERIT); 16701 } 16702 16703 /** 16704 * @return true if layout direction has been resolved. 16705 */ 16706 public boolean isLayoutDirectionResolved() { 16707 return (mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_RESOLVED) == PFLAG2_LAYOUT_DIRECTION_RESOLVED; 16708 } 16709 16710 /** 16711 * Return if padding has been resolved 16712 * 16713 * @hide 16714 */ 16715 boolean isPaddingResolved() { 16716 return (mPrivateFlags2 & PFLAG2_PADDING_RESOLVED) == PFLAG2_PADDING_RESOLVED; 16717 } 16718 16719 /** 16720 * Resolves padding depending on layout direction, if applicable, and 16721 * recomputes internal padding values to adjust for scroll bars. 16722 * 16723 * @hide 16724 */ 16725 public void resolvePadding() { 16726 final int resolvedLayoutDirection = getLayoutDirection(); 16727 16728 if (!isRtlCompatibilityMode()) { 16729 // Post Jelly Bean MR1 case: we need to take the resolved layout direction into account. 16730 // If start / end padding are defined, they will be resolved (hence overriding) to 16731 // left / right or right / left depending on the resolved layout direction. 16732 // If start / end padding are not defined, use the left / right ones. 16733 if (mBackground != null && (!mLeftPaddingDefined || !mRightPaddingDefined)) { 16734 Rect padding = sThreadLocal.get(); 16735 if (padding == null) { 16736 padding = new Rect(); 16737 sThreadLocal.set(padding); 16738 } 16739 mBackground.getPadding(padding); 16740 if (!mLeftPaddingDefined) { 16741 mUserPaddingLeftInitial = padding.left; 16742 } 16743 if (!mRightPaddingDefined) { 16744 mUserPaddingRightInitial = padding.right; 16745 } 16746 } 16747 switch (resolvedLayoutDirection) { 16748 case LAYOUT_DIRECTION_RTL: 16749 if (mUserPaddingStart != UNDEFINED_PADDING) { 16750 mUserPaddingRight = mUserPaddingStart; 16751 } else { 16752 mUserPaddingRight = mUserPaddingRightInitial; 16753 } 16754 if (mUserPaddingEnd != UNDEFINED_PADDING) { 16755 mUserPaddingLeft = mUserPaddingEnd; 16756 } else { 16757 mUserPaddingLeft = mUserPaddingLeftInitial; 16758 } 16759 break; 16760 case LAYOUT_DIRECTION_LTR: 16761 default: 16762 if (mUserPaddingStart != UNDEFINED_PADDING) { 16763 mUserPaddingLeft = mUserPaddingStart; 16764 } else { 16765 mUserPaddingLeft = mUserPaddingLeftInitial; 16766 } 16767 if (mUserPaddingEnd != UNDEFINED_PADDING) { 16768 mUserPaddingRight = mUserPaddingEnd; 16769 } else { 16770 mUserPaddingRight = mUserPaddingRightInitial; 16771 } 16772 } 16773 16774 mUserPaddingBottom = (mUserPaddingBottom >= 0) ? mUserPaddingBottom : mPaddingBottom; 16775 } 16776 16777 internalSetPadding(mUserPaddingLeft, mPaddingTop, mUserPaddingRight, mUserPaddingBottom); 16778 onRtlPropertiesChanged(resolvedLayoutDirection); 16779 16780 mPrivateFlags2 |= PFLAG2_PADDING_RESOLVED; 16781 } 16782 16783 /** 16784 * Reset the resolved layout direction. 16785 * 16786 * @hide 16787 */ 16788 public void resetResolvedPadding() { 16789 resetResolvedPaddingInternal(); 16790 } 16791 16792 /** 16793 * Used when we only want to reset *this* view's padding and not trigger overrides 16794 * in ViewGroup that reset children too. 16795 */ 16796 void resetResolvedPaddingInternal() { 16797 mPrivateFlags2 &= ~PFLAG2_PADDING_RESOLVED; 16798 } 16799 16800 /** 16801 * This is called when the view is detached from a window. At this point it 16802 * no longer has a surface for drawing. 16803 * 16804 * @see #onAttachedToWindow() 16805 */ 16806 @CallSuper 16807 protected void onDetachedFromWindow() { 16808 } 16809 16810 /** 16811 * This is a framework-internal mirror of onDetachedFromWindow() that's called 16812 * after onDetachedFromWindow(). 16813 * 16814 * If you override this you *MUST* call super.onDetachedFromWindowInternal()! 16815 * The super method should be called at the end of the overridden method to ensure 16816 * subclasses are destroyed first 16817 * 16818 * @hide 16819 */ 16820 @CallSuper 16821 protected void onDetachedFromWindowInternal() { 16822 mPrivateFlags &= ~PFLAG_CANCEL_NEXT_UP_EVENT; 16823 mPrivateFlags3 &= ~PFLAG3_IS_LAID_OUT; 16824 mPrivateFlags3 &= ~PFLAG3_TEMPORARY_DETACH; 16825 16826 removeUnsetPressCallback(); 16827 removeLongPressCallback(); 16828 removePerformClickCallback(); 16829 removeSendViewScrolledAccessibilityEventCallback(); 16830 stopNestedScroll(); 16831 16832 // Anything that started animating right before detach should already 16833 // be in its final state when re-attached. 16834 jumpDrawablesToCurrentState(); 16835 16836 destroyDrawingCache(); 16837 16838 cleanupDraw(); 16839 mCurrentAnimation = null; 16840 16841 if ((mViewFlags & TOOLTIP) == TOOLTIP) { 16842 hideTooltip(); 16843 } 16844 } 16845 16846 private void cleanupDraw() { 16847 resetDisplayList(); 16848 if (mAttachInfo != null) { 16849 mAttachInfo.mViewRootImpl.cancelInvalidate(this); 16850 } 16851 } 16852 16853 void invalidateInheritedLayoutMode(int layoutModeOfRoot) { 16854 } 16855 16856 /** 16857 * @return The number of times this view has been attached to a window 16858 */ 16859 protected int getWindowAttachCount() { 16860 return mWindowAttachCount; 16861 } 16862 16863 /** 16864 * Retrieve a unique token identifying the window this view is attached to. 16865 * @return Return the window's token for use in 16866 * {@link WindowManager.LayoutParams#token WindowManager.LayoutParams.token}. 16867 */ 16868 public IBinder getWindowToken() { 16869 return mAttachInfo != null ? mAttachInfo.mWindowToken : null; 16870 } 16871 16872 /** 16873 * Retrieve the {@link WindowId} for the window this view is 16874 * currently attached to. 16875 */ 16876 public WindowId getWindowId() { 16877 if (mAttachInfo == null) { 16878 return null; 16879 } 16880 if (mAttachInfo.mWindowId == null) { 16881 try { 16882 mAttachInfo.mIWindowId = mAttachInfo.mSession.getWindowId( 16883 mAttachInfo.mWindowToken); 16884 mAttachInfo.mWindowId = new WindowId( 16885 mAttachInfo.mIWindowId); 16886 } catch (RemoteException e) { 16887 } 16888 } 16889 return mAttachInfo.mWindowId; 16890 } 16891 16892 /** 16893 * Retrieve a unique token identifying the top-level "real" window of 16894 * the window that this view is attached to. That is, this is like 16895 * {@link #getWindowToken}, except if the window this view in is a panel 16896 * window (attached to another containing window), then the token of 16897 * the containing window is returned instead. 16898 * 16899 * @return Returns the associated window token, either 16900 * {@link #getWindowToken()} or the containing window's token. 16901 */ 16902 public IBinder getApplicationWindowToken() { 16903 AttachInfo ai = mAttachInfo; 16904 if (ai != null) { 16905 IBinder appWindowToken = ai.mPanelParentWindowToken; 16906 if (appWindowToken == null) { 16907 appWindowToken = ai.mWindowToken; 16908 } 16909 return appWindowToken; 16910 } 16911 return null; 16912 } 16913 16914 /** 16915 * Gets the logical display to which the view's window has been attached. 16916 * 16917 * @return The logical display, or null if the view is not currently attached to a window. 16918 */ 16919 public Display getDisplay() { 16920 return mAttachInfo != null ? mAttachInfo.mDisplay : null; 16921 } 16922 16923 /** 16924 * Retrieve private session object this view hierarchy is using to 16925 * communicate with the window manager. 16926 * @return the session object to communicate with the window manager 16927 */ 16928 /*package*/ IWindowSession getWindowSession() { 16929 return mAttachInfo != null ? mAttachInfo.mSession : null; 16930 } 16931 16932 /** 16933 * Return the visibility value of the least visible component passed. 16934 */ 16935 int combineVisibility(int vis1, int vis2) { 16936 // This works because VISIBLE < INVISIBLE < GONE. 16937 return Math.max(vis1, vis2); 16938 } 16939 16940 /** 16941 * @param info the {@link android.view.View.AttachInfo} to associated with 16942 * this view 16943 */ 16944 void dispatchAttachedToWindow(AttachInfo info, int visibility) { 16945 mAttachInfo = info; 16946 if (mOverlay != null) { 16947 mOverlay.getOverlayView().dispatchAttachedToWindow(info, visibility); 16948 } 16949 mWindowAttachCount++; 16950 // We will need to evaluate the drawable state at least once. 16951 mPrivateFlags |= PFLAG_DRAWABLE_STATE_DIRTY; 16952 if (mFloatingTreeObserver != null) { 16953 info.mTreeObserver.merge(mFloatingTreeObserver); 16954 mFloatingTreeObserver = null; 16955 } 16956 16957 registerPendingFrameMetricsObservers(); 16958 16959 if ((mPrivateFlags&PFLAG_SCROLL_CONTAINER) != 0) { 16960 mAttachInfo.mScrollContainers.add(this); 16961 mPrivateFlags |= PFLAG_SCROLL_CONTAINER_ADDED; 16962 } 16963 // Transfer all pending runnables. 16964 if (mRunQueue != null) { 16965 mRunQueue.executeActions(info.mHandler); 16966 mRunQueue = null; 16967 } 16968 performCollectViewAttributes(mAttachInfo, visibility); 16969 onAttachedToWindow(); 16970 16971 ListenerInfo li = mListenerInfo; 16972 final CopyOnWriteArrayList<OnAttachStateChangeListener> listeners = 16973 li != null ? li.mOnAttachStateChangeListeners : null; 16974 if (listeners != null && listeners.size() > 0) { 16975 // NOTE: because of the use of CopyOnWriteArrayList, we *must* use an iterator to 16976 // perform the dispatching. The iterator is a safe guard against listeners that 16977 // could mutate the list by calling the various add/remove methods. This prevents 16978 // the array from being modified while we iterate it. 16979 for (OnAttachStateChangeListener listener : listeners) { 16980 listener.onViewAttachedToWindow(this); 16981 } 16982 } 16983 16984 int vis = info.mWindowVisibility; 16985 if (vis != GONE) { 16986 onWindowVisibilityChanged(vis); 16987 if (isShown()) { 16988 // Calling onVisibilityAggregated directly here since the subtree will also 16989 // receive dispatchAttachedToWindow and this same call 16990 onVisibilityAggregated(vis == VISIBLE); 16991 } 16992 } 16993 16994 // Send onVisibilityChanged directly instead of dispatchVisibilityChanged. 16995 // As all views in the subtree will already receive dispatchAttachedToWindow 16996 // traversing the subtree again here is not desired. 16997 onVisibilityChanged(this, visibility); 16998 16999 if ((mPrivateFlags&PFLAG_DRAWABLE_STATE_DIRTY) != 0) { 17000 // If nobody has evaluated the drawable state yet, then do it now. 17001 refreshDrawableState(); 17002 } 17003 needGlobalAttributesUpdate(false); 17004 17005 notifyEnterOrExitForAutoFillIfNeeded(true); 17006 } 17007 17008 void dispatchDetachedFromWindow() { 17009 AttachInfo info = mAttachInfo; 17010 if (info != null) { 17011 int vis = info.mWindowVisibility; 17012 if (vis != GONE) { 17013 onWindowVisibilityChanged(GONE); 17014 if (isShown()) { 17015 // Invoking onVisibilityAggregated directly here since the subtree 17016 // will also receive detached from window 17017 onVisibilityAggregated(false); 17018 } 17019 } 17020 } 17021 17022 onDetachedFromWindow(); 17023 onDetachedFromWindowInternal(); 17024 17025 InputMethodManager imm = InputMethodManager.peekInstance(); 17026 if (imm != null) { 17027 imm.onViewDetachedFromWindow(this); 17028 } 17029 17030 ListenerInfo li = mListenerInfo; 17031 final CopyOnWriteArrayList<OnAttachStateChangeListener> listeners = 17032 li != null ? li.mOnAttachStateChangeListeners : null; 17033 if (listeners != null && listeners.size() > 0) { 17034 // NOTE: because of the use of CopyOnWriteArrayList, we *must* use an iterator to 17035 // perform the dispatching. The iterator is a safe guard against listeners that 17036 // could mutate the list by calling the various add/remove methods. This prevents 17037 // the array from being modified while we iterate it. 17038 for (OnAttachStateChangeListener listener : listeners) { 17039 listener.onViewDetachedFromWindow(this); 17040 } 17041 } 17042 17043 if ((mPrivateFlags & PFLAG_SCROLL_CONTAINER_ADDED) != 0) { 17044 mAttachInfo.mScrollContainers.remove(this); 17045 mPrivateFlags &= ~PFLAG_SCROLL_CONTAINER_ADDED; 17046 } 17047 17048 mAttachInfo = null; 17049 if (mOverlay != null) { 17050 mOverlay.getOverlayView().dispatchDetachedFromWindow(); 17051 } 17052 17053 notifyEnterOrExitForAutoFillIfNeeded(false); 17054 } 17055 17056 /** 17057 * Cancel any deferred high-level input events that were previously posted to the event queue. 17058 * 17059 * <p>Many views post high-level events such as click handlers to the event queue 17060 * to run deferred in order to preserve a desired user experience - clearing visible 17061 * pressed states before executing, etc. This method will abort any events of this nature 17062 * that are currently in flight.</p> 17063 * 17064 * <p>Custom views that generate their own high-level deferred input events should override 17065 * {@link #onCancelPendingInputEvents()} and remove those pending events from the queue.</p> 17066 * 17067 * <p>This will also cancel pending input events for any child views.</p> 17068 * 17069 * <p>Note that this may not be sufficient as a debouncing strategy for clicks in all cases. 17070 * This will not impact newer events posted after this call that may occur as a result of 17071 * lower-level input events still waiting in the queue. If you are trying to prevent 17072 * double-submitted events for the duration of some sort of asynchronous transaction 17073 * you should also take other steps to protect against unexpected double inputs e.g. calling 17074 * {@link #setEnabled(boolean) setEnabled(false)} and re-enabling the view when 17075 * the transaction completes, tracking already submitted transaction IDs, etc.</p> 17076 */ 17077 public final void cancelPendingInputEvents() { 17078 dispatchCancelPendingInputEvents(); 17079 } 17080 17081 /** 17082 * Called by {@link #cancelPendingInputEvents()} to cancel input events in flight. 17083 * Overridden by ViewGroup to dispatch. Package scoped to prevent app-side meddling. 17084 */ 17085 void dispatchCancelPendingInputEvents() { 17086 mPrivateFlags3 &= ~PFLAG3_CALLED_SUPER; 17087 onCancelPendingInputEvents(); 17088 if ((mPrivateFlags3 & PFLAG3_CALLED_SUPER) != PFLAG3_CALLED_SUPER) { 17089 throw new SuperNotCalledException("View " + getClass().getSimpleName() + 17090 " did not call through to super.onCancelPendingInputEvents()"); 17091 } 17092 } 17093 17094 /** 17095 * Called as the result of a call to {@link #cancelPendingInputEvents()} on this view or 17096 * a parent view. 17097 * 17098 * <p>This method is responsible for removing any pending high-level input events that were 17099 * posted to the event queue to run later. Custom view classes that post their own deferred 17100 * high-level events via {@link #post(Runnable)}, {@link #postDelayed(Runnable, long)} or 17101 * {@link android.os.Handler} should override this method, call 17102 * <code>super.onCancelPendingInputEvents()</code> and remove those callbacks as appropriate. 17103 * </p> 17104 */ 17105 public void onCancelPendingInputEvents() { 17106 removePerformClickCallback(); 17107 cancelLongPress(); 17108 mPrivateFlags3 |= PFLAG3_CALLED_SUPER; 17109 } 17110 17111 /** 17112 * Store this view hierarchy's frozen state into the given container. 17113 * 17114 * @param container The SparseArray in which to save the view's state. 17115 * 17116 * @see #restoreHierarchyState(android.util.SparseArray) 17117 * @see #dispatchSaveInstanceState(android.util.SparseArray) 17118 * @see #onSaveInstanceState() 17119 */ 17120 public void saveHierarchyState(SparseArray<Parcelable> container) { 17121 dispatchSaveInstanceState(container); 17122 } 17123 17124 /** 17125 * Called by {@link #saveHierarchyState(android.util.SparseArray)} to store the state for 17126 * this view and its children. May be overridden to modify how freezing happens to a 17127 * view's children; for example, some views may want to not store state for their children. 17128 * 17129 * @param container The SparseArray in which to save the view's state. 17130 * 17131 * @see #dispatchRestoreInstanceState(android.util.SparseArray) 17132 * @see #saveHierarchyState(android.util.SparseArray) 17133 * @see #onSaveInstanceState() 17134 */ 17135 protected void dispatchSaveInstanceState(SparseArray<Parcelable> container) { 17136 if (mID != NO_ID && (mViewFlags & SAVE_DISABLED_MASK) == 0) { 17137 mPrivateFlags &= ~PFLAG_SAVE_STATE_CALLED; 17138 Parcelable state = onSaveInstanceState(); 17139 if ((mPrivateFlags & PFLAG_SAVE_STATE_CALLED) == 0) { 17140 throw new IllegalStateException( 17141 "Derived class did not call super.onSaveInstanceState()"); 17142 } 17143 if (state != null) { 17144 // Log.i("View", "Freezing #" + Integer.toHexString(mID) 17145 // + ": " + state); 17146 container.put(mID, state); 17147 } 17148 } 17149 } 17150 17151 /** 17152 * Hook allowing a view to generate a representation of its internal state 17153 * that can later be used to create a new instance with that same state. 17154 * This state should only contain information that is not persistent or can 17155 * not be reconstructed later. For example, you will never store your 17156 * current position on screen because that will be computed again when a 17157 * new instance of the view is placed in its view hierarchy. 17158 * <p> 17159 * Some examples of things you may store here: the current cursor position 17160 * in a text view (but usually not the text itself since that is stored in a 17161 * content provider or other persistent storage), the currently selected 17162 * item in a list view. 17163 * 17164 * @return Returns a Parcelable object containing the view's current dynamic 17165 * state, or null if there is nothing interesting to save. The 17166 * default implementation returns null. 17167 * @see #onRestoreInstanceState(android.os.Parcelable) 17168 * @see #saveHierarchyState(android.util.SparseArray) 17169 * @see #dispatchSaveInstanceState(android.util.SparseArray) 17170 * @see #setSaveEnabled(boolean) 17171 */ 17172 @CallSuper 17173 protected Parcelable onSaveInstanceState() { 17174 mPrivateFlags |= PFLAG_SAVE_STATE_CALLED; 17175 if (mStartActivityRequestWho != null || isAutofilled() 17176 || mAccessibilityViewId > LAST_APP_ACCESSIBILITY_ID) { 17177 BaseSavedState state = new BaseSavedState(AbsSavedState.EMPTY_STATE); 17178 17179 if (mStartActivityRequestWho != null) { 17180 state.mSavedData |= BaseSavedState.START_ACTIVITY_REQUESTED_WHO_SAVED; 17181 } 17182 17183 if (isAutofilled()) { 17184 state.mSavedData |= BaseSavedState.IS_AUTOFILLED; 17185 } 17186 17187 if (mAccessibilityViewId > LAST_APP_ACCESSIBILITY_ID) { 17188 state.mSavedData |= BaseSavedState.ACCESSIBILITY_ID; 17189 } 17190 17191 state.mStartActivityRequestWhoSaved = mStartActivityRequestWho; 17192 state.mIsAutofilled = isAutofilled(); 17193 state.mAccessibilityViewId = mAccessibilityViewId; 17194 return state; 17195 } 17196 return BaseSavedState.EMPTY_STATE; 17197 } 17198 17199 /** 17200 * Restore this view hierarchy's frozen state from the given container. 17201 * 17202 * @param container The SparseArray which holds previously frozen states. 17203 * 17204 * @see #saveHierarchyState(android.util.SparseArray) 17205 * @see #dispatchRestoreInstanceState(android.util.SparseArray) 17206 * @see #onRestoreInstanceState(android.os.Parcelable) 17207 */ 17208 public void restoreHierarchyState(SparseArray<Parcelable> container) { 17209 dispatchRestoreInstanceState(container); 17210 } 17211 17212 /** 17213 * Called by {@link #restoreHierarchyState(android.util.SparseArray)} to retrieve the 17214 * state for this view and its children. May be overridden to modify how restoring 17215 * happens to a view's children; for example, some views may want to not store state 17216 * for their children. 17217 * 17218 * @param container The SparseArray which holds previously saved state. 17219 * 17220 * @see #dispatchSaveInstanceState(android.util.SparseArray) 17221 * @see #restoreHierarchyState(android.util.SparseArray) 17222 * @see #onRestoreInstanceState(android.os.Parcelable) 17223 */ 17224 protected void dispatchRestoreInstanceState(SparseArray<Parcelable> container) { 17225 if (mID != NO_ID) { 17226 Parcelable state = container.get(mID); 17227 if (state != null) { 17228 // Log.i("View", "Restoreing #" + Integer.toHexString(mID) 17229 // + ": " + state); 17230 mPrivateFlags &= ~PFLAG_SAVE_STATE_CALLED; 17231 onRestoreInstanceState(state); 17232 if ((mPrivateFlags & PFLAG_SAVE_STATE_CALLED) == 0) { 17233 throw new IllegalStateException( 17234 "Derived class did not call super.onRestoreInstanceState()"); 17235 } 17236 } 17237 } 17238 } 17239 17240 /** 17241 * Hook allowing a view to re-apply a representation of its internal state that had previously 17242 * been generated by {@link #onSaveInstanceState}. This function will never be called with a 17243 * null state. 17244 * 17245 * @param state The frozen state that had previously been returned by 17246 * {@link #onSaveInstanceState}. 17247 * 17248 * @see #onSaveInstanceState() 17249 * @see #restoreHierarchyState(android.util.SparseArray) 17250 * @see #dispatchRestoreInstanceState(android.util.SparseArray) 17251 */ 17252 @CallSuper 17253 protected void onRestoreInstanceState(Parcelable state) { 17254 mPrivateFlags |= PFLAG_SAVE_STATE_CALLED; 17255 if (state != null && !(state instanceof AbsSavedState)) { 17256 throw new IllegalArgumentException("Wrong state class, expecting View State but " 17257 + "received " + state.getClass().toString() + " instead. This usually happens " 17258 + "when two views of different type have the same id in the same hierarchy. " 17259 + "This view's id is " + ViewDebug.resolveId(mContext, getId()) + ". Make sure " 17260 + "other views do not use the same id."); 17261 } 17262 if (state != null && state instanceof BaseSavedState) { 17263 BaseSavedState baseState = (BaseSavedState) state; 17264 17265 if ((baseState.mSavedData & BaseSavedState.START_ACTIVITY_REQUESTED_WHO_SAVED) != 0) { 17266 mStartActivityRequestWho = baseState.mStartActivityRequestWhoSaved; 17267 } 17268 if ((baseState.mSavedData & BaseSavedState.IS_AUTOFILLED) != 0) { 17269 setAutofilled(baseState.mIsAutofilled); 17270 } 17271 if ((baseState.mSavedData & BaseSavedState.ACCESSIBILITY_ID) != 0) { 17272 mAccessibilityViewId = baseState.mAccessibilityViewId; 17273 } 17274 } 17275 } 17276 17277 /** 17278 * <p>Return the time at which the drawing of the view hierarchy started.</p> 17279 * 17280 * @return the drawing start time in milliseconds 17281 */ 17282 public long getDrawingTime() { 17283 return mAttachInfo != null ? mAttachInfo.mDrawingTime : 0; 17284 } 17285 17286 /** 17287 * <p>Enables or disables the duplication of the parent's state into this view. When 17288 * duplication is enabled, this view gets its drawable state from its parent rather 17289 * than from its own internal properties.</p> 17290 * 17291 * <p>Note: in the current implementation, setting this property to true after the 17292 * view was added to a ViewGroup might have no effect at all. This property should 17293 * always be used from XML or set to true before adding this view to a ViewGroup.</p> 17294 * 17295 * <p>Note: if this view's parent addStateFromChildren property is enabled and this 17296 * property is enabled, an exception will be thrown.</p> 17297 * 17298 * <p>Note: if the child view uses and updates additional states which are unknown to the 17299 * parent, these states should not be affected by this method.</p> 17300 * 17301 * @param enabled True to enable duplication of the parent's drawable state, false 17302 * to disable it. 17303 * 17304 * @see #getDrawableState() 17305 * @see #isDuplicateParentStateEnabled() 17306 */ 17307 public void setDuplicateParentStateEnabled(boolean enabled) { 17308 setFlags(enabled ? DUPLICATE_PARENT_STATE : 0, DUPLICATE_PARENT_STATE); 17309 } 17310 17311 /** 17312 * <p>Indicates whether this duplicates its drawable state from its parent.</p> 17313 * 17314 * @return True if this view's drawable state is duplicated from the parent, 17315 * false otherwise 17316 * 17317 * @see #getDrawableState() 17318 * @see #setDuplicateParentStateEnabled(boolean) 17319 */ 17320 public boolean isDuplicateParentStateEnabled() { 17321 return (mViewFlags & DUPLICATE_PARENT_STATE) == DUPLICATE_PARENT_STATE; 17322 } 17323 17324 /** 17325 * <p>Specifies the type of layer backing this view. The layer can be 17326 * {@link #LAYER_TYPE_NONE}, {@link #LAYER_TYPE_SOFTWARE} or 17327 * {@link #LAYER_TYPE_HARDWARE}.</p> 17328 * 17329 * <p>A layer is associated with an optional {@link android.graphics.Paint} 17330 * instance that controls how the layer is composed on screen. The following 17331 * properties of the paint are taken into account when composing the layer:</p> 17332 * <ul> 17333 * <li>{@link android.graphics.Paint#getAlpha() Translucency (alpha)}</li> 17334 * <li>{@link android.graphics.Paint#getXfermode() Blending mode}</li> 17335 * <li>{@link android.graphics.Paint#getColorFilter() Color filter}</li> 17336 * </ul> 17337 * 17338 * <p>If this view has an alpha value set to < 1.0 by calling 17339 * {@link #setAlpha(float)}, the alpha value of the layer's paint is superseded 17340 * by this view's alpha value.</p> 17341 * 17342 * <p>Refer to the documentation of {@link #LAYER_TYPE_NONE}, 17343 * {@link #LAYER_TYPE_SOFTWARE} and {@link #LAYER_TYPE_HARDWARE} 17344 * for more information on when and how to use layers.</p> 17345 * 17346 * @param layerType The type of layer to use with this view, must be one of 17347 * {@link #LAYER_TYPE_NONE}, {@link #LAYER_TYPE_SOFTWARE} or 17348 * {@link #LAYER_TYPE_HARDWARE} 17349 * @param paint The paint used to compose the layer. This argument is optional 17350 * and can be null. It is ignored when the layer type is 17351 * {@link #LAYER_TYPE_NONE} 17352 * 17353 * @see #getLayerType() 17354 * @see #LAYER_TYPE_NONE 17355 * @see #LAYER_TYPE_SOFTWARE 17356 * @see #LAYER_TYPE_HARDWARE 17357 * @see #setAlpha(float) 17358 * 17359 * @attr ref android.R.styleable#View_layerType 17360 */ 17361 public void setLayerType(int layerType, @Nullable Paint paint) { 17362 if (layerType < LAYER_TYPE_NONE || layerType > LAYER_TYPE_HARDWARE) { 17363 throw new IllegalArgumentException("Layer type can only be one of: LAYER_TYPE_NONE, " 17364 + "LAYER_TYPE_SOFTWARE or LAYER_TYPE_HARDWARE"); 17365 } 17366 17367 boolean typeChanged = mRenderNode.setLayerType(layerType); 17368 17369 if (!typeChanged) { 17370 setLayerPaint(paint); 17371 return; 17372 } 17373 17374 if (layerType != LAYER_TYPE_SOFTWARE) { 17375 // Destroy any previous software drawing cache if present 17376 // NOTE: even if previous layer type is HW, we do this to ensure we've cleaned up 17377 // drawing cache created in View#draw when drawing to a SW canvas. 17378 destroyDrawingCache(); 17379 } 17380 17381 mLayerType = layerType; 17382 mLayerPaint = mLayerType == LAYER_TYPE_NONE ? null : paint; 17383 mRenderNode.setLayerPaint(mLayerPaint); 17384 17385 // draw() behaves differently if we are on a layer, so we need to 17386 // invalidate() here 17387 invalidateParentCaches(); 17388 invalidate(true); 17389 } 17390 17391 /** 17392 * Updates the {@link Paint} object used with the current layer (used only if the current 17393 * layer type is not set to {@link #LAYER_TYPE_NONE}). Changed properties of the Paint 17394 * provided to {@link #setLayerType(int, android.graphics.Paint)} will be used the next time 17395 * the View is redrawn, but {@link #setLayerPaint(android.graphics.Paint)} must be called to 17396 * ensure that the view gets redrawn immediately. 17397 * 17398 * <p>A layer is associated with an optional {@link android.graphics.Paint} 17399 * instance that controls how the layer is composed on screen. The following 17400 * properties of the paint are taken into account when composing the layer:</p> 17401 * <ul> 17402 * <li>{@link android.graphics.Paint#getAlpha() Translucency (alpha)}</li> 17403 * <li>{@link android.graphics.Paint#getXfermode() Blending mode}</li> 17404 * <li>{@link android.graphics.Paint#getColorFilter() Color filter}</li> 17405 * </ul> 17406 * 17407 * <p>If this view has an alpha value set to < 1.0 by calling {@link #setAlpha(float)}, the 17408 * alpha value of the layer's paint is superseded by this view's alpha value.</p> 17409 * 17410 * @param paint The paint used to compose the layer. This argument is optional 17411 * and can be null. It is ignored when the layer type is 17412 * {@link #LAYER_TYPE_NONE} 17413 * 17414 * @see #setLayerType(int, android.graphics.Paint) 17415 */ 17416 public void setLayerPaint(@Nullable Paint paint) { 17417 int layerType = getLayerType(); 17418 if (layerType != LAYER_TYPE_NONE) { 17419 mLayerPaint = paint; 17420 if (layerType == LAYER_TYPE_HARDWARE) { 17421 if (mRenderNode.setLayerPaint(paint)) { 17422 invalidateViewProperty(false, false); 17423 } 17424 } else { 17425 invalidate(); 17426 } 17427 } 17428 } 17429 17430 /** 17431 * Indicates what type of layer is currently associated with this view. By default 17432 * a view does not have a layer, and the layer type is {@link #LAYER_TYPE_NONE}. 17433 * Refer to the documentation of {@link #setLayerType(int, android.graphics.Paint)} 17434 * for more information on the different types of layers. 17435 * 17436 * @return {@link #LAYER_TYPE_NONE}, {@link #LAYER_TYPE_SOFTWARE} or 17437 * {@link #LAYER_TYPE_HARDWARE} 17438 * 17439 * @see #setLayerType(int, android.graphics.Paint) 17440 * @see #buildLayer() 17441 * @see #LAYER_TYPE_NONE 17442 * @see #LAYER_TYPE_SOFTWARE 17443 * @see #LAYER_TYPE_HARDWARE 17444 */ 17445 public int getLayerType() { 17446 return mLayerType; 17447 } 17448 17449 /** 17450 * Forces this view's layer to be created and this view to be rendered 17451 * into its layer. If this view's layer type is set to {@link #LAYER_TYPE_NONE}, 17452 * invoking this method will have no effect. 17453 * 17454 * This method can for instance be used to render a view into its layer before 17455 * starting an animation. If this view is complex, rendering into the layer 17456 * before starting the animation will avoid skipping frames. 17457 * 17458 * @throws IllegalStateException If this view is not attached to a window 17459 * 17460 * @see #setLayerType(int, android.graphics.Paint) 17461 */ 17462 public void buildLayer() { 17463 if (mLayerType == LAYER_TYPE_NONE) return; 17464 17465 final AttachInfo attachInfo = mAttachInfo; 17466 if (attachInfo == null) { 17467 throw new IllegalStateException("This view must be attached to a window first"); 17468 } 17469 17470 if (getWidth() == 0 || getHeight() == 0) { 17471 return; 17472 } 17473 17474 switch (mLayerType) { 17475 case LAYER_TYPE_HARDWARE: 17476 updateDisplayListIfDirty(); 17477 if (attachInfo.mThreadedRenderer != null && mRenderNode.isValid()) { 17478 attachInfo.mThreadedRenderer.buildLayer(mRenderNode); 17479 } 17480 break; 17481 case LAYER_TYPE_SOFTWARE: 17482 buildDrawingCache(true); 17483 break; 17484 } 17485 } 17486 17487 /** 17488 * Destroys all hardware rendering resources. This method is invoked 17489 * when the system needs to reclaim resources. Upon execution of this 17490 * method, you should free any OpenGL resources created by the view. 17491 * 17492 * Note: you <strong>must</strong> call 17493 * <code>super.destroyHardwareResources()</code> when overriding 17494 * this method. 17495 * 17496 * @hide 17497 */ 17498 @CallSuper 17499 protected void destroyHardwareResources() { 17500 if (mOverlay != null) { 17501 mOverlay.getOverlayView().destroyHardwareResources(); 17502 } 17503 if (mGhostView != null) { 17504 mGhostView.destroyHardwareResources(); 17505 } 17506 } 17507 17508 /** 17509 * <p>Enables or disables the drawing cache. When the drawing cache is enabled, the next call 17510 * to {@link #getDrawingCache()} or {@link #buildDrawingCache()} will draw the view in a 17511 * bitmap. Calling {@link #draw(android.graphics.Canvas)} will not draw from the cache when 17512 * the cache is enabled. To benefit from the cache, you must request the drawing cache by 17513 * calling {@link #getDrawingCache()} and draw it on screen if the returned bitmap is not 17514 * null.</p> 17515 * 17516 * <p>Enabling the drawing cache is similar to 17517 * {@link #setLayerType(int, android.graphics.Paint) setting a layer} when hardware 17518 * acceleration is turned off. When hardware acceleration is turned on, enabling the 17519 * drawing cache has no effect on rendering because the system uses a different mechanism 17520 * for acceleration which ignores the flag. If you want to use a Bitmap for the view, even 17521 * when hardware acceleration is enabled, see {@link #setLayerType(int, android.graphics.Paint)} 17522 * for information on how to enable software and hardware layers.</p> 17523 * 17524 * <p>This API can be used to manually generate 17525 * a bitmap copy of this view, by setting the flag to <code>true</code> and calling 17526 * {@link #getDrawingCache()}.</p> 17527 * 17528 * @param enabled true to enable the drawing cache, false otherwise 17529 * 17530 * @see #isDrawingCacheEnabled() 17531 * @see #getDrawingCache() 17532 * @see #buildDrawingCache() 17533 * @see #setLayerType(int, android.graphics.Paint) 17534 */ 17535 public void setDrawingCacheEnabled(boolean enabled) { 17536 mCachingFailed = false; 17537 setFlags(enabled ? DRAWING_CACHE_ENABLED : 0, DRAWING_CACHE_ENABLED); 17538 } 17539 17540 /** 17541 * <p>Indicates whether the drawing cache is enabled for this view.</p> 17542 * 17543 * @return true if the drawing cache is enabled 17544 * 17545 * @see #setDrawingCacheEnabled(boolean) 17546 * @see #getDrawingCache() 17547 */ 17548 @ViewDebug.ExportedProperty(category = "drawing") 17549 public boolean isDrawingCacheEnabled() { 17550 return (mViewFlags & DRAWING_CACHE_ENABLED) == DRAWING_CACHE_ENABLED; 17551 } 17552 17553 /** 17554 * Debugging utility which recursively outputs the dirty state of a view and its 17555 * descendants. 17556 * 17557 * @hide 17558 */ 17559 @SuppressWarnings({"UnusedDeclaration"}) 17560 public void outputDirtyFlags(String indent, boolean clear, int clearMask) { 17561 Log.d("View", indent + this + " DIRTY(" + (mPrivateFlags & View.PFLAG_DIRTY_MASK) + 17562 ") DRAWN(" + (mPrivateFlags & PFLAG_DRAWN) + ")" + " CACHE_VALID(" + 17563 (mPrivateFlags & View.PFLAG_DRAWING_CACHE_VALID) + 17564 ") INVALIDATED(" + (mPrivateFlags & PFLAG_INVALIDATED) + ")"); 17565 if (clear) { 17566 mPrivateFlags &= clearMask; 17567 } 17568 if (this instanceof ViewGroup) { 17569 ViewGroup parent = (ViewGroup) this; 17570 final int count = parent.getChildCount(); 17571 for (int i = 0; i < count; i++) { 17572 final View child = parent.getChildAt(i); 17573 child.outputDirtyFlags(indent + " ", clear, clearMask); 17574 } 17575 } 17576 } 17577 17578 /** 17579 * This method is used by ViewGroup to cause its children to restore or recreate their 17580 * display lists. It is called by getDisplayList() when the parent ViewGroup does not need 17581 * to recreate its own display list, which would happen if it went through the normal 17582 * draw/dispatchDraw mechanisms. 17583 * 17584 * @hide 17585 */ 17586 protected void dispatchGetDisplayList() {} 17587 17588 /** 17589 * A view that is not attached or hardware accelerated cannot create a display list. 17590 * This method checks these conditions and returns the appropriate result. 17591 * 17592 * @return true if view has the ability to create a display list, false otherwise. 17593 * 17594 * @hide 17595 */ 17596 public boolean canHaveDisplayList() { 17597 return !(mAttachInfo == null || mAttachInfo.mThreadedRenderer == null); 17598 } 17599 17600 /** 17601 * Gets the RenderNode for the view, and updates its DisplayList (if needed and supported) 17602 * @hide 17603 */ 17604 @NonNull 17605 public RenderNode updateDisplayListIfDirty() { 17606 final RenderNode renderNode = mRenderNode; 17607 if (!canHaveDisplayList()) { 17608 // can't populate RenderNode, don't try 17609 return renderNode; 17610 } 17611 17612 if ((mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == 0 17613 || !renderNode.isValid() 17614 || (mRecreateDisplayList)) { 17615 // Don't need to recreate the display list, just need to tell our 17616 // children to restore/recreate theirs 17617 if (renderNode.isValid() 17618 && !mRecreateDisplayList) { 17619 mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID; 17620 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 17621 dispatchGetDisplayList(); 17622 17623 return renderNode; // no work needed 17624 } 17625 17626 // If we got here, we're recreating it. Mark it as such to ensure that 17627 // we copy in child display lists into ours in drawChild() 17628 mRecreateDisplayList = true; 17629 17630 int width = mRight - mLeft; 17631 int height = mBottom - mTop; 17632 int layerType = getLayerType(); 17633 17634 final DisplayListCanvas canvas = renderNode.start(width, height); 17635 canvas.setHighContrastText(mAttachInfo.mHighContrastText); 17636 17637 try { 17638 if (layerType == LAYER_TYPE_SOFTWARE) { 17639 buildDrawingCache(true); 17640 Bitmap cache = getDrawingCache(true); 17641 if (cache != null) { 17642 canvas.drawBitmap(cache, 0, 0, mLayerPaint); 17643 } 17644 } else { 17645 computeScroll(); 17646 17647 canvas.translate(-mScrollX, -mScrollY); 17648 mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID; 17649 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 17650 17651 // Fast path for layouts with no backgrounds 17652 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { 17653 dispatchDraw(canvas); 17654 drawAutofilledHighlight(canvas); 17655 if (mOverlay != null && !mOverlay.isEmpty()) { 17656 mOverlay.getOverlayView().draw(canvas); 17657 } 17658 if (debugDraw()) { 17659 debugDrawFocus(canvas); 17660 } 17661 } else { 17662 draw(canvas); 17663 } 17664 } 17665 } finally { 17666 renderNode.end(canvas); 17667 setDisplayListProperties(renderNode); 17668 } 17669 } else { 17670 mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID; 17671 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 17672 } 17673 return renderNode; 17674 } 17675 17676 private void resetDisplayList() { 17677 mRenderNode.discardDisplayList(); 17678 if (mBackgroundRenderNode != null) { 17679 mBackgroundRenderNode.discardDisplayList(); 17680 } 17681 } 17682 17683 /** 17684 * <p>Calling this method is equivalent to calling <code>getDrawingCache(false)</code>.</p> 17685 * 17686 * @return A non-scaled bitmap representing this view or null if cache is disabled. 17687 * 17688 * @see #getDrawingCache(boolean) 17689 */ 17690 public Bitmap getDrawingCache() { 17691 return getDrawingCache(false); 17692 } 17693 17694 /** 17695 * <p>Returns the bitmap in which this view drawing is cached. The returned bitmap 17696 * is null when caching is disabled. If caching is enabled and the cache is not ready, 17697 * this method will create it. Calling {@link #draw(android.graphics.Canvas)} will not 17698 * draw from the cache when the cache is enabled. To benefit from the cache, you must 17699 * request the drawing cache by calling this method and draw it on screen if the 17700 * returned bitmap is not null.</p> 17701 * 17702 * <p>Note about auto scaling in compatibility mode: When auto scaling is not enabled, 17703 * this method will create a bitmap of the same size as this view. Because this bitmap 17704 * will be drawn scaled by the parent ViewGroup, the result on screen might show 17705 * scaling artifacts. To avoid such artifacts, you should call this method by setting 17706 * the auto scaling to true. Doing so, however, will generate a bitmap of a different 17707 * size than the view. This implies that your application must be able to handle this 17708 * size.</p> 17709 * 17710 * @param autoScale Indicates whether the generated bitmap should be scaled based on 17711 * the current density of the screen when the application is in compatibility 17712 * mode. 17713 * 17714 * @return A bitmap representing this view or null if cache is disabled. 17715 * 17716 * @see #setDrawingCacheEnabled(boolean) 17717 * @see #isDrawingCacheEnabled() 17718 * @see #buildDrawingCache(boolean) 17719 * @see #destroyDrawingCache() 17720 */ 17721 public Bitmap getDrawingCache(boolean autoScale) { 17722 if ((mViewFlags & WILL_NOT_CACHE_DRAWING) == WILL_NOT_CACHE_DRAWING) { 17723 return null; 17724 } 17725 if ((mViewFlags & DRAWING_CACHE_ENABLED) == DRAWING_CACHE_ENABLED) { 17726 buildDrawingCache(autoScale); 17727 } 17728 return autoScale ? mDrawingCache : mUnscaledDrawingCache; 17729 } 17730 17731 /** 17732 * <p>Frees the resources used by the drawing cache. If you call 17733 * {@link #buildDrawingCache()} manually without calling 17734 * {@link #setDrawingCacheEnabled(boolean) setDrawingCacheEnabled(true)}, you 17735 * should cleanup the cache with this method afterwards.</p> 17736 * 17737 * @see #setDrawingCacheEnabled(boolean) 17738 * @see #buildDrawingCache() 17739 * @see #getDrawingCache() 17740 */ 17741 public void destroyDrawingCache() { 17742 if (mDrawingCache != null) { 17743 mDrawingCache.recycle(); 17744 mDrawingCache = null; 17745 } 17746 if (mUnscaledDrawingCache != null) { 17747 mUnscaledDrawingCache.recycle(); 17748 mUnscaledDrawingCache = null; 17749 } 17750 } 17751 17752 /** 17753 * Setting a solid background color for the drawing cache's bitmaps will improve 17754 * performance and memory usage. Note, though that this should only be used if this 17755 * view will always be drawn on top of a solid color. 17756 * 17757 * @param color The background color to use for the drawing cache's bitmap 17758 * 17759 * @see #setDrawingCacheEnabled(boolean) 17760 * @see #buildDrawingCache() 17761 * @see #getDrawingCache() 17762 */ 17763 public void setDrawingCacheBackgroundColor(@ColorInt int color) { 17764 if (color != mDrawingCacheBackgroundColor) { 17765 mDrawingCacheBackgroundColor = color; 17766 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; 17767 } 17768 } 17769 17770 /** 17771 * @see #setDrawingCacheBackgroundColor(int) 17772 * 17773 * @return The background color to used for the drawing cache's bitmap 17774 */ 17775 @ColorInt 17776 public int getDrawingCacheBackgroundColor() { 17777 return mDrawingCacheBackgroundColor; 17778 } 17779 17780 /** 17781 * <p>Calling this method is equivalent to calling <code>buildDrawingCache(false)</code>.</p> 17782 * 17783 * @see #buildDrawingCache(boolean) 17784 */ 17785 public void buildDrawingCache() { 17786 buildDrawingCache(false); 17787 } 17788 17789 /** 17790 * <p>Forces the drawing cache to be built if the drawing cache is invalid.</p> 17791 * 17792 * <p>If you call {@link #buildDrawingCache()} manually without calling 17793 * {@link #setDrawingCacheEnabled(boolean) setDrawingCacheEnabled(true)}, you 17794 * should cleanup the cache by calling {@link #destroyDrawingCache()} afterwards.</p> 17795 * 17796 * <p>Note about auto scaling in compatibility mode: When auto scaling is not enabled, 17797 * this method will create a bitmap of the same size as this view. Because this bitmap 17798 * will be drawn scaled by the parent ViewGroup, the result on screen might show 17799 * scaling artifacts. To avoid such artifacts, you should call this method by setting 17800 * the auto scaling to true. Doing so, however, will generate a bitmap of a different 17801 * size than the view. This implies that your application must be able to handle this 17802 * size.</p> 17803 * 17804 * <p>You should avoid calling this method when hardware acceleration is enabled. If 17805 * you do not need the drawing cache bitmap, calling this method will increase memory 17806 * usage and cause the view to be rendered in software once, thus negatively impacting 17807 * performance.</p> 17808 * 17809 * @see #getDrawingCache() 17810 * @see #destroyDrawingCache() 17811 */ 17812 public void buildDrawingCache(boolean autoScale) { 17813 if ((mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == 0 || (autoScale ? 17814 mDrawingCache == null : mUnscaledDrawingCache == null)) { 17815 if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) { 17816 Trace.traceBegin(Trace.TRACE_TAG_VIEW, 17817 "buildDrawingCache/SW Layer for " + getClass().getSimpleName()); 17818 } 17819 try { 17820 buildDrawingCacheImpl(autoScale); 17821 } finally { 17822 Trace.traceEnd(Trace.TRACE_TAG_VIEW); 17823 } 17824 } 17825 } 17826 17827 /** 17828 * private, internal implementation of buildDrawingCache, used to enable tracing 17829 */ 17830 private void buildDrawingCacheImpl(boolean autoScale) { 17831 mCachingFailed = false; 17832 17833 int width = mRight - mLeft; 17834 int height = mBottom - mTop; 17835 17836 final AttachInfo attachInfo = mAttachInfo; 17837 final boolean scalingRequired = attachInfo != null && attachInfo.mScalingRequired; 17838 17839 if (autoScale && scalingRequired) { 17840 width = (int) ((width * attachInfo.mApplicationScale) + 0.5f); 17841 height = (int) ((height * attachInfo.mApplicationScale) + 0.5f); 17842 } 17843 17844 final int drawingCacheBackgroundColor = mDrawingCacheBackgroundColor; 17845 final boolean opaque = drawingCacheBackgroundColor != 0 || isOpaque(); 17846 final boolean use32BitCache = attachInfo != null && attachInfo.mUse32BitDrawingCache; 17847 17848 final long projectedBitmapSize = width * height * (opaque && !use32BitCache ? 2 : 4); 17849 final long drawingCacheSize = 17850 ViewConfiguration.get(mContext).getScaledMaximumDrawingCacheSize(); 17851 if (width <= 0 || height <= 0 || projectedBitmapSize > drawingCacheSize) { 17852 if (width > 0 && height > 0) { 17853 Log.w(VIEW_LOG_TAG, getClass().getSimpleName() + " not displayed because it is" 17854 + " too large to fit into a software layer (or drawing cache), needs " 17855 + projectedBitmapSize + " bytes, only " 17856 + drawingCacheSize + " available"); 17857 } 17858 destroyDrawingCache(); 17859 mCachingFailed = true; 17860 return; 17861 } 17862 17863 boolean clear = true; 17864 Bitmap bitmap = autoScale ? mDrawingCache : mUnscaledDrawingCache; 17865 17866 if (bitmap == null || bitmap.getWidth() != width || bitmap.getHeight() != height) { 17867 Bitmap.Config quality; 17868 if (!opaque) { 17869 // Never pick ARGB_4444 because it looks awful 17870 // Keep the DRAWING_CACHE_QUALITY_LOW flag just in case 17871 switch (mViewFlags & DRAWING_CACHE_QUALITY_MASK) { 17872 case DRAWING_CACHE_QUALITY_AUTO: 17873 case DRAWING_CACHE_QUALITY_LOW: 17874 case DRAWING_CACHE_QUALITY_HIGH: 17875 default: 17876 quality = Bitmap.Config.ARGB_8888; 17877 break; 17878 } 17879 } else { 17880 // Optimization for translucent windows 17881 // If the window is translucent, use a 32 bits bitmap to benefit from memcpy() 17882 quality = use32BitCache ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565; 17883 } 17884 17885 // Try to cleanup memory 17886 if (bitmap != null) bitmap.recycle(); 17887 17888 try { 17889 bitmap = Bitmap.createBitmap(mResources.getDisplayMetrics(), 17890 width, height, quality); 17891 bitmap.setDensity(getResources().getDisplayMetrics().densityDpi); 17892 if (autoScale) { 17893 mDrawingCache = bitmap; 17894 } else { 17895 mUnscaledDrawingCache = bitmap; 17896 } 17897 if (opaque && use32BitCache) bitmap.setHasAlpha(false); 17898 } catch (OutOfMemoryError e) { 17899 // If there is not enough memory to create the bitmap cache, just 17900 // ignore the issue as bitmap caches are not required to draw the 17901 // view hierarchy 17902 if (autoScale) { 17903 mDrawingCache = null; 17904 } else { 17905 mUnscaledDrawingCache = null; 17906 } 17907 mCachingFailed = true; 17908 return; 17909 } 17910 17911 clear = drawingCacheBackgroundColor != 0; 17912 } 17913 17914 Canvas canvas; 17915 if (attachInfo != null) { 17916 canvas = attachInfo.mCanvas; 17917 if (canvas == null) { 17918 canvas = new Canvas(); 17919 } 17920 canvas.setBitmap(bitmap); 17921 // Temporarily clobber the cached Canvas in case one of our children 17922 // is also using a drawing cache. Without this, the children would 17923 // steal the canvas by attaching their own bitmap to it and bad, bad 17924 // thing would happen (invisible views, corrupted drawings, etc.) 17925 attachInfo.mCanvas = null; 17926 } else { 17927 // This case should hopefully never or seldom happen 17928 canvas = new Canvas(bitmap); 17929 } 17930 17931 if (clear) { 17932 bitmap.eraseColor(drawingCacheBackgroundColor); 17933 } 17934 17935 computeScroll(); 17936 final int restoreCount = canvas.save(); 17937 17938 if (autoScale && scalingRequired) { 17939 final float scale = attachInfo.mApplicationScale; 17940 canvas.scale(scale, scale); 17941 } 17942 17943 canvas.translate(-mScrollX, -mScrollY); 17944 17945 mPrivateFlags |= PFLAG_DRAWN; 17946 if (mAttachInfo == null || !mAttachInfo.mHardwareAccelerated || 17947 mLayerType != LAYER_TYPE_NONE) { 17948 mPrivateFlags |= PFLAG_DRAWING_CACHE_VALID; 17949 } 17950 17951 // Fast path for layouts with no backgrounds 17952 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { 17953 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 17954 dispatchDraw(canvas); 17955 drawAutofilledHighlight(canvas); 17956 if (mOverlay != null && !mOverlay.isEmpty()) { 17957 mOverlay.getOverlayView().draw(canvas); 17958 } 17959 } else { 17960 draw(canvas); 17961 } 17962 17963 canvas.restoreToCount(restoreCount); 17964 canvas.setBitmap(null); 17965 17966 if (attachInfo != null) { 17967 // Restore the cached Canvas for our siblings 17968 attachInfo.mCanvas = canvas; 17969 } 17970 } 17971 17972 /** 17973 * Create a snapshot of the view into a bitmap. We should probably make 17974 * some form of this public, but should think about the API. 17975 * 17976 * @hide 17977 */ 17978 public Bitmap createSnapshot(Bitmap.Config quality, int backgroundColor, boolean skipChildren) { 17979 int width = mRight - mLeft; 17980 int height = mBottom - mTop; 17981 17982 final AttachInfo attachInfo = mAttachInfo; 17983 final float scale = attachInfo != null ? attachInfo.mApplicationScale : 1.0f; 17984 width = (int) ((width * scale) + 0.5f); 17985 height = (int) ((height * scale) + 0.5f); 17986 17987 Bitmap bitmap = Bitmap.createBitmap(mResources.getDisplayMetrics(), 17988 width > 0 ? width : 1, height > 0 ? height : 1, quality); 17989 if (bitmap == null) { 17990 throw new OutOfMemoryError(); 17991 } 17992 17993 Resources resources = getResources(); 17994 if (resources != null) { 17995 bitmap.setDensity(resources.getDisplayMetrics().densityDpi); 17996 } 17997 17998 Canvas canvas; 17999 if (attachInfo != null) { 18000 canvas = attachInfo.mCanvas; 18001 if (canvas == null) { 18002 canvas = new Canvas(); 18003 } 18004 canvas.setBitmap(bitmap); 18005 // Temporarily clobber the cached Canvas in case one of our children 18006 // is also using a drawing cache. Without this, the children would 18007 // steal the canvas by attaching their own bitmap to it and bad, bad 18008 // things would happen (invisible views, corrupted drawings, etc.) 18009 attachInfo.mCanvas = null; 18010 } else { 18011 // This case should hopefully never or seldom happen 18012 canvas = new Canvas(bitmap); 18013 } 18014 boolean enabledHwBitmapsInSwMode = canvas.isHwBitmapsInSwModeEnabled(); 18015 canvas.setHwBitmapsInSwModeEnabled(true); 18016 if ((backgroundColor & 0xff000000) != 0) { 18017 bitmap.eraseColor(backgroundColor); 18018 } 18019 18020 computeScroll(); 18021 final int restoreCount = canvas.save(); 18022 canvas.scale(scale, scale); 18023 canvas.translate(-mScrollX, -mScrollY); 18024 18025 // Temporarily remove the dirty mask 18026 int flags = mPrivateFlags; 18027 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 18028 18029 // Fast path for layouts with no backgrounds 18030 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { 18031 dispatchDraw(canvas); 18032 drawAutofilledHighlight(canvas); 18033 if (mOverlay != null && !mOverlay.isEmpty()) { 18034 mOverlay.getOverlayView().draw(canvas); 18035 } 18036 } else { 18037 draw(canvas); 18038 } 18039 18040 mPrivateFlags = flags; 18041 18042 canvas.restoreToCount(restoreCount); 18043 canvas.setBitmap(null); 18044 canvas.setHwBitmapsInSwModeEnabled(enabledHwBitmapsInSwMode); 18045 18046 if (attachInfo != null) { 18047 // Restore the cached Canvas for our siblings 18048 attachInfo.mCanvas = canvas; 18049 } 18050 18051 return bitmap; 18052 } 18053 18054 /** 18055 * Indicates whether this View is currently in edit mode. A View is usually 18056 * in edit mode when displayed within a developer tool. For instance, if 18057 * this View is being drawn by a visual user interface builder, this method 18058 * should return true. 18059 * 18060 * Subclasses should check the return value of this method to provide 18061 * different behaviors if their normal behavior might interfere with the 18062 * host environment. For instance: the class spawns a thread in its 18063 * constructor, the drawing code relies on device-specific features, etc. 18064 * 18065 * This method is usually checked in the drawing code of custom widgets. 18066 * 18067 * @return True if this View is in edit mode, false otherwise. 18068 */ 18069 public boolean isInEditMode() { 18070 return false; 18071 } 18072 18073 /** 18074 * If the View draws content inside its padding and enables fading edges, 18075 * it needs to support padding offsets. Padding offsets are added to the 18076 * fading edges to extend the length of the fade so that it covers pixels 18077 * drawn inside the padding. 18078 * 18079 * Subclasses of this class should override this method if they need 18080 * to draw content inside the padding. 18081 * 18082 * @return True if padding offset must be applied, false otherwise. 18083 * 18084 * @see #getLeftPaddingOffset() 18085 * @see #getRightPaddingOffset() 18086 * @see #getTopPaddingOffset() 18087 * @see #getBottomPaddingOffset() 18088 * 18089 * @since CURRENT 18090 */ 18091 protected boolean isPaddingOffsetRequired() { 18092 return false; 18093 } 18094 18095 /** 18096 * Amount by which to extend the left fading region. Called only when 18097 * {@link #isPaddingOffsetRequired()} returns true. 18098 * 18099 * @return The left padding offset in pixels. 18100 * 18101 * @see #isPaddingOffsetRequired() 18102 * 18103 * @since CURRENT 18104 */ 18105 protected int getLeftPaddingOffset() { 18106 return 0; 18107 } 18108 18109 /** 18110 * Amount by which to extend the right fading region. Called only when 18111 * {@link #isPaddingOffsetRequired()} returns true. 18112 * 18113 * @return The right padding offset in pixels. 18114 * 18115 * @see #isPaddingOffsetRequired() 18116 * 18117 * @since CURRENT 18118 */ 18119 protected int getRightPaddingOffset() { 18120 return 0; 18121 } 18122 18123 /** 18124 * Amount by which to extend the top fading region. Called only when 18125 * {@link #isPaddingOffsetRequired()} returns true. 18126 * 18127 * @return The top padding offset in pixels. 18128 * 18129 * @see #isPaddingOffsetRequired() 18130 * 18131 * @since CURRENT 18132 */ 18133 protected int getTopPaddingOffset() { 18134 return 0; 18135 } 18136 18137 /** 18138 * Amount by which to extend the bottom fading region. Called only when 18139 * {@link #isPaddingOffsetRequired()} returns true. 18140 * 18141 * @return The bottom padding offset in pixels. 18142 * 18143 * @see #isPaddingOffsetRequired() 18144 * 18145 * @since CURRENT 18146 */ 18147 protected int getBottomPaddingOffset() { 18148 return 0; 18149 } 18150 18151 /** 18152 * @hide 18153 * @param offsetRequired 18154 */ 18155 protected int getFadeTop(boolean offsetRequired) { 18156 int top = mPaddingTop; 18157 if (offsetRequired) top += getTopPaddingOffset(); 18158 return top; 18159 } 18160 18161 /** 18162 * @hide 18163 * @param offsetRequired 18164 */ 18165 protected int getFadeHeight(boolean offsetRequired) { 18166 int padding = mPaddingTop; 18167 if (offsetRequired) padding += getTopPaddingOffset(); 18168 return mBottom - mTop - mPaddingBottom - padding; 18169 } 18170 18171 /** 18172 * <p>Indicates whether this view is attached to a hardware accelerated 18173 * window or not.</p> 18174 * 18175 * <p>Even if this method returns true, it does not mean that every call 18176 * to {@link #draw(android.graphics.Canvas)} will be made with an hardware 18177 * accelerated {@link android.graphics.Canvas}. For instance, if this view 18178 * is drawn onto an offscreen {@link android.graphics.Bitmap} and its 18179 * window is hardware accelerated, 18180 * {@link android.graphics.Canvas#isHardwareAccelerated()} will likely 18181 * return false, and this method will return true.</p> 18182 * 18183 * @return True if the view is attached to a window and the window is 18184 * hardware accelerated; false in any other case. 18185 */ 18186 @ViewDebug.ExportedProperty(category = "drawing") 18187 public boolean isHardwareAccelerated() { 18188 return mAttachInfo != null && mAttachInfo.mHardwareAccelerated; 18189 } 18190 18191 /** 18192 * Sets a rectangular area on this view to which the view will be clipped 18193 * when it is drawn. Setting the value to null will remove the clip bounds 18194 * and the view will draw normally, using its full bounds. 18195 * 18196 * @param clipBounds The rectangular area, in the local coordinates of 18197 * this view, to which future drawing operations will be clipped. 18198 */ 18199 public void setClipBounds(Rect clipBounds) { 18200 if (clipBounds == mClipBounds 18201 || (clipBounds != null && clipBounds.equals(mClipBounds))) { 18202 return; 18203 } 18204 if (clipBounds != null) { 18205 if (mClipBounds == null) { 18206 mClipBounds = new Rect(clipBounds); 18207 } else { 18208 mClipBounds.set(clipBounds); 18209 } 18210 } else { 18211 mClipBounds = null; 18212 } 18213 mRenderNode.setClipBounds(mClipBounds); 18214 invalidateViewProperty(false, false); 18215 } 18216 18217 /** 18218 * Returns a copy of the current {@link #setClipBounds(Rect) clipBounds}. 18219 * 18220 * @return A copy of the current clip bounds if clip bounds are set, 18221 * otherwise null. 18222 */ 18223 public Rect getClipBounds() { 18224 return (mClipBounds != null) ? new Rect(mClipBounds) : null; 18225 } 18226 18227 18228 /** 18229 * Populates an output rectangle with the clip bounds of the view, 18230 * returning {@code true} if successful or {@code false} if the view's 18231 * clip bounds are {@code null}. 18232 * 18233 * @param outRect rectangle in which to place the clip bounds of the view 18234 * @return {@code true} if successful or {@code false} if the view's 18235 * clip bounds are {@code null} 18236 */ 18237 public boolean getClipBounds(Rect outRect) { 18238 if (mClipBounds != null) { 18239 outRect.set(mClipBounds); 18240 return true; 18241 } 18242 return false; 18243 } 18244 18245 /** 18246 * Utility function, called by draw(canvas, parent, drawingTime) to handle the less common 18247 * case of an active Animation being run on the view. 18248 */ 18249 private boolean applyLegacyAnimation(ViewGroup parent, long drawingTime, 18250 Animation a, boolean scalingRequired) { 18251 Transformation invalidationTransform; 18252 final int flags = parent.mGroupFlags; 18253 final boolean initialized = a.isInitialized(); 18254 if (!initialized) { 18255 a.initialize(mRight - mLeft, mBottom - mTop, parent.getWidth(), parent.getHeight()); 18256 a.initializeInvalidateRegion(0, 0, mRight - mLeft, mBottom - mTop); 18257 if (mAttachInfo != null) a.setListenerHandler(mAttachInfo.mHandler); 18258 onAnimationStart(); 18259 } 18260 18261 final Transformation t = parent.getChildTransformation(); 18262 boolean more = a.getTransformation(drawingTime, t, 1f); 18263 if (scalingRequired && mAttachInfo.mApplicationScale != 1f) { 18264 if (parent.mInvalidationTransformation == null) { 18265 parent.mInvalidationTransformation = new Transformation(); 18266 } 18267 invalidationTransform = parent.mInvalidationTransformation; 18268 a.getTransformation(drawingTime, invalidationTransform, 1f); 18269 } else { 18270 invalidationTransform = t; 18271 } 18272 18273 if (more) { 18274 if (!a.willChangeBounds()) { 18275 if ((flags & (ViewGroup.FLAG_OPTIMIZE_INVALIDATE | ViewGroup.FLAG_ANIMATION_DONE)) == 18276 ViewGroup.FLAG_OPTIMIZE_INVALIDATE) { 18277 parent.mGroupFlags |= ViewGroup.FLAG_INVALIDATE_REQUIRED; 18278 } else if ((flags & ViewGroup.FLAG_INVALIDATE_REQUIRED) == 0) { 18279 // The child need to draw an animation, potentially offscreen, so 18280 // make sure we do not cancel invalidate requests 18281 parent.mPrivateFlags |= PFLAG_DRAW_ANIMATION; 18282 parent.invalidate(mLeft, mTop, mRight, mBottom); 18283 } 18284 } else { 18285 if (parent.mInvalidateRegion == null) { 18286 parent.mInvalidateRegion = new RectF(); 18287 } 18288 final RectF region = parent.mInvalidateRegion; 18289 a.getInvalidateRegion(0, 0, mRight - mLeft, mBottom - mTop, region, 18290 invalidationTransform); 18291 18292 // The child need to draw an animation, potentially offscreen, so 18293 // make sure we do not cancel invalidate requests 18294 parent.mPrivateFlags |= PFLAG_DRAW_ANIMATION; 18295 18296 final int left = mLeft + (int) region.left; 18297 final int top = mTop + (int) region.top; 18298 parent.invalidate(left, top, left + (int) (region.width() + .5f), 18299 top + (int) (region.height() + .5f)); 18300 } 18301 } 18302 return more; 18303 } 18304 18305 /** 18306 * This method is called by getDisplayList() when a display list is recorded for a View. 18307 * It pushes any properties to the RenderNode that aren't managed by the RenderNode. 18308 */ 18309 void setDisplayListProperties(RenderNode renderNode) { 18310 if (renderNode != null) { 18311 renderNode.setHasOverlappingRendering(getHasOverlappingRendering()); 18312 renderNode.setClipToBounds(mParent instanceof ViewGroup 18313 && ((ViewGroup) mParent).getClipChildren()); 18314 18315 float alpha = 1; 18316 if (mParent instanceof ViewGroup && (((ViewGroup) mParent).mGroupFlags & 18317 ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) != 0) { 18318 ViewGroup parentVG = (ViewGroup) mParent; 18319 final Transformation t = parentVG.getChildTransformation(); 18320 if (parentVG.getChildStaticTransformation(this, t)) { 18321 final int transformType = t.getTransformationType(); 18322 if (transformType != Transformation.TYPE_IDENTITY) { 18323 if ((transformType & Transformation.TYPE_ALPHA) != 0) { 18324 alpha = t.getAlpha(); 18325 } 18326 if ((transformType & Transformation.TYPE_MATRIX) != 0) { 18327 renderNode.setStaticMatrix(t.getMatrix()); 18328 } 18329 } 18330 } 18331 } 18332 if (mTransformationInfo != null) { 18333 alpha *= getFinalAlpha(); 18334 if (alpha < 1) { 18335 final int multipliedAlpha = (int) (255 * alpha); 18336 if (onSetAlpha(multipliedAlpha)) { 18337 alpha = 1; 18338 } 18339 } 18340 renderNode.setAlpha(alpha); 18341 } else if (alpha < 1) { 18342 renderNode.setAlpha(alpha); 18343 } 18344 } 18345 } 18346 18347 /** 18348 * This method is called by ViewGroup.drawChild() to have each child view draw itself. 18349 * 18350 * This is where the View specializes rendering behavior based on layer type, 18351 * and hardware acceleration. 18352 */ 18353 boolean draw(Canvas canvas, ViewGroup parent, long drawingTime) { 18354 final boolean hardwareAcceleratedCanvas = canvas.isHardwareAccelerated(); 18355 /* If an attached view draws to a HW canvas, it may use its RenderNode + DisplayList. 18356 * 18357 * If a view is dettached, its DisplayList shouldn't exist. If the canvas isn't 18358 * HW accelerated, it can't handle drawing RenderNodes. 18359 */ 18360 boolean drawingWithRenderNode = mAttachInfo != null 18361 && mAttachInfo.mHardwareAccelerated 18362 && hardwareAcceleratedCanvas; 18363 18364 boolean more = false; 18365 final boolean childHasIdentityMatrix = hasIdentityMatrix(); 18366 final int parentFlags = parent.mGroupFlags; 18367 18368 if ((parentFlags & ViewGroup.FLAG_CLEAR_TRANSFORMATION) != 0) { 18369 parent.getChildTransformation().clear(); 18370 parent.mGroupFlags &= ~ViewGroup.FLAG_CLEAR_TRANSFORMATION; 18371 } 18372 18373 Transformation transformToApply = null; 18374 boolean concatMatrix = false; 18375 final boolean scalingRequired = mAttachInfo != null && mAttachInfo.mScalingRequired; 18376 final Animation a = getAnimation(); 18377 if (a != null) { 18378 more = applyLegacyAnimation(parent, drawingTime, a, scalingRequired); 18379 concatMatrix = a.willChangeTransformationMatrix(); 18380 if (concatMatrix) { 18381 mPrivateFlags3 |= PFLAG3_VIEW_IS_ANIMATING_TRANSFORM; 18382 } 18383 transformToApply = parent.getChildTransformation(); 18384 } else { 18385 if ((mPrivateFlags3 & PFLAG3_VIEW_IS_ANIMATING_TRANSFORM) != 0) { 18386 // No longer animating: clear out old animation matrix 18387 mRenderNode.setAnimationMatrix(null); 18388 mPrivateFlags3 &= ~PFLAG3_VIEW_IS_ANIMATING_TRANSFORM; 18389 } 18390 if (!drawingWithRenderNode 18391 && (parentFlags & ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) != 0) { 18392 final Transformation t = parent.getChildTransformation(); 18393 final boolean hasTransform = parent.getChildStaticTransformation(this, t); 18394 if (hasTransform) { 18395 final int transformType = t.getTransformationType(); 18396 transformToApply = transformType != Transformation.TYPE_IDENTITY ? t : null; 18397 concatMatrix = (transformType & Transformation.TYPE_MATRIX) != 0; 18398 } 18399 } 18400 } 18401 18402 concatMatrix |= !childHasIdentityMatrix; 18403 18404 // Sets the flag as early as possible to allow draw() implementations 18405 // to call invalidate() successfully when doing animations 18406 mPrivateFlags |= PFLAG_DRAWN; 18407 18408 if (!concatMatrix && 18409 (parentFlags & (ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS | 18410 ViewGroup.FLAG_CLIP_CHILDREN)) == ViewGroup.FLAG_CLIP_CHILDREN && 18411 canvas.quickReject(mLeft, mTop, mRight, mBottom, Canvas.EdgeType.BW) && 18412 (mPrivateFlags & PFLAG_DRAW_ANIMATION) == 0) { 18413 mPrivateFlags2 |= PFLAG2_VIEW_QUICK_REJECTED; 18414 return more; 18415 } 18416 mPrivateFlags2 &= ~PFLAG2_VIEW_QUICK_REJECTED; 18417 18418 if (hardwareAcceleratedCanvas) { 18419 // Clear INVALIDATED flag to allow invalidation to occur during rendering, but 18420 // retain the flag's value temporarily in the mRecreateDisplayList flag 18421 mRecreateDisplayList = (mPrivateFlags & PFLAG_INVALIDATED) != 0; 18422 mPrivateFlags &= ~PFLAG_INVALIDATED; 18423 } 18424 18425 RenderNode renderNode = null; 18426 Bitmap cache = null; 18427 int layerType = getLayerType(); // TODO: signify cache state with just 'cache' local 18428 if (layerType == LAYER_TYPE_SOFTWARE || !drawingWithRenderNode) { 18429 if (layerType != LAYER_TYPE_NONE) { 18430 // If not drawing with RenderNode, treat HW layers as SW 18431 layerType = LAYER_TYPE_SOFTWARE; 18432 buildDrawingCache(true); 18433 } 18434 cache = getDrawingCache(true); 18435 } 18436 18437 if (drawingWithRenderNode) { 18438 // Delay getting the display list until animation-driven alpha values are 18439 // set up and possibly passed on to the view 18440 renderNode = updateDisplayListIfDirty(); 18441 if (!renderNode.isValid()) { 18442 // Uncommon, but possible. If a view is removed from the hierarchy during the call 18443 // to getDisplayList(), the display list will be marked invalid and we should not 18444 // try to use it again. 18445 renderNode = null; 18446 drawingWithRenderNode = false; 18447 } 18448 } 18449 18450 int sx = 0; 18451 int sy = 0; 18452 if (!drawingWithRenderNode) { 18453 computeScroll(); 18454 sx = mScrollX; 18455 sy = mScrollY; 18456 } 18457 18458 final boolean drawingWithDrawingCache = cache != null && !drawingWithRenderNode; 18459 final boolean offsetForScroll = cache == null && !drawingWithRenderNode; 18460 18461 int restoreTo = -1; 18462 if (!drawingWithRenderNode || transformToApply != null) { 18463 restoreTo = canvas.save(); 18464 } 18465 if (offsetForScroll) { 18466 canvas.translate(mLeft - sx, mTop - sy); 18467 } else { 18468 if (!drawingWithRenderNode) { 18469 canvas.translate(mLeft, mTop); 18470 } 18471 if (scalingRequired) { 18472 if (drawingWithRenderNode) { 18473 // TODO: Might not need this if we put everything inside the DL 18474 restoreTo = canvas.save(); 18475 } 18476 // mAttachInfo cannot be null, otherwise scalingRequired == false 18477 final float scale = 1.0f / mAttachInfo.mApplicationScale; 18478 canvas.scale(scale, scale); 18479 } 18480 } 18481 18482 float alpha = drawingWithRenderNode ? 1 : (getAlpha() * getTransitionAlpha()); 18483 if (transformToApply != null 18484 || alpha < 1 18485 || !hasIdentityMatrix() 18486 || (mPrivateFlags3 & PFLAG3_VIEW_IS_ANIMATING_ALPHA) != 0) { 18487 if (transformToApply != null || !childHasIdentityMatrix) { 18488 int transX = 0; 18489 int transY = 0; 18490 18491 if (offsetForScroll) { 18492 transX = -sx; 18493 transY = -sy; 18494 } 18495 18496 if (transformToApply != null) { 18497 if (concatMatrix) { 18498 if (drawingWithRenderNode) { 18499 renderNode.setAnimationMatrix(transformToApply.getMatrix()); 18500 } else { 18501 // Undo the scroll translation, apply the transformation matrix, 18502 // then redo the scroll translate to get the correct result. 18503 canvas.translate(-transX, -transY); 18504 canvas.concat(transformToApply.getMatrix()); 18505 canvas.translate(transX, transY); 18506 } 18507 parent.mGroupFlags |= ViewGroup.FLAG_CLEAR_TRANSFORMATION; 18508 } 18509 18510 float transformAlpha = transformToApply.getAlpha(); 18511 if (transformAlpha < 1) { 18512 alpha *= transformAlpha; 18513 parent.mGroupFlags |= ViewGroup.FLAG_CLEAR_TRANSFORMATION; 18514 } 18515 } 18516 18517 if (!childHasIdentityMatrix && !drawingWithRenderNode) { 18518 canvas.translate(-transX, -transY); 18519 canvas.concat(getMatrix()); 18520 canvas.translate(transX, transY); 18521 } 18522 } 18523 18524 // Deal with alpha if it is or used to be <1 18525 if (alpha < 1 || (mPrivateFlags3 & PFLAG3_VIEW_IS_ANIMATING_ALPHA) != 0) { 18526 if (alpha < 1) { 18527 mPrivateFlags3 |= PFLAG3_VIEW_IS_ANIMATING_ALPHA; 18528 } else { 18529 mPrivateFlags3 &= ~PFLAG3_VIEW_IS_ANIMATING_ALPHA; 18530 } 18531 parent.mGroupFlags |= ViewGroup.FLAG_CLEAR_TRANSFORMATION; 18532 if (!drawingWithDrawingCache) { 18533 final int multipliedAlpha = (int) (255 * alpha); 18534 if (!onSetAlpha(multipliedAlpha)) { 18535 if (drawingWithRenderNode) { 18536 renderNode.setAlpha(alpha * getAlpha() * getTransitionAlpha()); 18537 } else if (layerType == LAYER_TYPE_NONE) { 18538 canvas.saveLayerAlpha(sx, sy, sx + getWidth(), sy + getHeight(), 18539 multipliedAlpha); 18540 } 18541 } else { 18542 // Alpha is handled by the child directly, clobber the layer's alpha 18543 mPrivateFlags |= PFLAG_ALPHA_SET; 18544 } 18545 } 18546 } 18547 } else if ((mPrivateFlags & PFLAG_ALPHA_SET) == PFLAG_ALPHA_SET) { 18548 onSetAlpha(255); 18549 mPrivateFlags &= ~PFLAG_ALPHA_SET; 18550 } 18551 18552 if (!drawingWithRenderNode) { 18553 // apply clips directly, since RenderNode won't do it for this draw 18554 if ((parentFlags & ViewGroup.FLAG_CLIP_CHILDREN) != 0 && cache == null) { 18555 if (offsetForScroll) { 18556 canvas.clipRect(sx, sy, sx + getWidth(), sy + getHeight()); 18557 } else { 18558 if (!scalingRequired || cache == null) { 18559 canvas.clipRect(0, 0, getWidth(), getHeight()); 18560 } else { 18561 canvas.clipRect(0, 0, cache.getWidth(), cache.getHeight()); 18562 } 18563 } 18564 } 18565 18566 if (mClipBounds != null) { 18567 // clip bounds ignore scroll 18568 canvas.clipRect(mClipBounds); 18569 } 18570 } 18571 18572 if (!drawingWithDrawingCache) { 18573 if (drawingWithRenderNode) { 18574 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 18575 ((DisplayListCanvas) canvas).drawRenderNode(renderNode); 18576 } else { 18577 // Fast path for layouts with no backgrounds 18578 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { 18579 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 18580 dispatchDraw(canvas); 18581 } else { 18582 draw(canvas); 18583 } 18584 } 18585 } else if (cache != null) { 18586 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 18587 if (layerType == LAYER_TYPE_NONE || mLayerPaint == null) { 18588 // no layer paint, use temporary paint to draw bitmap 18589 Paint cachePaint = parent.mCachePaint; 18590 if (cachePaint == null) { 18591 cachePaint = new Paint(); 18592 cachePaint.setDither(false); 18593 parent.mCachePaint = cachePaint; 18594 } 18595 cachePaint.setAlpha((int) (alpha * 255)); 18596 canvas.drawBitmap(cache, 0.0f, 0.0f, cachePaint); 18597 } else { 18598 // use layer paint to draw the bitmap, merging the two alphas, but also restore 18599 int layerPaintAlpha = mLayerPaint.getAlpha(); 18600 if (alpha < 1) { 18601 mLayerPaint.setAlpha((int) (alpha * layerPaintAlpha)); 18602 } 18603 canvas.drawBitmap(cache, 0.0f, 0.0f, mLayerPaint); 18604 if (alpha < 1) { 18605 mLayerPaint.setAlpha(layerPaintAlpha); 18606 } 18607 } 18608 } 18609 18610 if (restoreTo >= 0) { 18611 canvas.restoreToCount(restoreTo); 18612 } 18613 18614 if (a != null && !more) { 18615 if (!hardwareAcceleratedCanvas && !a.getFillAfter()) { 18616 onSetAlpha(255); 18617 } 18618 parent.finishAnimatingView(this, a); 18619 } 18620 18621 if (more && hardwareAcceleratedCanvas) { 18622 if (a.hasAlpha() && (mPrivateFlags & PFLAG_ALPHA_SET) == PFLAG_ALPHA_SET) { 18623 // alpha animations should cause the child to recreate its display list 18624 invalidate(true); 18625 } 18626 } 18627 18628 mRecreateDisplayList = false; 18629 18630 return more; 18631 } 18632 18633 static Paint getDebugPaint() { 18634 if (sDebugPaint == null) { 18635 sDebugPaint = new Paint(); 18636 sDebugPaint.setAntiAlias(false); 18637 } 18638 return sDebugPaint; 18639 } 18640 18641 final int dipsToPixels(int dips) { 18642 float scale = getContext().getResources().getDisplayMetrics().density; 18643 return (int) (dips * scale + 0.5f); 18644 } 18645 18646 final private void debugDrawFocus(Canvas canvas) { 18647 if (isFocused()) { 18648 final int cornerSquareSize = dipsToPixels(DEBUG_CORNERS_SIZE_DIP); 18649 final int l = mScrollX; 18650 final int r = l + mRight - mLeft; 18651 final int t = mScrollY; 18652 final int b = t + mBottom - mTop; 18653 18654 final Paint paint = getDebugPaint(); 18655 paint.setColor(DEBUG_CORNERS_COLOR); 18656 18657 // Draw squares in corners. 18658 paint.setStyle(Paint.Style.FILL); 18659 canvas.drawRect(l, t, l + cornerSquareSize, t + cornerSquareSize, paint); 18660 canvas.drawRect(r - cornerSquareSize, t, r, t + cornerSquareSize, paint); 18661 canvas.drawRect(l, b - cornerSquareSize, l + cornerSquareSize, b, paint); 18662 canvas.drawRect(r - cornerSquareSize, b - cornerSquareSize, r, b, paint); 18663 18664 // Draw big X across the view. 18665 paint.setStyle(Paint.Style.STROKE); 18666 canvas.drawLine(l, t, r, b, paint); 18667 canvas.drawLine(l, b, r, t, paint); 18668 } 18669 } 18670 18671 /** 18672 * Manually render this view (and all of its children) to the given Canvas. 18673 * The view must have already done a full layout before this function is 18674 * called. When implementing a view, implement 18675 * {@link #onDraw(android.graphics.Canvas)} instead of overriding this method. 18676 * If you do need to override this method, call the superclass version. 18677 * 18678 * @param canvas The Canvas to which the View is rendered. 18679 */ 18680 @CallSuper 18681 public void draw(Canvas canvas) { 18682 final int privateFlags = mPrivateFlags; 18683 final boolean dirtyOpaque = (privateFlags & PFLAG_DIRTY_MASK) == PFLAG_DIRTY_OPAQUE && 18684 (mAttachInfo == null || !mAttachInfo.mIgnoreDirtyState); 18685 mPrivateFlags = (privateFlags & ~PFLAG_DIRTY_MASK) | PFLAG_DRAWN; 18686 18687 /* 18688 * Draw traversal performs several drawing steps which must be executed 18689 * in the appropriate order: 18690 * 18691 * 1. Draw the background 18692 * 2. If necessary, save the canvas' layers to prepare for fading 18693 * 3. Draw view's content 18694 * 4. Draw children 18695 * 5. If necessary, draw the fading edges and restore layers 18696 * 6. Draw decorations (scrollbars for instance) 18697 */ 18698 18699 // Step 1, draw the background, if needed 18700 int saveCount; 18701 18702 if (!dirtyOpaque) { 18703 drawBackground(canvas); 18704 } 18705 18706 // skip step 2 & 5 if possible (common case) 18707 final int viewFlags = mViewFlags; 18708 boolean horizontalEdges = (viewFlags & FADING_EDGE_HORIZONTAL) != 0; 18709 boolean verticalEdges = (viewFlags & FADING_EDGE_VERTICAL) != 0; 18710 if (!verticalEdges && !horizontalEdges) { 18711 // Step 3, draw the content 18712 if (!dirtyOpaque) onDraw(canvas); 18713 18714 // Step 4, draw the children 18715 dispatchDraw(canvas); 18716 18717 drawAutofilledHighlight(canvas); 18718 18719 // Overlay is part of the content and draws beneath Foreground 18720 if (mOverlay != null && !mOverlay.isEmpty()) { 18721 mOverlay.getOverlayView().dispatchDraw(canvas); 18722 } 18723 18724 // Step 6, draw decorations (foreground, scrollbars) 18725 onDrawForeground(canvas); 18726 18727 // Step 7, draw the default focus highlight 18728 drawDefaultFocusHighlight(canvas); 18729 18730 if (debugDraw()) { 18731 debugDrawFocus(canvas); 18732 } 18733 18734 // we're done... 18735 return; 18736 } 18737 18738 /* 18739 * Here we do the full fledged routine... 18740 * (this is an uncommon case where speed matters less, 18741 * this is why we repeat some of the tests that have been 18742 * done above) 18743 */ 18744 18745 boolean drawTop = false; 18746 boolean drawBottom = false; 18747 boolean drawLeft = false; 18748 boolean drawRight = false; 18749 18750 float topFadeStrength = 0.0f; 18751 float bottomFadeStrength = 0.0f; 18752 float leftFadeStrength = 0.0f; 18753 float rightFadeStrength = 0.0f; 18754 18755 // Step 2, save the canvas' layers 18756 int paddingLeft = mPaddingLeft; 18757 18758 final boolean offsetRequired = isPaddingOffsetRequired(); 18759 if (offsetRequired) { 18760 paddingLeft += getLeftPaddingOffset(); 18761 } 18762 18763 int left = mScrollX + paddingLeft; 18764 int right = left + mRight - mLeft - mPaddingRight - paddingLeft; 18765 int top = mScrollY + getFadeTop(offsetRequired); 18766 int bottom = top + getFadeHeight(offsetRequired); 18767 18768 if (offsetRequired) { 18769 right += getRightPaddingOffset(); 18770 bottom += getBottomPaddingOffset(); 18771 } 18772 18773 final ScrollabilityCache scrollabilityCache = mScrollCache; 18774 final float fadeHeight = scrollabilityCache.fadingEdgeLength; 18775 int length = (int) fadeHeight; 18776 18777 // clip the fade length if top and bottom fades overlap 18778 // overlapping fades produce odd-looking artifacts 18779 if (verticalEdges && (top + length > bottom - length)) { 18780 length = (bottom - top) / 2; 18781 } 18782 18783 // also clip horizontal fades if necessary 18784 if (horizontalEdges && (left + length > right - length)) { 18785 length = (right - left) / 2; 18786 } 18787 18788 if (verticalEdges) { 18789 topFadeStrength = Math.max(0.0f, Math.min(1.0f, getTopFadingEdgeStrength())); 18790 drawTop = topFadeStrength * fadeHeight > 1.0f; 18791 bottomFadeStrength = Math.max(0.0f, Math.min(1.0f, getBottomFadingEdgeStrength())); 18792 drawBottom = bottomFadeStrength * fadeHeight > 1.0f; 18793 } 18794 18795 if (horizontalEdges) { 18796 leftFadeStrength = Math.max(0.0f, Math.min(1.0f, getLeftFadingEdgeStrength())); 18797 drawLeft = leftFadeStrength * fadeHeight > 1.0f; 18798 rightFadeStrength = Math.max(0.0f, Math.min(1.0f, getRightFadingEdgeStrength())); 18799 drawRight = rightFadeStrength * fadeHeight > 1.0f; 18800 } 18801 18802 saveCount = canvas.getSaveCount(); 18803 18804 int solidColor = getSolidColor(); 18805 if (solidColor == 0) { 18806 final int flags = Canvas.HAS_ALPHA_LAYER_SAVE_FLAG; 18807 18808 if (drawTop) { 18809 canvas.saveLayer(left, top, right, top + length, null, flags); 18810 } 18811 18812 if (drawBottom) { 18813 canvas.saveLayer(left, bottom - length, right, bottom, null, flags); 18814 } 18815 18816 if (drawLeft) { 18817 canvas.saveLayer(left, top, left + length, bottom, null, flags); 18818 } 18819 18820 if (drawRight) { 18821 canvas.saveLayer(right - length, top, right, bottom, null, flags); 18822 } 18823 } else { 18824 scrollabilityCache.setFadeColor(solidColor); 18825 } 18826 18827 // Step 3, draw the content 18828 if (!dirtyOpaque) onDraw(canvas); 18829 18830 // Step 4, draw the children 18831 dispatchDraw(canvas); 18832 18833 // Step 5, draw the fade effect and restore layers 18834 final Paint p = scrollabilityCache.paint; 18835 final Matrix matrix = scrollabilityCache.matrix; 18836 final Shader fade = scrollabilityCache.shader; 18837 18838 if (drawTop) { 18839 matrix.setScale(1, fadeHeight * topFadeStrength); 18840 matrix.postTranslate(left, top); 18841 fade.setLocalMatrix(matrix); 18842 p.setShader(fade); 18843 canvas.drawRect(left, top, right, top + length, p); 18844 } 18845 18846 if (drawBottom) { 18847 matrix.setScale(1, fadeHeight * bottomFadeStrength); 18848 matrix.postRotate(180); 18849 matrix.postTranslate(left, bottom); 18850 fade.setLocalMatrix(matrix); 18851 p.setShader(fade); 18852 canvas.drawRect(left, bottom - length, right, bottom, p); 18853 } 18854 18855 if (drawLeft) { 18856 matrix.setScale(1, fadeHeight * leftFadeStrength); 18857 matrix.postRotate(-90); 18858 matrix.postTranslate(left, top); 18859 fade.setLocalMatrix(matrix); 18860 p.setShader(fade); 18861 canvas.drawRect(left, top, left + length, bottom, p); 18862 } 18863 18864 if (drawRight) { 18865 matrix.setScale(1, fadeHeight * rightFadeStrength); 18866 matrix.postRotate(90); 18867 matrix.postTranslate(right, top); 18868 fade.setLocalMatrix(matrix); 18869 p.setShader(fade); 18870 canvas.drawRect(right - length, top, right, bottom, p); 18871 } 18872 18873 canvas.restoreToCount(saveCount); 18874 18875 drawAutofilledHighlight(canvas); 18876 18877 // Overlay is part of the content and draws beneath Foreground 18878 if (mOverlay != null && !mOverlay.isEmpty()) { 18879 mOverlay.getOverlayView().dispatchDraw(canvas); 18880 } 18881 18882 // Step 6, draw decorations (foreground, scrollbars) 18883 onDrawForeground(canvas); 18884 18885 if (debugDraw()) { 18886 debugDrawFocus(canvas); 18887 } 18888 } 18889 18890 /** 18891 * Draws the background onto the specified canvas. 18892 * 18893 * @param canvas Canvas on which to draw the background 18894 */ 18895 private void drawBackground(Canvas canvas) { 18896 final Drawable background = mBackground; 18897 if (background == null) { 18898 return; 18899 } 18900 18901 setBackgroundBounds(); 18902 18903 // Attempt to use a display list if requested. 18904 if (canvas.isHardwareAccelerated() && mAttachInfo != null 18905 && mAttachInfo.mThreadedRenderer != null) { 18906 mBackgroundRenderNode = getDrawableRenderNode(background, mBackgroundRenderNode); 18907 18908 final RenderNode renderNode = mBackgroundRenderNode; 18909 if (renderNode != null && renderNode.isValid()) { 18910 setBackgroundRenderNodeProperties(renderNode); 18911 ((DisplayListCanvas) canvas).drawRenderNode(renderNode); 18912 return; 18913 } 18914 } 18915 18916 final int scrollX = mScrollX; 18917 final int scrollY = mScrollY; 18918 if ((scrollX | scrollY) == 0) { 18919 background.draw(canvas); 18920 } else { 18921 canvas.translate(scrollX, scrollY); 18922 background.draw(canvas); 18923 canvas.translate(-scrollX, -scrollY); 18924 } 18925 } 18926 18927 /** 18928 * Sets the correct background bounds and rebuilds the outline, if needed. 18929 * <p/> 18930 * This is called by LayoutLib. 18931 */ 18932 void setBackgroundBounds() { 18933 if (mBackgroundSizeChanged && mBackground != null) { 18934 mBackground.setBounds(0, 0, mRight - mLeft, mBottom - mTop); 18935 mBackgroundSizeChanged = false; 18936 rebuildOutline(); 18937 } 18938 } 18939 18940 private void setBackgroundRenderNodeProperties(RenderNode renderNode) { 18941 renderNode.setTranslationX(mScrollX); 18942 renderNode.setTranslationY(mScrollY); 18943 } 18944 18945 /** 18946 * Creates a new display list or updates the existing display list for the 18947 * specified Drawable. 18948 * 18949 * @param drawable Drawable for which to create a display list 18950 * @param renderNode Existing RenderNode, or {@code null} 18951 * @return A valid display list for the specified drawable 18952 */ 18953 private RenderNode getDrawableRenderNode(Drawable drawable, RenderNode renderNode) { 18954 if (renderNode == null) { 18955 renderNode = RenderNode.create(drawable.getClass().getName(), this); 18956 } 18957 18958 final Rect bounds = drawable.getBounds(); 18959 final int width = bounds.width(); 18960 final int height = bounds.height(); 18961 final DisplayListCanvas canvas = renderNode.start(width, height); 18962 18963 // Reverse left/top translation done by drawable canvas, which will 18964 // instead be applied by rendernode's LTRB bounds below. This way, the 18965 // drawable's bounds match with its rendernode bounds and its content 18966 // will lie within those bounds in the rendernode tree. 18967 canvas.translate(-bounds.left, -bounds.top); 18968 18969 try { 18970 drawable.draw(canvas); 18971 } finally { 18972 renderNode.end(canvas); 18973 } 18974 18975 // Set up drawable properties that are view-independent. 18976 renderNode.setLeftTopRightBottom(bounds.left, bounds.top, bounds.right, bounds.bottom); 18977 renderNode.setProjectBackwards(drawable.isProjected()); 18978 renderNode.setProjectionReceiver(true); 18979 renderNode.setClipToBounds(false); 18980 return renderNode; 18981 } 18982 18983 /** 18984 * Returns the overlay for this view, creating it if it does not yet exist. 18985 * Adding drawables to the overlay will cause them to be displayed whenever 18986 * the view itself is redrawn. Objects in the overlay should be actively 18987 * managed: remove them when they should not be displayed anymore. The 18988 * overlay will always have the same size as its host view. 18989 * 18990 * <p>Note: Overlays do not currently work correctly with {@link 18991 * SurfaceView} or {@link TextureView}; contents in overlays for these 18992 * types of views may not display correctly.</p> 18993 * 18994 * @return The ViewOverlay object for this view. 18995 * @see ViewOverlay 18996 */ 18997 public ViewOverlay getOverlay() { 18998 if (mOverlay == null) { 18999 mOverlay = new ViewOverlay(mContext, this); 19000 } 19001 return mOverlay; 19002 } 19003 19004 /** 19005 * Override this if your view is known to always be drawn on top of a solid color background, 19006 * and needs to draw fading edges. Returning a non-zero color enables the view system to 19007 * optimize the drawing of the fading edges. If you do return a non-zero color, the alpha 19008 * should be set to 0xFF. 19009 * 19010 * @see #setVerticalFadingEdgeEnabled(boolean) 19011 * @see #setHorizontalFadingEdgeEnabled(boolean) 19012 * 19013 * @return The known solid color background for this view, or 0 if the color may vary 19014 */ 19015 @ViewDebug.ExportedProperty(category = "drawing") 19016 @ColorInt 19017 public int getSolidColor() { 19018 return 0; 19019 } 19020 19021 /** 19022 * Build a human readable string representation of the specified view flags. 19023 * 19024 * @param flags the view flags to convert to a string 19025 * @return a String representing the supplied flags 19026 */ 19027 private static String printFlags(int flags) { 19028 String output = ""; 19029 int numFlags = 0; 19030 if ((flags & FOCUSABLE) == FOCUSABLE) { 19031 output += "TAKES_FOCUS"; 19032 numFlags++; 19033 } 19034 19035 switch (flags & VISIBILITY_MASK) { 19036 case INVISIBLE: 19037 if (numFlags > 0) { 19038 output += " "; 19039 } 19040 output += "INVISIBLE"; 19041 // USELESS HERE numFlags++; 19042 break; 19043 case GONE: 19044 if (numFlags > 0) { 19045 output += " "; 19046 } 19047 output += "GONE"; 19048 // USELESS HERE numFlags++; 19049 break; 19050 default: 19051 break; 19052 } 19053 return output; 19054 } 19055 19056 /** 19057 * Build a human readable string representation of the specified private 19058 * view flags. 19059 * 19060 * @param privateFlags the private view flags to convert to a string 19061 * @return a String representing the supplied flags 19062 */ 19063 private static String printPrivateFlags(int privateFlags) { 19064 String output = ""; 19065 int numFlags = 0; 19066 19067 if ((privateFlags & PFLAG_WANTS_FOCUS) == PFLAG_WANTS_FOCUS) { 19068 output += "WANTS_FOCUS"; 19069 numFlags++; 19070 } 19071 19072 if ((privateFlags & PFLAG_FOCUSED) == PFLAG_FOCUSED) { 19073 if (numFlags > 0) { 19074 output += " "; 19075 } 19076 output += "FOCUSED"; 19077 numFlags++; 19078 } 19079 19080 if ((privateFlags & PFLAG_SELECTED) == PFLAG_SELECTED) { 19081 if (numFlags > 0) { 19082 output += " "; 19083 } 19084 output += "SELECTED"; 19085 numFlags++; 19086 } 19087 19088 if ((privateFlags & PFLAG_IS_ROOT_NAMESPACE) == PFLAG_IS_ROOT_NAMESPACE) { 19089 if (numFlags > 0) { 19090 output += " "; 19091 } 19092 output += "IS_ROOT_NAMESPACE"; 19093 numFlags++; 19094 } 19095 19096 if ((privateFlags & PFLAG_HAS_BOUNDS) == PFLAG_HAS_BOUNDS) { 19097 if (numFlags > 0) { 19098 output += " "; 19099 } 19100 output += "HAS_BOUNDS"; 19101 numFlags++; 19102 } 19103 19104 if ((privateFlags & PFLAG_DRAWN) == PFLAG_DRAWN) { 19105 if (numFlags > 0) { 19106 output += " "; 19107 } 19108 output += "DRAWN"; 19109 // USELESS HERE numFlags++; 19110 } 19111 return output; 19112 } 19113 19114 /** 19115 * <p>Indicates whether or not this view's layout will be requested during 19116 * the next hierarchy layout pass.</p> 19117 * 19118 * @return true if the layout will be forced during next layout pass 19119 */ 19120 public boolean isLayoutRequested() { 19121 return (mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT; 19122 } 19123 19124 /** 19125 * Return true if o is a ViewGroup that is laying out using optical bounds. 19126 * @hide 19127 */ 19128 public static boolean isLayoutModeOptical(Object o) { 19129 return o instanceof ViewGroup && ((ViewGroup) o).isLayoutModeOptical(); 19130 } 19131 19132 private boolean setOpticalFrame(int left, int top, int right, int bottom) { 19133 Insets parentInsets = mParent instanceof View ? 19134 ((View) mParent).getOpticalInsets() : Insets.NONE; 19135 Insets childInsets = getOpticalInsets(); 19136 return setFrame( 19137 left + parentInsets.left - childInsets.left, 19138 top + parentInsets.top - childInsets.top, 19139 right + parentInsets.left + childInsets.right, 19140 bottom + parentInsets.top + childInsets.bottom); 19141 } 19142 19143 /** 19144 * Assign a size and position to a view and all of its 19145 * descendants 19146 * 19147 * <p>This is the second phase of the layout mechanism. 19148 * (The first is measuring). In this phase, each parent calls 19149 * layout on all of its children to position them. 19150 * This is typically done using the child measurements 19151 * that were stored in the measure pass().</p> 19152 * 19153 * <p>Derived classes should not override this method. 19154 * Derived classes with children should override 19155 * onLayout. In that method, they should 19156 * call layout on each of their children.</p> 19157 * 19158 * @param l Left position, relative to parent 19159 * @param t Top position, relative to parent 19160 * @param r Right position, relative to parent 19161 * @param b Bottom position, relative to parent 19162 */ 19163 @SuppressWarnings({"unchecked"}) 19164 public void layout(int l, int t, int r, int b) { 19165 if ((mPrivateFlags3 & PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT) != 0) { 19166 onMeasure(mOldWidthMeasureSpec, mOldHeightMeasureSpec); 19167 mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT; 19168 } 19169 19170 int oldL = mLeft; 19171 int oldT = mTop; 19172 int oldB = mBottom; 19173 int oldR = mRight; 19174 19175 boolean changed = isLayoutModeOptical(mParent) ? 19176 setOpticalFrame(l, t, r, b) : setFrame(l, t, r, b); 19177 19178 if (changed || (mPrivateFlags & PFLAG_LAYOUT_REQUIRED) == PFLAG_LAYOUT_REQUIRED) { 19179 onLayout(changed, l, t, r, b); 19180 19181 if (shouldDrawRoundScrollbar()) { 19182 if(mRoundScrollbarRenderer == null) { 19183 mRoundScrollbarRenderer = new RoundScrollbarRenderer(this); 19184 } 19185 } else { 19186 mRoundScrollbarRenderer = null; 19187 } 19188 19189 mPrivateFlags &= ~PFLAG_LAYOUT_REQUIRED; 19190 19191 ListenerInfo li = mListenerInfo; 19192 if (li != null && li.mOnLayoutChangeListeners != null) { 19193 ArrayList<OnLayoutChangeListener> listenersCopy = 19194 (ArrayList<OnLayoutChangeListener>)li.mOnLayoutChangeListeners.clone(); 19195 int numListeners = listenersCopy.size(); 19196 for (int i = 0; i < numListeners; ++i) { 19197 listenersCopy.get(i).onLayoutChange(this, l, t, r, b, oldL, oldT, oldR, oldB); 19198 } 19199 } 19200 } 19201 19202 mPrivateFlags &= ~PFLAG_FORCE_LAYOUT; 19203 mPrivateFlags3 |= PFLAG3_IS_LAID_OUT; 19204 } 19205 19206 /** 19207 * Called from layout when this view should 19208 * assign a size and position to each of its children. 19209 * 19210 * Derived classes with children should override 19211 * this method and call layout on each of 19212 * their children. 19213 * @param changed This is a new size or position for this view 19214 * @param left Left position, relative to parent 19215 * @param top Top position, relative to parent 19216 * @param right Right position, relative to parent 19217 * @param bottom Bottom position, relative to parent 19218 */ 19219 protected void onLayout(boolean changed, int left, int top, int right, int bottom) { 19220 } 19221 19222 /** 19223 * Assign a size and position to this view. 19224 * 19225 * This is called from layout. 19226 * 19227 * @param left Left position, relative to parent 19228 * @param top Top position, relative to parent 19229 * @param right Right position, relative to parent 19230 * @param bottom Bottom position, relative to parent 19231 * @return true if the new size and position are different than the 19232 * previous ones 19233 * {@hide} 19234 */ 19235 protected boolean setFrame(int left, int top, int right, int bottom) { 19236 boolean changed = false; 19237 19238 if (DBG) { 19239 Log.d("View", this + " View.setFrame(" + left + "," + top + "," 19240 + right + "," + bottom + ")"); 19241 } 19242 19243 if (mLeft != left || mRight != right || mTop != top || mBottom != bottom) { 19244 changed = true; 19245 19246 // Remember our drawn bit 19247 int drawn = mPrivateFlags & PFLAG_DRAWN; 19248 19249 int oldWidth = mRight - mLeft; 19250 int oldHeight = mBottom - mTop; 19251 int newWidth = right - left; 19252 int newHeight = bottom - top; 19253 boolean sizeChanged = (newWidth != oldWidth) || (newHeight != oldHeight); 19254 19255 // Invalidate our old position 19256 invalidate(sizeChanged); 19257 19258 mLeft = left; 19259 mTop = top; 19260 mRight = right; 19261 mBottom = bottom; 19262 mRenderNode.setLeftTopRightBottom(mLeft, mTop, mRight, mBottom); 19263 19264 mPrivateFlags |= PFLAG_HAS_BOUNDS; 19265 19266 19267 if (sizeChanged) { 19268 sizeChange(newWidth, newHeight, oldWidth, oldHeight); 19269 } 19270 19271 if ((mViewFlags & VISIBILITY_MASK) == VISIBLE || mGhostView != null) { 19272 // If we are visible, force the DRAWN bit to on so that 19273 // this invalidate will go through (at least to our parent). 19274 // This is because someone may have invalidated this view 19275 // before this call to setFrame came in, thereby clearing 19276 // the DRAWN bit. 19277 mPrivateFlags |= PFLAG_DRAWN; 19278 invalidate(sizeChanged); 19279 // parent display list may need to be recreated based on a change in the bounds 19280 // of any child 19281 invalidateParentCaches(); 19282 } 19283 19284 // Reset drawn bit to original value (invalidate turns it off) 19285 mPrivateFlags |= drawn; 19286 19287 mBackgroundSizeChanged = true; 19288 mDefaultFocusHighlightSizeChanged = true; 19289 if (mForegroundInfo != null) { 19290 mForegroundInfo.mBoundsChanged = true; 19291 } 19292 19293 notifySubtreeAccessibilityStateChangedIfNeeded(); 19294 } 19295 return changed; 19296 } 19297 19298 /** 19299 * Same as setFrame, but public and hidden. For use in {@link android.transition.ChangeBounds}. 19300 * @hide 19301 */ 19302 public void setLeftTopRightBottom(int left, int top, int right, int bottom) { 19303 setFrame(left, top, right, bottom); 19304 } 19305 19306 private void sizeChange(int newWidth, int newHeight, int oldWidth, int oldHeight) { 19307 onSizeChanged(newWidth, newHeight, oldWidth, oldHeight); 19308 if (mOverlay != null) { 19309 mOverlay.getOverlayView().setRight(newWidth); 19310 mOverlay.getOverlayView().setBottom(newHeight); 19311 } 19312 rebuildOutline(); 19313 } 19314 19315 /** 19316 * Finalize inflating a view from XML. This is called as the last phase 19317 * of inflation, after all child views have been added. 19318 * 19319 * <p>Even if the subclass overrides onFinishInflate, they should always be 19320 * sure to call the super method, so that we get called. 19321 */ 19322 @CallSuper 19323 protected void onFinishInflate() { 19324 } 19325 19326 /** 19327 * Returns the resources associated with this view. 19328 * 19329 * @return Resources object. 19330 */ 19331 public Resources getResources() { 19332 return mResources; 19333 } 19334 19335 /** 19336 * Invalidates the specified Drawable. 19337 * 19338 * @param drawable the drawable to invalidate 19339 */ 19340 @Override 19341 public void invalidateDrawable(@NonNull Drawable drawable) { 19342 if (verifyDrawable(drawable)) { 19343 final Rect dirty = drawable.getDirtyBounds(); 19344 final int scrollX = mScrollX; 19345 final int scrollY = mScrollY; 19346 19347 invalidate(dirty.left + scrollX, dirty.top + scrollY, 19348 dirty.right + scrollX, dirty.bottom + scrollY); 19349 rebuildOutline(); 19350 } 19351 } 19352 19353 /** 19354 * Schedules an action on a drawable to occur at a specified time. 19355 * 19356 * @param who the recipient of the action 19357 * @param what the action to run on the drawable 19358 * @param when the time at which the action must occur. Uses the 19359 * {@link SystemClock#uptimeMillis} timebase. 19360 */ 19361 @Override 19362 public void scheduleDrawable(@NonNull Drawable who, @NonNull Runnable what, long when) { 19363 if (verifyDrawable(who) && what != null) { 19364 final long delay = when - SystemClock.uptimeMillis(); 19365 if (mAttachInfo != null) { 19366 mAttachInfo.mViewRootImpl.mChoreographer.postCallbackDelayed( 19367 Choreographer.CALLBACK_ANIMATION, what, who, 19368 Choreographer.subtractFrameDelay(delay)); 19369 } else { 19370 // Postpone the runnable until we know 19371 // on which thread it needs to run. 19372 getRunQueue().postDelayed(what, delay); 19373 } 19374 } 19375 } 19376 19377 /** 19378 * Cancels a scheduled action on a drawable. 19379 * 19380 * @param who the recipient of the action 19381 * @param what the action to cancel 19382 */ 19383 @Override 19384 public void unscheduleDrawable(@NonNull Drawable who, @NonNull Runnable what) { 19385 if (verifyDrawable(who) && what != null) { 19386 if (mAttachInfo != null) { 19387 mAttachInfo.mViewRootImpl.mChoreographer.removeCallbacks( 19388 Choreographer.CALLBACK_ANIMATION, what, who); 19389 } 19390 getRunQueue().removeCallbacks(what); 19391 } 19392 } 19393 19394 /** 19395 * Unschedule any events associated with the given Drawable. This can be 19396 * used when selecting a new Drawable into a view, so that the previous 19397 * one is completely unscheduled. 19398 * 19399 * @param who The Drawable to unschedule. 19400 * 19401 * @see #drawableStateChanged 19402 */ 19403 public void unscheduleDrawable(Drawable who) { 19404 if (mAttachInfo != null && who != null) { 19405 mAttachInfo.mViewRootImpl.mChoreographer.removeCallbacks( 19406 Choreographer.CALLBACK_ANIMATION, null, who); 19407 } 19408 } 19409 19410 /** 19411 * Resolve the Drawables depending on the layout direction. This is implicitly supposing 19412 * that the View directionality can and will be resolved before its Drawables. 19413 * 19414 * Will call {@link View#onResolveDrawables} when resolution is done. 19415 * 19416 * @hide 19417 */ 19418 protected void resolveDrawables() { 19419 // Drawables resolution may need to happen before resolving the layout direction (which is 19420 // done only during the measure() call). 19421 // If the layout direction is not resolved yet, we cannot resolve the Drawables except in 19422 // one case: when the raw layout direction has not been defined as LAYOUT_DIRECTION_INHERIT. 19423 // So, if the raw layout direction is LAYOUT_DIRECTION_LTR or LAYOUT_DIRECTION_RTL or 19424 // LAYOUT_DIRECTION_LOCALE, we can "cheat" and we don't need to wait for the layout 19425 // direction to be resolved as its resolved value will be the same as its raw value. 19426 if (!isLayoutDirectionResolved() && 19427 getRawLayoutDirection() == View.LAYOUT_DIRECTION_INHERIT) { 19428 return; 19429 } 19430 19431 final int layoutDirection = isLayoutDirectionResolved() ? 19432 getLayoutDirection() : getRawLayoutDirection(); 19433 19434 if (mBackground != null) { 19435 mBackground.setLayoutDirection(layoutDirection); 19436 } 19437 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null) { 19438 mForegroundInfo.mDrawable.setLayoutDirection(layoutDirection); 19439 } 19440 if (mDefaultFocusHighlight != null) { 19441 mDefaultFocusHighlight.setLayoutDirection(layoutDirection); 19442 } 19443 mPrivateFlags2 |= PFLAG2_DRAWABLE_RESOLVED; 19444 onResolveDrawables(layoutDirection); 19445 } 19446 19447 boolean areDrawablesResolved() { 19448 return (mPrivateFlags2 & PFLAG2_DRAWABLE_RESOLVED) == PFLAG2_DRAWABLE_RESOLVED; 19449 } 19450 19451 /** 19452 * Called when layout direction has been resolved. 19453 * 19454 * The default implementation does nothing. 19455 * 19456 * @param layoutDirection The resolved layout direction. 19457 * 19458 * @see #LAYOUT_DIRECTION_LTR 19459 * @see #LAYOUT_DIRECTION_RTL 19460 * 19461 * @hide 19462 */ 19463 public void onResolveDrawables(@ResolvedLayoutDir int layoutDirection) { 19464 } 19465 19466 /** 19467 * @hide 19468 */ 19469 protected void resetResolvedDrawables() { 19470 resetResolvedDrawablesInternal(); 19471 } 19472 19473 void resetResolvedDrawablesInternal() { 19474 mPrivateFlags2 &= ~PFLAG2_DRAWABLE_RESOLVED; 19475 } 19476 19477 /** 19478 * If your view subclass is displaying its own Drawable objects, it should 19479 * override this function and return true for any Drawable it is 19480 * displaying. This allows animations for those drawables to be 19481 * scheduled. 19482 * 19483 * <p>Be sure to call through to the super class when overriding this 19484 * function. 19485 * 19486 * @param who The Drawable to verify. Return true if it is one you are 19487 * displaying, else return the result of calling through to the 19488 * super class. 19489 * 19490 * @return boolean If true than the Drawable is being displayed in the 19491 * view; else false and it is not allowed to animate. 19492 * 19493 * @see #unscheduleDrawable(android.graphics.drawable.Drawable) 19494 * @see #drawableStateChanged() 19495 */ 19496 @CallSuper 19497 protected boolean verifyDrawable(@NonNull Drawable who) { 19498 // Avoid verifying the scroll bar drawable so that we don't end up in 19499 // an invalidation loop. This effectively prevents the scroll bar 19500 // drawable from triggering invalidations and scheduling runnables. 19501 return who == mBackground || (mForegroundInfo != null && mForegroundInfo.mDrawable == who) 19502 || (mDefaultFocusHighlight == who); 19503 } 19504 19505 /** 19506 * This function is called whenever the state of the view changes in such 19507 * a way that it impacts the state of drawables being shown. 19508 * <p> 19509 * If the View has a StateListAnimator, it will also be called to run necessary state 19510 * change animations. 19511 * <p> 19512 * Be sure to call through to the superclass when overriding this function. 19513 * 19514 * @see Drawable#setState(int[]) 19515 */ 19516 @CallSuper 19517 protected void drawableStateChanged() { 19518 final int[] state = getDrawableState(); 19519 boolean changed = false; 19520 19521 final Drawable bg = mBackground; 19522 if (bg != null && bg.isStateful()) { 19523 changed |= bg.setState(state); 19524 } 19525 19526 final Drawable hl = mDefaultFocusHighlight; 19527 if (hl != null && hl.isStateful()) { 19528 changed |= hl.setState(state); 19529 } 19530 19531 final Drawable fg = mForegroundInfo != null ? mForegroundInfo.mDrawable : null; 19532 if (fg != null && fg.isStateful()) { 19533 changed |= fg.setState(state); 19534 } 19535 19536 if (mScrollCache != null) { 19537 final Drawable scrollBar = mScrollCache.scrollBar; 19538 if (scrollBar != null && scrollBar.isStateful()) { 19539 changed |= scrollBar.setState(state) 19540 && mScrollCache.state != ScrollabilityCache.OFF; 19541 } 19542 } 19543 19544 if (mStateListAnimator != null) { 19545 mStateListAnimator.setState(state); 19546 } 19547 19548 if (changed) { 19549 invalidate(); 19550 } 19551 } 19552 19553 /** 19554 * This function is called whenever the view hotspot changes and needs to 19555 * be propagated to drawables or child views managed by the view. 19556 * <p> 19557 * Dispatching to child views is handled by 19558 * {@link #dispatchDrawableHotspotChanged(float, float)}. 19559 * <p> 19560 * Be sure to call through to the superclass when overriding this function. 19561 * 19562 * @param x hotspot x coordinate 19563 * @param y hotspot y coordinate 19564 */ 19565 @CallSuper 19566 public void drawableHotspotChanged(float x, float y) { 19567 if (mBackground != null) { 19568 mBackground.setHotspot(x, y); 19569 } 19570 if (mDefaultFocusHighlight != null) { 19571 mDefaultFocusHighlight.setHotspot(x, y); 19572 } 19573 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null) { 19574 mForegroundInfo.mDrawable.setHotspot(x, y); 19575 } 19576 19577 dispatchDrawableHotspotChanged(x, y); 19578 } 19579 19580 /** 19581 * Dispatches drawableHotspotChanged to all of this View's children. 19582 * 19583 * @param x hotspot x coordinate 19584 * @param y hotspot y coordinate 19585 * @see #drawableHotspotChanged(float, float) 19586 */ 19587 public void dispatchDrawableHotspotChanged(float x, float y) { 19588 } 19589 19590 /** 19591 * Call this to force a view to update its drawable state. This will cause 19592 * drawableStateChanged to be called on this view. Views that are interested 19593 * in the new state should call getDrawableState. 19594 * 19595 * @see #drawableStateChanged 19596 * @see #getDrawableState 19597 */ 19598 public void refreshDrawableState() { 19599 mPrivateFlags |= PFLAG_DRAWABLE_STATE_DIRTY; 19600 drawableStateChanged(); 19601 19602 ViewParent parent = mParent; 19603 if (parent != null) { 19604 parent.childDrawableStateChanged(this); 19605 } 19606 } 19607 19608 /** 19609 * Create a default focus highlight if it doesn't exist. 19610 * @return a default focus highlight. 19611 */ 19612 private Drawable getDefaultFocusHighlightDrawable() { 19613 if (mDefaultFocusHighlightCache == null) { 19614 if (mContext != null) { 19615 final int[] attrs = new int[] { android.R.attr.selectableItemBackground }; 19616 final TypedArray ta = mContext.obtainStyledAttributes(attrs); 19617 mDefaultFocusHighlightCache = ta.getDrawable(0); 19618 ta.recycle(); 19619 } 19620 } 19621 return mDefaultFocusHighlightCache; 19622 } 19623 19624 /** 19625 * Set the current default focus highlight. 19626 * @param highlight the highlight drawable, or {@code null} if it's no longer needed. 19627 */ 19628 private void setDefaultFocusHighlight(Drawable highlight) { 19629 mDefaultFocusHighlight = highlight; 19630 mDefaultFocusHighlightSizeChanged = true; 19631 if (highlight != null) { 19632 if ((mPrivateFlags & PFLAG_SKIP_DRAW) != 0) { 19633 mPrivateFlags &= ~PFLAG_SKIP_DRAW; 19634 } 19635 highlight.setLayoutDirection(getLayoutDirection()); 19636 if (highlight.isStateful()) { 19637 highlight.setState(getDrawableState()); 19638 } 19639 if (isAttachedToWindow()) { 19640 highlight.setVisible(getWindowVisibility() == VISIBLE && isShown(), false); 19641 } 19642 // Set callback last, since the view may still be initializing. 19643 highlight.setCallback(this); 19644 } else if ((mViewFlags & WILL_NOT_DRAW) != 0 && mBackground == null 19645 && (mForegroundInfo == null || mForegroundInfo.mDrawable == null)) { 19646 mPrivateFlags |= PFLAG_SKIP_DRAW; 19647 } 19648 requestLayout(); 19649 invalidate(); 19650 } 19651 19652 /** 19653 * Check whether we need to draw a default focus highlight when this view gets focused, 19654 * which requires: 19655 * <ul> 19656 * <li>In the background, {@link android.R.attr#state_focused} is not defined.</li> 19657 * <li>This view is not in touch mode.</li> 19658 * <li>This view doesn't opt out for a default focus highlight, via 19659 * {@link #setDefaultFocusHighlightEnabled(boolean)}.</li> 19660 * <li>This view is attached to window.</li> 19661 * </ul> 19662 * @return {@code true} if a default focus highlight is needed. 19663 */ 19664 private boolean isDefaultFocusHighlightNeeded(Drawable background) { 19665 final boolean hasFocusStateSpecified = background == null || !background.isStateful() 19666 || !background.hasFocusStateSpecified(); 19667 return !isInTouchMode() && getDefaultFocusHighlightEnabled() && hasFocusStateSpecified 19668 && isAttachedToWindow() && sUseDefaultFocusHighlight; 19669 } 19670 19671 /** 19672 * When this view is focused, switches on/off the default focused highlight. 19673 * <p> 19674 * This always happens when this view is focused, and only at this moment the default focus 19675 * highlight can be visible. 19676 */ 19677 private void switchDefaultFocusHighlight() { 19678 if (isFocused()) { 19679 final boolean needed = isDefaultFocusHighlightNeeded(mBackground); 19680 final boolean active = mDefaultFocusHighlight != null; 19681 if (needed && !active) { 19682 setDefaultFocusHighlight(getDefaultFocusHighlightDrawable()); 19683 } else if (!needed && active) { 19684 // The highlight is no longer needed, so tear it down. 19685 setDefaultFocusHighlight(null); 19686 } 19687 } 19688 } 19689 19690 /** 19691 * Draw the default focus highlight onto the canvas. 19692 * @param canvas the canvas where we're drawing the highlight. 19693 */ 19694 private void drawDefaultFocusHighlight(Canvas canvas) { 19695 if (mDefaultFocusHighlight != null) { 19696 if (mDefaultFocusHighlightSizeChanged) { 19697 mDefaultFocusHighlightSizeChanged = false; 19698 final int l = mScrollX; 19699 final int r = l + mRight - mLeft; 19700 final int t = mScrollY; 19701 final int b = t + mBottom - mTop; 19702 mDefaultFocusHighlight.setBounds(l, t, r, b); 19703 } 19704 mDefaultFocusHighlight.draw(canvas); 19705 } 19706 } 19707 19708 /** 19709 * Return an array of resource IDs of the drawable states representing the 19710 * current state of the view. 19711 * 19712 * @return The current drawable state 19713 * 19714 * @see Drawable#setState(int[]) 19715 * @see #drawableStateChanged() 19716 * @see #onCreateDrawableState(int) 19717 */ 19718 public final int[] getDrawableState() { 19719 if ((mDrawableState != null) && ((mPrivateFlags & PFLAG_DRAWABLE_STATE_DIRTY) == 0)) { 19720 return mDrawableState; 19721 } else { 19722 mDrawableState = onCreateDrawableState(0); 19723 mPrivateFlags &= ~PFLAG_DRAWABLE_STATE_DIRTY; 19724 return mDrawableState; 19725 } 19726 } 19727 19728 /** 19729 * Generate the new {@link android.graphics.drawable.Drawable} state for 19730 * this view. This is called by the view 19731 * system when the cached Drawable state is determined to be invalid. To 19732 * retrieve the current state, you should use {@link #getDrawableState}. 19733 * 19734 * @param extraSpace if non-zero, this is the number of extra entries you 19735 * would like in the returned array in which you can place your own 19736 * states. 19737 * 19738 * @return Returns an array holding the current {@link Drawable} state of 19739 * the view. 19740 * 19741 * @see #mergeDrawableStates(int[], int[]) 19742 */ 19743 protected int[] onCreateDrawableState(int extraSpace) { 19744 if ((mViewFlags & DUPLICATE_PARENT_STATE) == DUPLICATE_PARENT_STATE && 19745 mParent instanceof View) { 19746 return ((View) mParent).onCreateDrawableState(extraSpace); 19747 } 19748 19749 int[] drawableState; 19750 19751 int privateFlags = mPrivateFlags; 19752 19753 int viewStateIndex = 0; 19754 if ((privateFlags & PFLAG_PRESSED) != 0) viewStateIndex |= StateSet.VIEW_STATE_PRESSED; 19755 if ((mViewFlags & ENABLED_MASK) == ENABLED) viewStateIndex |= StateSet.VIEW_STATE_ENABLED; 19756 if (isFocused()) viewStateIndex |= StateSet.VIEW_STATE_FOCUSED; 19757 if ((privateFlags & PFLAG_SELECTED) != 0) viewStateIndex |= StateSet.VIEW_STATE_SELECTED; 19758 if (hasWindowFocus()) viewStateIndex |= StateSet.VIEW_STATE_WINDOW_FOCUSED; 19759 if ((privateFlags & PFLAG_ACTIVATED) != 0) viewStateIndex |= StateSet.VIEW_STATE_ACTIVATED; 19760 if (mAttachInfo != null && mAttachInfo.mHardwareAccelerationRequested && 19761 ThreadedRenderer.isAvailable()) { 19762 // This is set if HW acceleration is requested, even if the current 19763 // process doesn't allow it. This is just to allow app preview 19764 // windows to better match their app. 19765 viewStateIndex |= StateSet.VIEW_STATE_ACCELERATED; 19766 } 19767 if ((privateFlags & PFLAG_HOVERED) != 0) viewStateIndex |= StateSet.VIEW_STATE_HOVERED; 19768 19769 final int privateFlags2 = mPrivateFlags2; 19770 if ((privateFlags2 & PFLAG2_DRAG_CAN_ACCEPT) != 0) { 19771 viewStateIndex |= StateSet.VIEW_STATE_DRAG_CAN_ACCEPT; 19772 } 19773 if ((privateFlags2 & PFLAG2_DRAG_HOVERED) != 0) { 19774 viewStateIndex |= StateSet.VIEW_STATE_DRAG_HOVERED; 19775 } 19776 19777 drawableState = StateSet.get(viewStateIndex); 19778 19779 //noinspection ConstantIfStatement 19780 if (false) { 19781 Log.i("View", "drawableStateIndex=" + viewStateIndex); 19782 Log.i("View", toString() 19783 + " pressed=" + ((privateFlags & PFLAG_PRESSED) != 0) 19784 + " en=" + ((mViewFlags & ENABLED_MASK) == ENABLED) 19785 + " fo=" + hasFocus() 19786 + " sl=" + ((privateFlags & PFLAG_SELECTED) != 0) 19787 + " wf=" + hasWindowFocus() 19788 + ": " + Arrays.toString(drawableState)); 19789 } 19790 19791 if (extraSpace == 0) { 19792 return drawableState; 19793 } 19794 19795 final int[] fullState; 19796 if (drawableState != null) { 19797 fullState = new int[drawableState.length + extraSpace]; 19798 System.arraycopy(drawableState, 0, fullState, 0, drawableState.length); 19799 } else { 19800 fullState = new int[extraSpace]; 19801 } 19802 19803 return fullState; 19804 } 19805 19806 /** 19807 * Merge your own state values in <var>additionalState</var> into the base 19808 * state values <var>baseState</var> that were returned by 19809 * {@link #onCreateDrawableState(int)}. 19810 * 19811 * @param baseState The base state values returned by 19812 * {@link #onCreateDrawableState(int)}, which will be modified to also hold your 19813 * own additional state values. 19814 * 19815 * @param additionalState The additional state values you would like 19816 * added to <var>baseState</var>; this array is not modified. 19817 * 19818 * @return As a convenience, the <var>baseState</var> array you originally 19819 * passed into the function is returned. 19820 * 19821 * @see #onCreateDrawableState(int) 19822 */ 19823 protected static int[] mergeDrawableStates(int[] baseState, int[] additionalState) { 19824 final int N = baseState.length; 19825 int i = N - 1; 19826 while (i >= 0 && baseState[i] == 0) { 19827 i--; 19828 } 19829 System.arraycopy(additionalState, 0, baseState, i + 1, additionalState.length); 19830 return baseState; 19831 } 19832 19833 /** 19834 * Call {@link Drawable#jumpToCurrentState() Drawable.jumpToCurrentState()} 19835 * on all Drawable objects associated with this view. 19836 * <p> 19837 * Also calls {@link StateListAnimator#jumpToCurrentState()} if there is a StateListAnimator 19838 * attached to this view. 19839 */ 19840 @CallSuper 19841 public void jumpDrawablesToCurrentState() { 19842 if (mBackground != null) { 19843 mBackground.jumpToCurrentState(); 19844 } 19845 if (mStateListAnimator != null) { 19846 mStateListAnimator.jumpToCurrentState(); 19847 } 19848 if (mDefaultFocusHighlight != null) { 19849 mDefaultFocusHighlight.jumpToCurrentState(); 19850 } 19851 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null) { 19852 mForegroundInfo.mDrawable.jumpToCurrentState(); 19853 } 19854 } 19855 19856 /** 19857 * Sets the background color for this view. 19858 * @param color the color of the background 19859 */ 19860 @RemotableViewMethod 19861 public void setBackgroundColor(@ColorInt int color) { 19862 if (mBackground instanceof ColorDrawable) { 19863 ((ColorDrawable) mBackground.mutate()).setColor(color); 19864 computeOpaqueFlags(); 19865 mBackgroundResource = 0; 19866 } else { 19867 setBackground(new ColorDrawable(color)); 19868 } 19869 } 19870 19871 /** 19872 * Set the background to a given resource. The resource should refer to 19873 * a Drawable object or 0 to remove the background. 19874 * @param resid The identifier of the resource. 19875 * 19876 * @attr ref android.R.styleable#View_background 19877 */ 19878 @RemotableViewMethod 19879 public void setBackgroundResource(@DrawableRes int resid) { 19880 if (resid != 0 && resid == mBackgroundResource) { 19881 return; 19882 } 19883 19884 Drawable d = null; 19885 if (resid != 0) { 19886 d = mContext.getDrawable(resid); 19887 } 19888 setBackground(d); 19889 19890 mBackgroundResource = resid; 19891 } 19892 19893 /** 19894 * Set the background to a given Drawable, or remove the background. If the 19895 * background has padding, this View's padding is set to the background's 19896 * padding. However, when a background is removed, this View's padding isn't 19897 * touched. If setting the padding is desired, please use 19898 * {@link #setPadding(int, int, int, int)}. 19899 * 19900 * @param background The Drawable to use as the background, or null to remove the 19901 * background 19902 */ 19903 public void setBackground(Drawable background) { 19904 //noinspection deprecation 19905 setBackgroundDrawable(background); 19906 } 19907 19908 /** 19909 * @deprecated use {@link #setBackground(Drawable)} instead 19910 */ 19911 @Deprecated 19912 public void setBackgroundDrawable(Drawable background) { 19913 computeOpaqueFlags(); 19914 19915 if (background == mBackground) { 19916 return; 19917 } 19918 19919 boolean requestLayout = false; 19920 19921 mBackgroundResource = 0; 19922 19923 /* 19924 * Regardless of whether we're setting a new background or not, we want 19925 * to clear the previous drawable. setVisible first while we still have the callback set. 19926 */ 19927 if (mBackground != null) { 19928 if (isAttachedToWindow()) { 19929 mBackground.setVisible(false, false); 19930 } 19931 mBackground.setCallback(null); 19932 unscheduleDrawable(mBackground); 19933 } 19934 19935 if (background != null) { 19936 Rect padding = sThreadLocal.get(); 19937 if (padding == null) { 19938 padding = new Rect(); 19939 sThreadLocal.set(padding); 19940 } 19941 resetResolvedDrawablesInternal(); 19942 background.setLayoutDirection(getLayoutDirection()); 19943 if (background.getPadding(padding)) { 19944 resetResolvedPaddingInternal(); 19945 switch (background.getLayoutDirection()) { 19946 case LAYOUT_DIRECTION_RTL: 19947 mUserPaddingLeftInitial = padding.right; 19948 mUserPaddingRightInitial = padding.left; 19949 internalSetPadding(padding.right, padding.top, padding.left, padding.bottom); 19950 break; 19951 case LAYOUT_DIRECTION_LTR: 19952 default: 19953 mUserPaddingLeftInitial = padding.left; 19954 mUserPaddingRightInitial = padding.right; 19955 internalSetPadding(padding.left, padding.top, padding.right, padding.bottom); 19956 } 19957 mLeftPaddingDefined = false; 19958 mRightPaddingDefined = false; 19959 } 19960 19961 // Compare the minimum sizes of the old Drawable and the new. If there isn't an old or 19962 // if it has a different minimum size, we should layout again 19963 if (mBackground == null 19964 || mBackground.getMinimumHeight() != background.getMinimumHeight() 19965 || mBackground.getMinimumWidth() != background.getMinimumWidth()) { 19966 requestLayout = true; 19967 } 19968 19969 // Set mBackground before we set this as the callback and start making other 19970 // background drawable state change calls. In particular, the setVisible call below 19971 // can result in drawables attempting to start animations or otherwise invalidate, 19972 // which requires the view set as the callback (us) to recognize the drawable as 19973 // belonging to it as per verifyDrawable. 19974 mBackground = background; 19975 if (background.isStateful()) { 19976 background.setState(getDrawableState()); 19977 } 19978 if (isAttachedToWindow()) { 19979 background.setVisible(getWindowVisibility() == VISIBLE && isShown(), false); 19980 } 19981 19982 applyBackgroundTint(); 19983 19984 // Set callback last, since the view may still be initializing. 19985 background.setCallback(this); 19986 19987 if ((mPrivateFlags & PFLAG_SKIP_DRAW) != 0) { 19988 mPrivateFlags &= ~PFLAG_SKIP_DRAW; 19989 requestLayout = true; 19990 } 19991 } else { 19992 /* Remove the background */ 19993 mBackground = null; 19994 if ((mViewFlags & WILL_NOT_DRAW) != 0 19995 && (mDefaultFocusHighlight == null) 19996 && (mForegroundInfo == null || mForegroundInfo.mDrawable == null)) { 19997 mPrivateFlags |= PFLAG_SKIP_DRAW; 19998 } 19999 20000 /* 20001 * When the background is set, we try to apply its padding to this 20002 * View. When the background is removed, we don't touch this View's 20003 * padding. This is noted in the Javadocs. Hence, we don't need to 20004 * requestLayout(), the invalidate() below is sufficient. 20005 */ 20006 20007 // The old background's minimum size could have affected this 20008 // View's layout, so let's requestLayout 20009 requestLayout = true; 20010 } 20011 20012 computeOpaqueFlags(); 20013 20014 if (requestLayout) { 20015 requestLayout(); 20016 } 20017 20018 mBackgroundSizeChanged = true; 20019 invalidate(true); 20020 invalidateOutline(); 20021 } 20022 20023 /** 20024 * Gets the background drawable 20025 * 20026 * @return The drawable used as the background for this view, if any. 20027 * 20028 * @see #setBackground(Drawable) 20029 * 20030 * @attr ref android.R.styleable#View_background 20031 */ 20032 public Drawable getBackground() { 20033 return mBackground; 20034 } 20035 20036 /** 20037 * Applies a tint to the background drawable. Does not modify the current tint 20038 * mode, which is {@link PorterDuff.Mode#SRC_IN} by default. 20039 * <p> 20040 * Subsequent calls to {@link #setBackground(Drawable)} will automatically 20041 * mutate the drawable and apply the specified tint and tint mode using 20042 * {@link Drawable#setTintList(ColorStateList)}. 20043 * 20044 * @param tint the tint to apply, may be {@code null} to clear tint 20045 * 20046 * @attr ref android.R.styleable#View_backgroundTint 20047 * @see #getBackgroundTintList() 20048 * @see Drawable#setTintList(ColorStateList) 20049 */ 20050 public void setBackgroundTintList(@Nullable ColorStateList tint) { 20051 if (mBackgroundTint == null) { 20052 mBackgroundTint = new TintInfo(); 20053 } 20054 mBackgroundTint.mTintList = tint; 20055 mBackgroundTint.mHasTintList = true; 20056 20057 applyBackgroundTint(); 20058 } 20059 20060 /** 20061 * Return the tint applied to the background drawable, if specified. 20062 * 20063 * @return the tint applied to the background drawable 20064 * @attr ref android.R.styleable#View_backgroundTint 20065 * @see #setBackgroundTintList(ColorStateList) 20066 */ 20067 @Nullable 20068 public ColorStateList getBackgroundTintList() { 20069 return mBackgroundTint != null ? mBackgroundTint.mTintList : null; 20070 } 20071 20072 /** 20073 * Specifies the blending mode used to apply the tint specified by 20074 * {@link #setBackgroundTintList(ColorStateList)}} to the background 20075 * drawable. The default mode is {@link PorterDuff.Mode#SRC_IN}. 20076 * 20077 * @param tintMode the blending mode used to apply the tint, may be 20078 * {@code null} to clear tint 20079 * @attr ref android.R.styleable#View_backgroundTintMode 20080 * @see #getBackgroundTintMode() 20081 * @see Drawable#setTintMode(PorterDuff.Mode) 20082 */ 20083 public void setBackgroundTintMode(@Nullable PorterDuff.Mode tintMode) { 20084 if (mBackgroundTint == null) { 20085 mBackgroundTint = new TintInfo(); 20086 } 20087 mBackgroundTint.mTintMode = tintMode; 20088 mBackgroundTint.mHasTintMode = true; 20089 20090 applyBackgroundTint(); 20091 } 20092 20093 /** 20094 * Return the blending mode used to apply the tint to the background 20095 * drawable, if specified. 20096 * 20097 * @return the blending mode used to apply the tint to the background 20098 * drawable 20099 * @attr ref android.R.styleable#View_backgroundTintMode 20100 * @see #setBackgroundTintMode(PorterDuff.Mode) 20101 */ 20102 @Nullable 20103 public PorterDuff.Mode getBackgroundTintMode() { 20104 return mBackgroundTint != null ? mBackgroundTint.mTintMode : null; 20105 } 20106 20107 private void applyBackgroundTint() { 20108 if (mBackground != null && mBackgroundTint != null) { 20109 final TintInfo tintInfo = mBackgroundTint; 20110 if (tintInfo.mHasTintList || tintInfo.mHasTintMode) { 20111 mBackground = mBackground.mutate(); 20112 20113 if (tintInfo.mHasTintList) { 20114 mBackground.setTintList(tintInfo.mTintList); 20115 } 20116 20117 if (tintInfo.mHasTintMode) { 20118 mBackground.setTintMode(tintInfo.mTintMode); 20119 } 20120 20121 // The drawable (or one of its children) may not have been 20122 // stateful before applying the tint, so let's try again. 20123 if (mBackground.isStateful()) { 20124 mBackground.setState(getDrawableState()); 20125 } 20126 } 20127 } 20128 } 20129 20130 /** 20131 * Returns the drawable used as the foreground of this View. The 20132 * foreground drawable, if non-null, is always drawn on top of the view's content. 20133 * 20134 * @return a Drawable or null if no foreground was set 20135 * 20136 * @see #onDrawForeground(Canvas) 20137 */ 20138 public Drawable getForeground() { 20139 return mForegroundInfo != null ? mForegroundInfo.mDrawable : null; 20140 } 20141 20142 /** 20143 * Supply a Drawable that is to be rendered on top of all of the content in the view. 20144 * 20145 * @param foreground the Drawable to be drawn on top of the children 20146 * 20147 * @attr ref android.R.styleable#View_foreground 20148 */ 20149 public void setForeground(Drawable foreground) { 20150 if (mForegroundInfo == null) { 20151 if (foreground == null) { 20152 // Nothing to do. 20153 return; 20154 } 20155 mForegroundInfo = new ForegroundInfo(); 20156 } 20157 20158 if (foreground == mForegroundInfo.mDrawable) { 20159 // Nothing to do 20160 return; 20161 } 20162 20163 if (mForegroundInfo.mDrawable != null) { 20164 if (isAttachedToWindow()) { 20165 mForegroundInfo.mDrawable.setVisible(false, false); 20166 } 20167 mForegroundInfo.mDrawable.setCallback(null); 20168 unscheduleDrawable(mForegroundInfo.mDrawable); 20169 } 20170 20171 mForegroundInfo.mDrawable = foreground; 20172 mForegroundInfo.mBoundsChanged = true; 20173 if (foreground != null) { 20174 if ((mPrivateFlags & PFLAG_SKIP_DRAW) != 0) { 20175 mPrivateFlags &= ~PFLAG_SKIP_DRAW; 20176 } 20177 foreground.setLayoutDirection(getLayoutDirection()); 20178 if (foreground.isStateful()) { 20179 foreground.setState(getDrawableState()); 20180 } 20181 applyForegroundTint(); 20182 if (isAttachedToWindow()) { 20183 foreground.setVisible(getWindowVisibility() == VISIBLE && isShown(), false); 20184 } 20185 // Set callback last, since the view may still be initializing. 20186 foreground.setCallback(this); 20187 } else if ((mViewFlags & WILL_NOT_DRAW) != 0 && mBackground == null 20188 && (mDefaultFocusHighlight == null)) { 20189 mPrivateFlags |= PFLAG_SKIP_DRAW; 20190 } 20191 requestLayout(); 20192 invalidate(); 20193 } 20194 20195 /** 20196 * Magic bit used to support features of framework-internal window decor implementation details. 20197 * This used to live exclusively in FrameLayout. 20198 * 20199 * @return true if the foreground should draw inside the padding region or false 20200 * if it should draw inset by the view's padding 20201 * @hide internal use only; only used by FrameLayout and internal screen layouts. 20202 */ 20203 public boolean isForegroundInsidePadding() { 20204 return mForegroundInfo != null ? mForegroundInfo.mInsidePadding : true; 20205 } 20206 20207 /** 20208 * Describes how the foreground is positioned. 20209 * 20210 * @return foreground gravity. 20211 * 20212 * @see #setForegroundGravity(int) 20213 * 20214 * @attr ref android.R.styleable#View_foregroundGravity 20215 */ 20216 public int getForegroundGravity() { 20217 return mForegroundInfo != null ? mForegroundInfo.mGravity 20218 : Gravity.START | Gravity.TOP; 20219 } 20220 20221 /** 20222 * Describes how the foreground is positioned. Defaults to START and TOP. 20223 * 20224 * @param gravity see {@link android.view.Gravity} 20225 * 20226 * @see #getForegroundGravity() 20227 * 20228 * @attr ref android.R.styleable#View_foregroundGravity 20229 */ 20230 public void setForegroundGravity(int gravity) { 20231 if (mForegroundInfo == null) { 20232 mForegroundInfo = new ForegroundInfo(); 20233 } 20234 20235 if (mForegroundInfo.mGravity != gravity) { 20236 if ((gravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK) == 0) { 20237 gravity |= Gravity.START; 20238 } 20239 20240 if ((gravity & Gravity.VERTICAL_GRAVITY_MASK) == 0) { 20241 gravity |= Gravity.TOP; 20242 } 20243 20244 mForegroundInfo.mGravity = gravity; 20245 requestLayout(); 20246 } 20247 } 20248 20249 /** 20250 * Applies a tint to the foreground drawable. Does not modify the current tint 20251 * mode, which is {@link PorterDuff.Mode#SRC_IN} by default. 20252 * <p> 20253 * Subsequent calls to {@link #setForeground(Drawable)} will automatically 20254 * mutate the drawable and apply the specified tint and tint mode using 20255 * {@link Drawable#setTintList(ColorStateList)}. 20256 * 20257 * @param tint the tint to apply, may be {@code null} to clear tint 20258 * 20259 * @attr ref android.R.styleable#View_foregroundTint 20260 * @see #getForegroundTintList() 20261 * @see Drawable#setTintList(ColorStateList) 20262 */ 20263 public void setForegroundTintList(@Nullable ColorStateList tint) { 20264 if (mForegroundInfo == null) { 20265 mForegroundInfo = new ForegroundInfo(); 20266 } 20267 if (mForegroundInfo.mTintInfo == null) { 20268 mForegroundInfo.mTintInfo = new TintInfo(); 20269 } 20270 mForegroundInfo.mTintInfo.mTintList = tint; 20271 mForegroundInfo.mTintInfo.mHasTintList = true; 20272 20273 applyForegroundTint(); 20274 } 20275 20276 /** 20277 * Return the tint applied to the foreground drawable, if specified. 20278 * 20279 * @return the tint applied to the foreground drawable 20280 * @attr ref android.R.styleable#View_foregroundTint 20281 * @see #setForegroundTintList(ColorStateList) 20282 */ 20283 @Nullable 20284 public ColorStateList getForegroundTintList() { 20285 return mForegroundInfo != null && mForegroundInfo.mTintInfo != null 20286 ? mForegroundInfo.mTintInfo.mTintList : null; 20287 } 20288 20289 /** 20290 * Specifies the blending mode used to apply the tint specified by 20291 * {@link #setForegroundTintList(ColorStateList)}} to the background 20292 * drawable. The default mode is {@link PorterDuff.Mode#SRC_IN}. 20293 * 20294 * @param tintMode the blending mode used to apply the tint, may be 20295 * {@code null} to clear tint 20296 * @attr ref android.R.styleable#View_foregroundTintMode 20297 * @see #getForegroundTintMode() 20298 * @see Drawable#setTintMode(PorterDuff.Mode) 20299 */ 20300 public void setForegroundTintMode(@Nullable PorterDuff.Mode tintMode) { 20301 if (mForegroundInfo == null) { 20302 mForegroundInfo = new ForegroundInfo(); 20303 } 20304 if (mForegroundInfo.mTintInfo == null) { 20305 mForegroundInfo.mTintInfo = new TintInfo(); 20306 } 20307 mForegroundInfo.mTintInfo.mTintMode = tintMode; 20308 mForegroundInfo.mTintInfo.mHasTintMode = true; 20309 20310 applyForegroundTint(); 20311 } 20312 20313 /** 20314 * Return the blending mode used to apply the tint to the foreground 20315 * drawable, if specified. 20316 * 20317 * @return the blending mode used to apply the tint to the foreground 20318 * drawable 20319 * @attr ref android.R.styleable#View_foregroundTintMode 20320 * @see #setForegroundTintMode(PorterDuff.Mode) 20321 */ 20322 @Nullable 20323 public PorterDuff.Mode getForegroundTintMode() { 20324 return mForegroundInfo != null && mForegroundInfo.mTintInfo != null 20325 ? mForegroundInfo.mTintInfo.mTintMode : null; 20326 } 20327 20328 private void applyForegroundTint() { 20329 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null 20330 && mForegroundInfo.mTintInfo != null) { 20331 final TintInfo tintInfo = mForegroundInfo.mTintInfo; 20332 if (tintInfo.mHasTintList || tintInfo.mHasTintMode) { 20333 mForegroundInfo.mDrawable = mForegroundInfo.mDrawable.mutate(); 20334 20335 if (tintInfo.mHasTintList) { 20336 mForegroundInfo.mDrawable.setTintList(tintInfo.mTintList); 20337 } 20338 20339 if (tintInfo.mHasTintMode) { 20340 mForegroundInfo.mDrawable.setTintMode(tintInfo.mTintMode); 20341 } 20342 20343 // The drawable (or one of its children) may not have been 20344 // stateful before applying the tint, so let's try again. 20345 if (mForegroundInfo.mDrawable.isStateful()) { 20346 mForegroundInfo.mDrawable.setState(getDrawableState()); 20347 } 20348 } 20349 } 20350 } 20351 20352 /** 20353 * Get the drawable to be overlayed when a view is autofilled 20354 * 20355 * @return The drawable 20356 * 20357 * @throws IllegalStateException if the drawable could not be found. 20358 */ 20359 @NonNull private Drawable getAutofilledDrawable() { 20360 // Lazily load the isAutofilled drawable. 20361 if (mAttachInfo.mAutofilledDrawable == null) { 20362 mAttachInfo.mAutofilledDrawable = mContext.getDrawable(R.drawable.autofilled_highlight); 20363 20364 if (mAttachInfo.mAutofilledDrawable == null) { 20365 throw new IllegalStateException( 20366 "Could not find android:drawable/autofilled_highlight"); 20367 } 20368 } 20369 20370 return mAttachInfo.mAutofilledDrawable; 20371 } 20372 20373 /** 20374 * Draw {@link View#isAutofilled()} highlight over view if the view is autofilled. 20375 * 20376 * @param canvas The canvas to draw on 20377 */ 20378 private void drawAutofilledHighlight(@NonNull Canvas canvas) { 20379 if (isAutofilled()) { 20380 Drawable autofilledHighlight = getAutofilledDrawable(); 20381 20382 autofilledHighlight.setBounds(0, 0, getWidth(), getHeight()); 20383 autofilledHighlight.draw(canvas); 20384 } 20385 } 20386 20387 /** 20388 * Draw any foreground content for this view. 20389 * 20390 * <p>Foreground content may consist of scroll bars, a {@link #setForeground foreground} 20391 * drawable or other view-specific decorations. The foreground is drawn on top of the 20392 * primary view content.</p> 20393 * 20394 * @param canvas canvas to draw into 20395 */ 20396 public void onDrawForeground(Canvas canvas) { 20397 onDrawScrollIndicators(canvas); 20398 onDrawScrollBars(canvas); 20399 20400 final Drawable foreground = mForegroundInfo != null ? mForegroundInfo.mDrawable : null; 20401 if (foreground != null) { 20402 if (mForegroundInfo.mBoundsChanged) { 20403 mForegroundInfo.mBoundsChanged = false; 20404 final Rect selfBounds = mForegroundInfo.mSelfBounds; 20405 final Rect overlayBounds = mForegroundInfo.mOverlayBounds; 20406 20407 if (mForegroundInfo.mInsidePadding) { 20408 selfBounds.set(0, 0, getWidth(), getHeight()); 20409 } else { 20410 selfBounds.set(getPaddingLeft(), getPaddingTop(), 20411 getWidth() - getPaddingRight(), getHeight() - getPaddingBottom()); 20412 } 20413 20414 final int ld = getLayoutDirection(); 20415 Gravity.apply(mForegroundInfo.mGravity, foreground.getIntrinsicWidth(), 20416 foreground.getIntrinsicHeight(), selfBounds, overlayBounds, ld); 20417 foreground.setBounds(overlayBounds); 20418 } 20419 20420 foreground.draw(canvas); 20421 } 20422 } 20423 20424 /** 20425 * Sets the padding. The view may add on the space required to display 20426 * the scrollbars, depending on the style and visibility of the scrollbars. 20427 * So the values returned from {@link #getPaddingLeft}, {@link #getPaddingTop}, 20428 * {@link #getPaddingRight} and {@link #getPaddingBottom} may be different 20429 * from the values set in this call. 20430 * 20431 * @attr ref android.R.styleable#View_padding 20432 * @attr ref android.R.styleable#View_paddingBottom 20433 * @attr ref android.R.styleable#View_paddingLeft 20434 * @attr ref android.R.styleable#View_paddingRight 20435 * @attr ref android.R.styleable#View_paddingTop 20436 * @param left the left padding in pixels 20437 * @param top the top padding in pixels 20438 * @param right the right padding in pixels 20439 * @param bottom the bottom padding in pixels 20440 */ 20441 public void setPadding(int left, int top, int right, int bottom) { 20442 resetResolvedPaddingInternal(); 20443 20444 mUserPaddingStart = UNDEFINED_PADDING; 20445 mUserPaddingEnd = UNDEFINED_PADDING; 20446 20447 mUserPaddingLeftInitial = left; 20448 mUserPaddingRightInitial = right; 20449 20450 mLeftPaddingDefined = true; 20451 mRightPaddingDefined = true; 20452 20453 internalSetPadding(left, top, right, bottom); 20454 } 20455 20456 /** 20457 * @hide 20458 */ 20459 protected void internalSetPadding(int left, int top, int right, int bottom) { 20460 mUserPaddingLeft = left; 20461 mUserPaddingRight = right; 20462 mUserPaddingBottom = bottom; 20463 20464 final int viewFlags = mViewFlags; 20465 boolean changed = false; 20466 20467 // Common case is there are no scroll bars. 20468 if ((viewFlags & (SCROLLBARS_VERTICAL|SCROLLBARS_HORIZONTAL)) != 0) { 20469 if ((viewFlags & SCROLLBARS_VERTICAL) != 0) { 20470 final int offset = (viewFlags & SCROLLBARS_INSET_MASK) == 0 20471 ? 0 : getVerticalScrollbarWidth(); 20472 switch (mVerticalScrollbarPosition) { 20473 case SCROLLBAR_POSITION_DEFAULT: 20474 if (isLayoutRtl()) { 20475 left += offset; 20476 } else { 20477 right += offset; 20478 } 20479 break; 20480 case SCROLLBAR_POSITION_RIGHT: 20481 right += offset; 20482 break; 20483 case SCROLLBAR_POSITION_LEFT: 20484 left += offset; 20485 break; 20486 } 20487 } 20488 if ((viewFlags & SCROLLBARS_HORIZONTAL) != 0) { 20489 bottom += (viewFlags & SCROLLBARS_INSET_MASK) == 0 20490 ? 0 : getHorizontalScrollbarHeight(); 20491 } 20492 } 20493 20494 if (mPaddingLeft != left) { 20495 changed = true; 20496 mPaddingLeft = left; 20497 } 20498 if (mPaddingTop != top) { 20499 changed = true; 20500 mPaddingTop = top; 20501 } 20502 if (mPaddingRight != right) { 20503 changed = true; 20504 mPaddingRight = right; 20505 } 20506 if (mPaddingBottom != bottom) { 20507 changed = true; 20508 mPaddingBottom = bottom; 20509 } 20510 20511 if (changed) { 20512 requestLayout(); 20513 invalidateOutline(); 20514 } 20515 } 20516 20517 /** 20518 * Sets the relative padding. The view may add on the space required to display 20519 * the scrollbars, depending on the style and visibility of the scrollbars. 20520 * So the values returned from {@link #getPaddingStart}, {@link #getPaddingTop}, 20521 * {@link #getPaddingEnd} and {@link #getPaddingBottom} may be different 20522 * from the values set in this call. 20523 * 20524 * @attr ref android.R.styleable#View_padding 20525 * @attr ref android.R.styleable#View_paddingBottom 20526 * @attr ref android.R.styleable#View_paddingStart 20527 * @attr ref android.R.styleable#View_paddingEnd 20528 * @attr ref android.R.styleable#View_paddingTop 20529 * @param start the start padding in pixels 20530 * @param top the top padding in pixels 20531 * @param end the end padding in pixels 20532 * @param bottom the bottom padding in pixels 20533 */ 20534 public void setPaddingRelative(int start, int top, int end, int bottom) { 20535 resetResolvedPaddingInternal(); 20536 20537 mUserPaddingStart = start; 20538 mUserPaddingEnd = end; 20539 mLeftPaddingDefined = true; 20540 mRightPaddingDefined = true; 20541 20542 switch(getLayoutDirection()) { 20543 case LAYOUT_DIRECTION_RTL: 20544 mUserPaddingLeftInitial = end; 20545 mUserPaddingRightInitial = start; 20546 internalSetPadding(end, top, start, bottom); 20547 break; 20548 case LAYOUT_DIRECTION_LTR: 20549 default: 20550 mUserPaddingLeftInitial = start; 20551 mUserPaddingRightInitial = end; 20552 internalSetPadding(start, top, end, bottom); 20553 } 20554 } 20555 20556 /** 20557 * Returns the top padding of this view. 20558 * 20559 * @return the top padding in pixels 20560 */ 20561 public int getPaddingTop() { 20562 return mPaddingTop; 20563 } 20564 20565 /** 20566 * Returns the bottom padding of this view. If there are inset and enabled 20567 * scrollbars, this value may include the space required to display the 20568 * scrollbars as well. 20569 * 20570 * @return the bottom padding in pixels 20571 */ 20572 public int getPaddingBottom() { 20573 return mPaddingBottom; 20574 } 20575 20576 /** 20577 * Returns the left padding of this view. If there are inset and enabled 20578 * scrollbars, this value may include the space required to display the 20579 * scrollbars as well. 20580 * 20581 * @return the left padding in pixels 20582 */ 20583 public int getPaddingLeft() { 20584 if (!isPaddingResolved()) { 20585 resolvePadding(); 20586 } 20587 return mPaddingLeft; 20588 } 20589 20590 /** 20591 * Returns the start padding of this view depending on its resolved layout direction. 20592 * If there are inset and enabled scrollbars, this value may include the space 20593 * required to display the scrollbars as well. 20594 * 20595 * @return the start padding in pixels 20596 */ 20597 public int getPaddingStart() { 20598 if (!isPaddingResolved()) { 20599 resolvePadding(); 20600 } 20601 return (getLayoutDirection() == LAYOUT_DIRECTION_RTL) ? 20602 mPaddingRight : mPaddingLeft; 20603 } 20604 20605 /** 20606 * Returns the right padding of this view. If there are inset and enabled 20607 * scrollbars, this value may include the space required to display the 20608 * scrollbars as well. 20609 * 20610 * @return the right padding in pixels 20611 */ 20612 public int getPaddingRight() { 20613 if (!isPaddingResolved()) { 20614 resolvePadding(); 20615 } 20616 return mPaddingRight; 20617 } 20618 20619 /** 20620 * Returns the end padding of this view depending on its resolved layout direction. 20621 * If there are inset and enabled scrollbars, this value may include the space 20622 * required to display the scrollbars as well. 20623 * 20624 * @return the end padding in pixels 20625 */ 20626 public int getPaddingEnd() { 20627 if (!isPaddingResolved()) { 20628 resolvePadding(); 20629 } 20630 return (getLayoutDirection() == LAYOUT_DIRECTION_RTL) ? 20631 mPaddingLeft : mPaddingRight; 20632 } 20633 20634 /** 20635 * Return if the padding has been set through relative values 20636 * {@link #setPaddingRelative(int, int, int, int)} or through 20637 * @attr ref android.R.styleable#View_paddingStart or 20638 * @attr ref android.R.styleable#View_paddingEnd 20639 * 20640 * @return true if the padding is relative or false if it is not. 20641 */ 20642 public boolean isPaddingRelative() { 20643 return (mUserPaddingStart != UNDEFINED_PADDING || mUserPaddingEnd != UNDEFINED_PADDING); 20644 } 20645 20646 Insets computeOpticalInsets() { 20647 return (mBackground == null) ? Insets.NONE : mBackground.getOpticalInsets(); 20648 } 20649 20650 /** 20651 * @hide 20652 */ 20653 public void resetPaddingToInitialValues() { 20654 if (isRtlCompatibilityMode()) { 20655 mPaddingLeft = mUserPaddingLeftInitial; 20656 mPaddingRight = mUserPaddingRightInitial; 20657 return; 20658 } 20659 if (isLayoutRtl()) { 20660 mPaddingLeft = (mUserPaddingEnd >= 0) ? mUserPaddingEnd : mUserPaddingLeftInitial; 20661 mPaddingRight = (mUserPaddingStart >= 0) ? mUserPaddingStart : mUserPaddingRightInitial; 20662 } else { 20663 mPaddingLeft = (mUserPaddingStart >= 0) ? mUserPaddingStart : mUserPaddingLeftInitial; 20664 mPaddingRight = (mUserPaddingEnd >= 0) ? mUserPaddingEnd : mUserPaddingRightInitial; 20665 } 20666 } 20667 20668 /** 20669 * @hide 20670 */ 20671 public Insets getOpticalInsets() { 20672 if (mLayoutInsets == null) { 20673 mLayoutInsets = computeOpticalInsets(); 20674 } 20675 return mLayoutInsets; 20676 } 20677 20678 /** 20679 * Set this view's optical insets. 20680 * 20681 * <p>This method should be treated similarly to setMeasuredDimension and not as a general 20682 * property. Views that compute their own optical insets should call it as part of measurement. 20683 * This method does not request layout. If you are setting optical insets outside of 20684 * measure/layout itself you will want to call requestLayout() yourself. 20685 * </p> 20686 * @hide 20687 */ 20688 public void setOpticalInsets(Insets insets) { 20689 mLayoutInsets = insets; 20690 } 20691 20692 /** 20693 * Changes the selection state of this view. A view can be selected or not. 20694 * Note that selection is not the same as focus. Views are typically 20695 * selected in the context of an AdapterView like ListView or GridView; 20696 * the selected view is the view that is highlighted. 20697 * 20698 * @param selected true if the view must be selected, false otherwise 20699 */ 20700 public void setSelected(boolean selected) { 20701 //noinspection DoubleNegation 20702 if (((mPrivateFlags & PFLAG_SELECTED) != 0) != selected) { 20703 mPrivateFlags = (mPrivateFlags & ~PFLAG_SELECTED) | (selected ? PFLAG_SELECTED : 0); 20704 if (!selected) resetPressedState(); 20705 invalidate(true); 20706 refreshDrawableState(); 20707 dispatchSetSelected(selected); 20708 if (selected) { 20709 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED); 20710 } else { 20711 notifyViewAccessibilityStateChangedIfNeeded( 20712 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 20713 } 20714 } 20715 } 20716 20717 /** 20718 * Dispatch setSelected to all of this View's children. 20719 * 20720 * @see #setSelected(boolean) 20721 * 20722 * @param selected The new selected state 20723 */ 20724 protected void dispatchSetSelected(boolean selected) { 20725 } 20726 20727 /** 20728 * Indicates the selection state of this view. 20729 * 20730 * @return true if the view is selected, false otherwise 20731 */ 20732 @ViewDebug.ExportedProperty 20733 public boolean isSelected() { 20734 return (mPrivateFlags & PFLAG_SELECTED) != 0; 20735 } 20736 20737 /** 20738 * Changes the activated state of this view. A view can be activated or not. 20739 * Note that activation is not the same as selection. Selection is 20740 * a transient property, representing the view (hierarchy) the user is 20741 * currently interacting with. Activation is a longer-term state that the 20742 * user can move views in and out of. For example, in a list view with 20743 * single or multiple selection enabled, the views in the current selection 20744 * set are activated. (Um, yeah, we are deeply sorry about the terminology 20745 * here.) The activated state is propagated down to children of the view it 20746 * is set on. 20747 * 20748 * @param activated true if the view must be activated, false otherwise 20749 */ 20750 public void setActivated(boolean activated) { 20751 //noinspection DoubleNegation 20752 if (((mPrivateFlags & PFLAG_ACTIVATED) != 0) != activated) { 20753 mPrivateFlags = (mPrivateFlags & ~PFLAG_ACTIVATED) | (activated ? PFLAG_ACTIVATED : 0); 20754 invalidate(true); 20755 refreshDrawableState(); 20756 dispatchSetActivated(activated); 20757 } 20758 } 20759 20760 /** 20761 * Dispatch setActivated to all of this View's children. 20762 * 20763 * @see #setActivated(boolean) 20764 * 20765 * @param activated The new activated state 20766 */ 20767 protected void dispatchSetActivated(boolean activated) { 20768 } 20769 20770 /** 20771 * Indicates the activation state of this view. 20772 * 20773 * @return true if the view is activated, false otherwise 20774 */ 20775 @ViewDebug.ExportedProperty 20776 public boolean isActivated() { 20777 return (mPrivateFlags & PFLAG_ACTIVATED) != 0; 20778 } 20779 20780 /** 20781 * Returns the ViewTreeObserver for this view's hierarchy. The view tree 20782 * observer can be used to get notifications when global events, like 20783 * layout, happen. 20784 * 20785 * The returned ViewTreeObserver observer is not guaranteed to remain 20786 * valid for the lifetime of this View. If the caller of this method keeps 20787 * a long-lived reference to ViewTreeObserver, it should always check for 20788 * the return value of {@link ViewTreeObserver#isAlive()}. 20789 * 20790 * @return The ViewTreeObserver for this view's hierarchy. 20791 */ 20792 public ViewTreeObserver getViewTreeObserver() { 20793 if (mAttachInfo != null) { 20794 return mAttachInfo.mTreeObserver; 20795 } 20796 if (mFloatingTreeObserver == null) { 20797 mFloatingTreeObserver = new ViewTreeObserver(mContext); 20798 } 20799 return mFloatingTreeObserver; 20800 } 20801 20802 /** 20803 * <p>Finds the topmost view in the current view hierarchy.</p> 20804 * 20805 * @return the topmost view containing this view 20806 */ 20807 public View getRootView() { 20808 if (mAttachInfo != null) { 20809 final View v = mAttachInfo.mRootView; 20810 if (v != null) { 20811 return v; 20812 } 20813 } 20814 20815 View parent = this; 20816 20817 while (parent.mParent != null && parent.mParent instanceof View) { 20818 parent = (View) parent.mParent; 20819 } 20820 20821 return parent; 20822 } 20823 20824 /** 20825 * Transforms a motion event from view-local coordinates to on-screen 20826 * coordinates. 20827 * 20828 * @param ev the view-local motion event 20829 * @return false if the transformation could not be applied 20830 * @hide 20831 */ 20832 public boolean toGlobalMotionEvent(MotionEvent ev) { 20833 final AttachInfo info = mAttachInfo; 20834 if (info == null) { 20835 return false; 20836 } 20837 20838 final Matrix m = info.mTmpMatrix; 20839 m.set(Matrix.IDENTITY_MATRIX); 20840 transformMatrixToGlobal(m); 20841 ev.transform(m); 20842 return true; 20843 } 20844 20845 /** 20846 * Transforms a motion event from on-screen coordinates to view-local 20847 * coordinates. 20848 * 20849 * @param ev the on-screen motion event 20850 * @return false if the transformation could not be applied 20851 * @hide 20852 */ 20853 public boolean toLocalMotionEvent(MotionEvent ev) { 20854 final AttachInfo info = mAttachInfo; 20855 if (info == null) { 20856 return false; 20857 } 20858 20859 final Matrix m = info.mTmpMatrix; 20860 m.set(Matrix.IDENTITY_MATRIX); 20861 transformMatrixToLocal(m); 20862 ev.transform(m); 20863 return true; 20864 } 20865 20866 /** 20867 * Modifies the input matrix such that it maps view-local coordinates to 20868 * on-screen coordinates. 20869 * 20870 * @param m input matrix to modify 20871 * @hide 20872 */ 20873 public void transformMatrixToGlobal(Matrix m) { 20874 final ViewParent parent = mParent; 20875 if (parent instanceof View) { 20876 final View vp = (View) parent; 20877 vp.transformMatrixToGlobal(m); 20878 m.preTranslate(-vp.mScrollX, -vp.mScrollY); 20879 } else if (parent instanceof ViewRootImpl) { 20880 final ViewRootImpl vr = (ViewRootImpl) parent; 20881 vr.transformMatrixToGlobal(m); 20882 m.preTranslate(0, -vr.mCurScrollY); 20883 } 20884 20885 m.preTranslate(mLeft, mTop); 20886 20887 if (!hasIdentityMatrix()) { 20888 m.preConcat(getMatrix()); 20889 } 20890 } 20891 20892 /** 20893 * Modifies the input matrix such that it maps on-screen coordinates to 20894 * view-local coordinates. 20895 * 20896 * @param m input matrix to modify 20897 * @hide 20898 */ 20899 public void transformMatrixToLocal(Matrix m) { 20900 final ViewParent parent = mParent; 20901 if (parent instanceof View) { 20902 final View vp = (View) parent; 20903 vp.transformMatrixToLocal(m); 20904 m.postTranslate(vp.mScrollX, vp.mScrollY); 20905 } else if (parent instanceof ViewRootImpl) { 20906 final ViewRootImpl vr = (ViewRootImpl) parent; 20907 vr.transformMatrixToLocal(m); 20908 m.postTranslate(0, vr.mCurScrollY); 20909 } 20910 20911 m.postTranslate(-mLeft, -mTop); 20912 20913 if (!hasIdentityMatrix()) { 20914 m.postConcat(getInverseMatrix()); 20915 } 20916 } 20917 20918 /** 20919 * @hide 20920 */ 20921 @ViewDebug.ExportedProperty(category = "layout", indexMapping = { 20922 @ViewDebug.IntToString(from = 0, to = "x"), 20923 @ViewDebug.IntToString(from = 1, to = "y") 20924 }) 20925 public int[] getLocationOnScreen() { 20926 int[] location = new int[2]; 20927 getLocationOnScreen(location); 20928 return location; 20929 } 20930 20931 /** 20932 * <p>Computes the coordinates of this view on the screen. The argument 20933 * must be an array of two integers. After the method returns, the array 20934 * contains the x and y location in that order.</p> 20935 * 20936 * @param outLocation an array of two integers in which to hold the coordinates 20937 */ 20938 public void getLocationOnScreen(@Size(2) int[] outLocation) { 20939 getLocationInWindow(outLocation); 20940 20941 final AttachInfo info = mAttachInfo; 20942 if (info != null) { 20943 outLocation[0] += info.mWindowLeft; 20944 outLocation[1] += info.mWindowTop; 20945 } 20946 } 20947 20948 /** 20949 * <p>Computes the coordinates of this view in its window. The argument 20950 * must be an array of two integers. After the method returns, the array 20951 * contains the x and y location in that order.</p> 20952 * 20953 * @param outLocation an array of two integers in which to hold the coordinates 20954 */ 20955 public void getLocationInWindow(@Size(2) int[] outLocation) { 20956 if (outLocation == null || outLocation.length < 2) { 20957 throw new IllegalArgumentException("outLocation must be an array of two integers"); 20958 } 20959 20960 outLocation[0] = 0; 20961 outLocation[1] = 0; 20962 20963 transformFromViewToWindowSpace(outLocation); 20964 } 20965 20966 /** @hide */ 20967 public void transformFromViewToWindowSpace(@Size(2) int[] inOutLocation) { 20968 if (inOutLocation == null || inOutLocation.length < 2) { 20969 throw new IllegalArgumentException("inOutLocation must be an array of two integers"); 20970 } 20971 20972 if (mAttachInfo == null) { 20973 // When the view is not attached to a window, this method does not make sense 20974 inOutLocation[0] = inOutLocation[1] = 0; 20975 return; 20976 } 20977 20978 float position[] = mAttachInfo.mTmpTransformLocation; 20979 position[0] = inOutLocation[0]; 20980 position[1] = inOutLocation[1]; 20981 20982 if (!hasIdentityMatrix()) { 20983 getMatrix().mapPoints(position); 20984 } 20985 20986 position[0] += mLeft; 20987 position[1] += mTop; 20988 20989 ViewParent viewParent = mParent; 20990 while (viewParent instanceof View) { 20991 final View view = (View) viewParent; 20992 20993 position[0] -= view.mScrollX; 20994 position[1] -= view.mScrollY; 20995 20996 if (!view.hasIdentityMatrix()) { 20997 view.getMatrix().mapPoints(position); 20998 } 20999 21000 position[0] += view.mLeft; 21001 position[1] += view.mTop; 21002 21003 viewParent = view.mParent; 21004 } 21005 21006 if (viewParent instanceof ViewRootImpl) { 21007 // *cough* 21008 final ViewRootImpl vr = (ViewRootImpl) viewParent; 21009 position[1] -= vr.mCurScrollY; 21010 } 21011 21012 inOutLocation[0] = Math.round(position[0]); 21013 inOutLocation[1] = Math.round(position[1]); 21014 } 21015 21016 /** 21017 * @param id the id of the view to be found 21018 * @return the view of the specified id, null if cannot be found 21019 * @hide 21020 */ 21021 protected <T extends View> T findViewTraversal(@IdRes int id) { 21022 if (id == mID) { 21023 return (T) this; 21024 } 21025 return null; 21026 } 21027 21028 /** 21029 * @param tag the tag of the view to be found 21030 * @return the view of specified tag, null if cannot be found 21031 * @hide 21032 */ 21033 protected <T extends View> T findViewWithTagTraversal(Object tag) { 21034 if (tag != null && tag.equals(mTag)) { 21035 return (T) this; 21036 } 21037 return null; 21038 } 21039 21040 /** 21041 * @param predicate The predicate to evaluate. 21042 * @param childToSkip If not null, ignores this child during the recursive traversal. 21043 * @return The first view that matches the predicate or null. 21044 * @hide 21045 */ 21046 protected <T extends View> T findViewByPredicateTraversal(Predicate<View> predicate, 21047 View childToSkip) { 21048 if (predicate.test(this)) { 21049 return (T) this; 21050 } 21051 return null; 21052 } 21053 21054 /** 21055 * Finds the first descendant view with the given ID, the view itself if 21056 * the ID matches {@link #getId()}, or {@code null} if the ID is invalid 21057 * (< 0) or there is no matching view in the hierarchy. 21058 * <p> 21059 * <strong>Note:</strong> In most cases -- depending on compiler support -- 21060 * the resulting view is automatically cast to the target class type. If 21061 * the target class type is unconstrained, an explicit cast may be 21062 * necessary. 21063 * 21064 * @param id the ID to search for 21065 * @return a view with given ID if found, or {@code null} otherwise 21066 * @see View#findViewById(int) 21067 */ 21068 @Nullable 21069 public final <T extends View> T findViewById(@IdRes int id) { 21070 if (id < 0) { 21071 return null; 21072 } 21073 return findViewTraversal(id); 21074 } 21075 21076 /** 21077 * Finds a view by its unuque and stable accessibility id. 21078 * 21079 * @param accessibilityId The searched accessibility id. 21080 * @return The found view. 21081 */ 21082 final <T extends View> T findViewByAccessibilityId(int accessibilityId) { 21083 if (accessibilityId < 0) { 21084 return null; 21085 } 21086 T view = findViewByAccessibilityIdTraversal(accessibilityId); 21087 if (view != null) { 21088 return view.includeForAccessibility() ? view : null; 21089 } 21090 return null; 21091 } 21092 21093 /** 21094 * Performs the traversal to find a view by its unuque and stable accessibility id. 21095 * 21096 * <strong>Note:</strong>This method does not stop at the root namespace 21097 * boundary since the user can touch the screen at an arbitrary location 21098 * potentially crossing the root namespace bounday which will send an 21099 * accessibility event to accessibility services and they should be able 21100 * to obtain the event source. Also accessibility ids are guaranteed to be 21101 * unique in the window. 21102 * 21103 * @param accessibilityId The accessibility id. 21104 * @return The found view. 21105 * @hide 21106 */ 21107 public <T extends View> T findViewByAccessibilityIdTraversal(int accessibilityId) { 21108 if (getAccessibilityViewId() == accessibilityId) { 21109 return (T) this; 21110 } 21111 return null; 21112 } 21113 21114 /** 21115 * Look for a child view with the given tag. If this view has the given 21116 * tag, return this view. 21117 * 21118 * @param tag The tag to search for, using "tag.equals(getTag())". 21119 * @return The View that has the given tag in the hierarchy or null 21120 */ 21121 public final <T extends View> T findViewWithTag(Object tag) { 21122 if (tag == null) { 21123 return null; 21124 } 21125 return findViewWithTagTraversal(tag); 21126 } 21127 21128 /** 21129 * Look for a child view that matches the specified predicate. 21130 * If this view matches the predicate, return this view. 21131 * 21132 * @param predicate The predicate to evaluate. 21133 * @return The first view that matches the predicate or null. 21134 * @hide 21135 */ 21136 public final <T extends View> T findViewByPredicate(Predicate<View> predicate) { 21137 return findViewByPredicateTraversal(predicate, null); 21138 } 21139 21140 /** 21141 * Look for a child view that matches the specified predicate, 21142 * starting with the specified view and its descendents and then 21143 * recusively searching the ancestors and siblings of that view 21144 * until this view is reached. 21145 * 21146 * This method is useful in cases where the predicate does not match 21147 * a single unique view (perhaps multiple views use the same id) 21148 * and we are trying to find the view that is "closest" in scope to the 21149 * starting view. 21150 * 21151 * @param start The view to start from. 21152 * @param predicate The predicate to evaluate. 21153 * @return The first view that matches the predicate or null. 21154 * @hide 21155 */ 21156 public final <T extends View> T findViewByPredicateInsideOut( 21157 View start, Predicate<View> predicate) { 21158 View childToSkip = null; 21159 for (;;) { 21160 T view = start.findViewByPredicateTraversal(predicate, childToSkip); 21161 if (view != null || start == this) { 21162 return view; 21163 } 21164 21165 ViewParent parent = start.getParent(); 21166 if (parent == null || !(parent instanceof View)) { 21167 return null; 21168 } 21169 21170 childToSkip = start; 21171 start = (View) parent; 21172 } 21173 } 21174 21175 /** 21176 * Sets the identifier for this view. The identifier does not have to be 21177 * unique in this view's hierarchy. The identifier should be a positive 21178 * number. 21179 * 21180 * @see #NO_ID 21181 * @see #getId() 21182 * @see #findViewById(int) 21183 * 21184 * @param id a number used to identify the view 21185 * 21186 * @attr ref android.R.styleable#View_id 21187 */ 21188 public void setId(@IdRes int id) { 21189 mID = id; 21190 if (mID == View.NO_ID && mLabelForId != View.NO_ID) { 21191 mID = generateViewId(); 21192 } 21193 } 21194 21195 /** 21196 * {@hide} 21197 * 21198 * @param isRoot true if the view belongs to the root namespace, false 21199 * otherwise 21200 */ 21201 public void setIsRootNamespace(boolean isRoot) { 21202 if (isRoot) { 21203 mPrivateFlags |= PFLAG_IS_ROOT_NAMESPACE; 21204 } else { 21205 mPrivateFlags &= ~PFLAG_IS_ROOT_NAMESPACE; 21206 } 21207 } 21208 21209 /** 21210 * {@hide} 21211 * 21212 * @return true if the view belongs to the root namespace, false otherwise 21213 */ 21214 public boolean isRootNamespace() { 21215 return (mPrivateFlags&PFLAG_IS_ROOT_NAMESPACE) != 0; 21216 } 21217 21218 /** 21219 * Returns this view's identifier. 21220 * 21221 * @return a positive integer used to identify the view or {@link #NO_ID} 21222 * if the view has no ID 21223 * 21224 * @see #setId(int) 21225 * @see #findViewById(int) 21226 * @attr ref android.R.styleable#View_id 21227 */ 21228 @IdRes 21229 @ViewDebug.CapturedViewProperty 21230 public int getId() { 21231 return mID; 21232 } 21233 21234 /** 21235 * Returns this view's tag. 21236 * 21237 * @return the Object stored in this view as a tag, or {@code null} if not 21238 * set 21239 * 21240 * @see #setTag(Object) 21241 * @see #getTag(int) 21242 */ 21243 @ViewDebug.ExportedProperty 21244 public Object getTag() { 21245 return mTag; 21246 } 21247 21248 /** 21249 * Sets the tag associated with this view. A tag can be used to mark 21250 * a view in its hierarchy and does not have to be unique within the 21251 * hierarchy. Tags can also be used to store data within a view without 21252 * resorting to another data structure. 21253 * 21254 * @param tag an Object to tag the view with 21255 * 21256 * @see #getTag() 21257 * @see #setTag(int, Object) 21258 */ 21259 public void setTag(final Object tag) { 21260 mTag = tag; 21261 } 21262 21263 /** 21264 * Returns the tag associated with this view and the specified key. 21265 * 21266 * @param key The key identifying the tag 21267 * 21268 * @return the Object stored in this view as a tag, or {@code null} if not 21269 * set 21270 * 21271 * @see #setTag(int, Object) 21272 * @see #getTag() 21273 */ 21274 public Object getTag(int key) { 21275 if (mKeyedTags != null) return mKeyedTags.get(key); 21276 return null; 21277 } 21278 21279 /** 21280 * Sets a tag associated with this view and a key. A tag can be used 21281 * to mark a view in its hierarchy and does not have to be unique within 21282 * the hierarchy. Tags can also be used to store data within a view 21283 * without resorting to another data structure. 21284 * 21285 * The specified key should be an id declared in the resources of the 21286 * application to ensure it is unique (see the <a 21287 * href="{@docRoot}guide/topics/resources/more-resources.html#Id">ID resource type</a>). 21288 * Keys identified as belonging to 21289 * the Android framework or not associated with any package will cause 21290 * an {@link IllegalArgumentException} to be thrown. 21291 * 21292 * @param key The key identifying the tag 21293 * @param tag An Object to tag the view with 21294 * 21295 * @throws IllegalArgumentException If they specified key is not valid 21296 * 21297 * @see #setTag(Object) 21298 * @see #getTag(int) 21299 */ 21300 public void setTag(int key, final Object tag) { 21301 // If the package id is 0x00 or 0x01, it's either an undefined package 21302 // or a framework id 21303 if ((key >>> 24) < 2) { 21304 throw new IllegalArgumentException("The key must be an application-specific " 21305 + "resource id."); 21306 } 21307 21308 setKeyedTag(key, tag); 21309 } 21310 21311 /** 21312 * Variation of {@link #setTag(int, Object)} that enforces the key to be a 21313 * framework id. 21314 * 21315 * @hide 21316 */ 21317 public void setTagInternal(int key, Object tag) { 21318 if ((key >>> 24) != 0x1) { 21319 throw new IllegalArgumentException("The key must be a framework-specific " 21320 + "resource id."); 21321 } 21322 21323 setKeyedTag(key, tag); 21324 } 21325 21326 private void setKeyedTag(int key, Object tag) { 21327 if (mKeyedTags == null) { 21328 mKeyedTags = new SparseArray<Object>(2); 21329 } 21330 21331 mKeyedTags.put(key, tag); 21332 } 21333 21334 /** 21335 * Prints information about this view in the log output, with the tag 21336 * {@link #VIEW_LOG_TAG}. 21337 * 21338 * @hide 21339 */ 21340 public void debug() { 21341 debug(0); 21342 } 21343 21344 /** 21345 * Prints information about this view in the log output, with the tag 21346 * {@link #VIEW_LOG_TAG}. Each line in the output is preceded with an 21347 * indentation defined by the <code>depth</code>. 21348 * 21349 * @param depth the indentation level 21350 * 21351 * @hide 21352 */ 21353 protected void debug(int depth) { 21354 String output = debugIndent(depth - 1); 21355 21356 output += "+ " + this; 21357 int id = getId(); 21358 if (id != -1) { 21359 output += " (id=" + id + ")"; 21360 } 21361 Object tag = getTag(); 21362 if (tag != null) { 21363 output += " (tag=" + tag + ")"; 21364 } 21365 Log.d(VIEW_LOG_TAG, output); 21366 21367 if ((mPrivateFlags & PFLAG_FOCUSED) != 0) { 21368 output = debugIndent(depth) + " FOCUSED"; 21369 Log.d(VIEW_LOG_TAG, output); 21370 } 21371 21372 output = debugIndent(depth); 21373 output += "frame={" + mLeft + ", " + mTop + ", " + mRight 21374 + ", " + mBottom + "} scroll={" + mScrollX + ", " + mScrollY 21375 + "} "; 21376 Log.d(VIEW_LOG_TAG, output); 21377 21378 if (mPaddingLeft != 0 || mPaddingTop != 0 || mPaddingRight != 0 21379 || mPaddingBottom != 0) { 21380 output = debugIndent(depth); 21381 output += "padding={" + mPaddingLeft + ", " + mPaddingTop 21382 + ", " + mPaddingRight + ", " + mPaddingBottom + "}"; 21383 Log.d(VIEW_LOG_TAG, output); 21384 } 21385 21386 output = debugIndent(depth); 21387 output += "mMeasureWidth=" + mMeasuredWidth + 21388 " mMeasureHeight=" + mMeasuredHeight; 21389 Log.d(VIEW_LOG_TAG, output); 21390 21391 output = debugIndent(depth); 21392 if (mLayoutParams == null) { 21393 output += "BAD! no layout params"; 21394 } else { 21395 output = mLayoutParams.debug(output); 21396 } 21397 Log.d(VIEW_LOG_TAG, output); 21398 21399 output = debugIndent(depth); 21400 output += "flags={"; 21401 output += View.printFlags(mViewFlags); 21402 output += "}"; 21403 Log.d(VIEW_LOG_TAG, output); 21404 21405 output = debugIndent(depth); 21406 output += "privateFlags={"; 21407 output += View.printPrivateFlags(mPrivateFlags); 21408 output += "}"; 21409 Log.d(VIEW_LOG_TAG, output); 21410 } 21411 21412 /** 21413 * Creates a string of whitespaces used for indentation. 21414 * 21415 * @param depth the indentation level 21416 * @return a String containing (depth * 2 + 3) * 2 white spaces 21417 * 21418 * @hide 21419 */ 21420 protected static String debugIndent(int depth) { 21421 StringBuilder spaces = new StringBuilder((depth * 2 + 3) * 2); 21422 for (int i = 0; i < (depth * 2) + 3; i++) { 21423 spaces.append(' ').append(' '); 21424 } 21425 return spaces.toString(); 21426 } 21427 21428 /** 21429 * <p>Return the offset of the widget's text baseline from the widget's top 21430 * boundary. If this widget does not support baseline alignment, this 21431 * method returns -1. </p> 21432 * 21433 * @return the offset of the baseline within the widget's bounds or -1 21434 * if baseline alignment is not supported 21435 */ 21436 @ViewDebug.ExportedProperty(category = "layout") 21437 public int getBaseline() { 21438 return -1; 21439 } 21440 21441 /** 21442 * Returns whether the view hierarchy is currently undergoing a layout pass. This 21443 * information is useful to avoid situations such as calling {@link #requestLayout()} during 21444 * a layout pass. 21445 * 21446 * @return whether the view hierarchy is currently undergoing a layout pass 21447 */ 21448 public boolean isInLayout() { 21449 ViewRootImpl viewRoot = getViewRootImpl(); 21450 return (viewRoot != null && viewRoot.isInLayout()); 21451 } 21452 21453 /** 21454 * Call this when something has changed which has invalidated the 21455 * layout of this view. This will schedule a layout pass of the view 21456 * tree. This should not be called while the view hierarchy is currently in a layout 21457 * pass ({@link #isInLayout()}. If layout is happening, the request may be honored at the 21458 * end of the current layout pass (and then layout will run again) or after the current 21459 * frame is drawn and the next layout occurs. 21460 * 21461 * <p>Subclasses which override this method should call the superclass method to 21462 * handle possible request-during-layout errors correctly.</p> 21463 */ 21464 @CallSuper 21465 public void requestLayout() { 21466 if (mMeasureCache != null) mMeasureCache.clear(); 21467 21468 if (mAttachInfo != null && mAttachInfo.mViewRequestingLayout == null) { 21469 // Only trigger request-during-layout logic if this is the view requesting it, 21470 // not the views in its parent hierarchy 21471 ViewRootImpl viewRoot = getViewRootImpl(); 21472 if (viewRoot != null && viewRoot.isInLayout()) { 21473 if (!viewRoot.requestLayoutDuringLayout(this)) { 21474 return; 21475 } 21476 } 21477 mAttachInfo.mViewRequestingLayout = this; 21478 } 21479 21480 mPrivateFlags |= PFLAG_FORCE_LAYOUT; 21481 mPrivateFlags |= PFLAG_INVALIDATED; 21482 21483 if (mParent != null && !mParent.isLayoutRequested()) { 21484 mParent.requestLayout(); 21485 } 21486 if (mAttachInfo != null && mAttachInfo.mViewRequestingLayout == this) { 21487 mAttachInfo.mViewRequestingLayout = null; 21488 } 21489 } 21490 21491 /** 21492 * Forces this view to be laid out during the next layout pass. 21493 * This method does not call requestLayout() or forceLayout() 21494 * on the parent. 21495 */ 21496 public void forceLayout() { 21497 if (mMeasureCache != null) mMeasureCache.clear(); 21498 21499 mPrivateFlags |= PFLAG_FORCE_LAYOUT; 21500 mPrivateFlags |= PFLAG_INVALIDATED; 21501 } 21502 21503 /** 21504 * <p> 21505 * This is called to find out how big a view should be. The parent 21506 * supplies constraint information in the width and height parameters. 21507 * </p> 21508 * 21509 * <p> 21510 * The actual measurement work of a view is performed in 21511 * {@link #onMeasure(int, int)}, called by this method. Therefore, only 21512 * {@link #onMeasure(int, int)} can and must be overridden by subclasses. 21513 * </p> 21514 * 21515 * 21516 * @param widthMeasureSpec Horizontal space requirements as imposed by the 21517 * parent 21518 * @param heightMeasureSpec Vertical space requirements as imposed by the 21519 * parent 21520 * 21521 * @see #onMeasure(int, int) 21522 */ 21523 public final void measure(int widthMeasureSpec, int heightMeasureSpec) { 21524 boolean optical = isLayoutModeOptical(this); 21525 if (optical != isLayoutModeOptical(mParent)) { 21526 Insets insets = getOpticalInsets(); 21527 int oWidth = insets.left + insets.right; 21528 int oHeight = insets.top + insets.bottom; 21529 widthMeasureSpec = MeasureSpec.adjust(widthMeasureSpec, optical ? -oWidth : oWidth); 21530 heightMeasureSpec = MeasureSpec.adjust(heightMeasureSpec, optical ? -oHeight : oHeight); 21531 } 21532 21533 // Suppress sign extension for the low bytes 21534 long key = (long) widthMeasureSpec << 32 | (long) heightMeasureSpec & 0xffffffffL; 21535 if (mMeasureCache == null) mMeasureCache = new LongSparseLongArray(2); 21536 21537 final boolean forceLayout = (mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT; 21538 21539 // Optimize layout by avoiding an extra EXACTLY pass when the view is 21540 // already measured as the correct size. In API 23 and below, this 21541 // extra pass is required to make LinearLayout re-distribute weight. 21542 final boolean specChanged = widthMeasureSpec != mOldWidthMeasureSpec 21543 || heightMeasureSpec != mOldHeightMeasureSpec; 21544 final boolean isSpecExactly = MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY 21545 && MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.EXACTLY; 21546 final boolean matchesSpecSize = getMeasuredWidth() == MeasureSpec.getSize(widthMeasureSpec) 21547 && getMeasuredHeight() == MeasureSpec.getSize(heightMeasureSpec); 21548 final boolean needsLayout = specChanged 21549 && (sAlwaysRemeasureExactly || !isSpecExactly || !matchesSpecSize); 21550 21551 if (forceLayout || needsLayout) { 21552 // first clears the measured dimension flag 21553 mPrivateFlags &= ~PFLAG_MEASURED_DIMENSION_SET; 21554 21555 resolveRtlPropertiesIfNeeded(); 21556 21557 int cacheIndex = forceLayout ? -1 : mMeasureCache.indexOfKey(key); 21558 if (cacheIndex < 0 || sIgnoreMeasureCache) { 21559 // measure ourselves, this should set the measured dimension flag back 21560 onMeasure(widthMeasureSpec, heightMeasureSpec); 21561 mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT; 21562 } else { 21563 long value = mMeasureCache.valueAt(cacheIndex); 21564 // Casting a long to int drops the high 32 bits, no mask needed 21565 setMeasuredDimensionRaw((int) (value >> 32), (int) value); 21566 mPrivateFlags3 |= PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT; 21567 } 21568 21569 // flag not set, setMeasuredDimension() was not invoked, we raise 21570 // an exception to warn the developer 21571 if ((mPrivateFlags & PFLAG_MEASURED_DIMENSION_SET) != PFLAG_MEASURED_DIMENSION_SET) { 21572 throw new IllegalStateException("View with id " + getId() + ": " 21573 + getClass().getName() + "#onMeasure() did not set the" 21574 + " measured dimension by calling" 21575 + " setMeasuredDimension()"); 21576 } 21577 21578 mPrivateFlags |= PFLAG_LAYOUT_REQUIRED; 21579 } 21580 21581 mOldWidthMeasureSpec = widthMeasureSpec; 21582 mOldHeightMeasureSpec = heightMeasureSpec; 21583 21584 mMeasureCache.put(key, ((long) mMeasuredWidth) << 32 | 21585 (long) mMeasuredHeight & 0xffffffffL); // suppress sign extension 21586 } 21587 21588 /** 21589 * <p> 21590 * Measure the view and its content to determine the measured width and the 21591 * measured height. This method is invoked by {@link #measure(int, int)} and 21592 * should be overridden by subclasses to provide accurate and efficient 21593 * measurement of their contents. 21594 * </p> 21595 * 21596 * <p> 21597 * <strong>CONTRACT:</strong> When overriding this method, you 21598 * <em>must</em> call {@link #setMeasuredDimension(int, int)} to store the 21599 * measured width and height of this view. Failure to do so will trigger an 21600 * <code>IllegalStateException</code>, thrown by 21601 * {@link #measure(int, int)}. Calling the superclass' 21602 * {@link #onMeasure(int, int)} is a valid use. 21603 * </p> 21604 * 21605 * <p> 21606 * The base class implementation of measure defaults to the background size, 21607 * unless a larger size is allowed by the MeasureSpec. Subclasses should 21608 * override {@link #onMeasure(int, int)} to provide better measurements of 21609 * their content. 21610 * </p> 21611 * 21612 * <p> 21613 * If this method is overridden, it is the subclass's responsibility to make 21614 * sure the measured height and width are at least the view's minimum height 21615 * and width ({@link #getSuggestedMinimumHeight()} and 21616 * {@link #getSuggestedMinimumWidth()}). 21617 * </p> 21618 * 21619 * @param widthMeasureSpec horizontal space requirements as imposed by the parent. 21620 * The requirements are encoded with 21621 * {@link android.view.View.MeasureSpec}. 21622 * @param heightMeasureSpec vertical space requirements as imposed by the parent. 21623 * The requirements are encoded with 21624 * {@link android.view.View.MeasureSpec}. 21625 * 21626 * @see #getMeasuredWidth() 21627 * @see #getMeasuredHeight() 21628 * @see #setMeasuredDimension(int, int) 21629 * @see #getSuggestedMinimumHeight() 21630 * @see #getSuggestedMinimumWidth() 21631 * @see android.view.View.MeasureSpec#getMode(int) 21632 * @see android.view.View.MeasureSpec#getSize(int) 21633 */ 21634 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 21635 setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec), 21636 getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec)); 21637 } 21638 21639 /** 21640 * <p>This method must be called by {@link #onMeasure(int, int)} to store the 21641 * measured width and measured height. Failing to do so will trigger an 21642 * exception at measurement time.</p> 21643 * 21644 * @param measuredWidth The measured width of this view. May be a complex 21645 * bit mask as defined by {@link #MEASURED_SIZE_MASK} and 21646 * {@link #MEASURED_STATE_TOO_SMALL}. 21647 * @param measuredHeight The measured height of this view. May be a complex 21648 * bit mask as defined by {@link #MEASURED_SIZE_MASK} and 21649 * {@link #MEASURED_STATE_TOO_SMALL}. 21650 */ 21651 protected final void setMeasuredDimension(int measuredWidth, int measuredHeight) { 21652 boolean optical = isLayoutModeOptical(this); 21653 if (optical != isLayoutModeOptical(mParent)) { 21654 Insets insets = getOpticalInsets(); 21655 int opticalWidth = insets.left + insets.right; 21656 int opticalHeight = insets.top + insets.bottom; 21657 21658 measuredWidth += optical ? opticalWidth : -opticalWidth; 21659 measuredHeight += optical ? opticalHeight : -opticalHeight; 21660 } 21661 setMeasuredDimensionRaw(measuredWidth, measuredHeight); 21662 } 21663 21664 /** 21665 * Sets the measured dimension without extra processing for things like optical bounds. 21666 * Useful for reapplying consistent values that have already been cooked with adjustments 21667 * for optical bounds, etc. such as those from the measurement cache. 21668 * 21669 * @param measuredWidth The measured width of this view. May be a complex 21670 * bit mask as defined by {@link #MEASURED_SIZE_MASK} and 21671 * {@link #MEASURED_STATE_TOO_SMALL}. 21672 * @param measuredHeight The measured height of this view. May be a complex 21673 * bit mask as defined by {@link #MEASURED_SIZE_MASK} and 21674 * {@link #MEASURED_STATE_TOO_SMALL}. 21675 */ 21676 private void setMeasuredDimensionRaw(int measuredWidth, int measuredHeight) { 21677 mMeasuredWidth = measuredWidth; 21678 mMeasuredHeight = measuredHeight; 21679 21680 mPrivateFlags |= PFLAG_MEASURED_DIMENSION_SET; 21681 } 21682 21683 /** 21684 * Merge two states as returned by {@link #getMeasuredState()}. 21685 * @param curState The current state as returned from a view or the result 21686 * of combining multiple views. 21687 * @param newState The new view state to combine. 21688 * @return Returns a new integer reflecting the combination of the two 21689 * states. 21690 */ 21691 public static int combineMeasuredStates(int curState, int newState) { 21692 return curState | newState; 21693 } 21694 21695 /** 21696 * Version of {@link #resolveSizeAndState(int, int, int)} 21697 * returning only the {@link #MEASURED_SIZE_MASK} bits of the result. 21698 */ 21699 public static int resolveSize(int size, int measureSpec) { 21700 return resolveSizeAndState(size, measureSpec, 0) & MEASURED_SIZE_MASK; 21701 } 21702 21703 /** 21704 * Utility to reconcile a desired size and state, with constraints imposed 21705 * by a MeasureSpec. Will take the desired size, unless a different size 21706 * is imposed by the constraints. The returned value is a compound integer, 21707 * with the resolved size in the {@link #MEASURED_SIZE_MASK} bits and 21708 * optionally the bit {@link #MEASURED_STATE_TOO_SMALL} set if the 21709 * resulting size is smaller than the size the view wants to be. 21710 * 21711 * @param size How big the view wants to be. 21712 * @param measureSpec Constraints imposed by the parent. 21713 * @param childMeasuredState Size information bit mask for the view's 21714 * children. 21715 * @return Size information bit mask as defined by 21716 * {@link #MEASURED_SIZE_MASK} and 21717 * {@link #MEASURED_STATE_TOO_SMALL}. 21718 */ 21719 public static int resolveSizeAndState(int size, int measureSpec, int childMeasuredState) { 21720 final int specMode = MeasureSpec.getMode(measureSpec); 21721 final int specSize = MeasureSpec.getSize(measureSpec); 21722 final int result; 21723 switch (specMode) { 21724 case MeasureSpec.AT_MOST: 21725 if (specSize < size) { 21726 result = specSize | MEASURED_STATE_TOO_SMALL; 21727 } else { 21728 result = size; 21729 } 21730 break; 21731 case MeasureSpec.EXACTLY: 21732 result = specSize; 21733 break; 21734 case MeasureSpec.UNSPECIFIED: 21735 default: 21736 result = size; 21737 } 21738 return result | (childMeasuredState & MEASURED_STATE_MASK); 21739 } 21740 21741 /** 21742 * Utility to return a default size. Uses the supplied size if the 21743 * MeasureSpec imposed no constraints. Will get larger if allowed 21744 * by the MeasureSpec. 21745 * 21746 * @param size Default size for this view 21747 * @param measureSpec Constraints imposed by the parent 21748 * @return The size this view should be. 21749 */ 21750 public static int getDefaultSize(int size, int measureSpec) { 21751 int result = size; 21752 int specMode = MeasureSpec.getMode(measureSpec); 21753 int specSize = MeasureSpec.getSize(measureSpec); 21754 21755 switch (specMode) { 21756 case MeasureSpec.UNSPECIFIED: 21757 result = size; 21758 break; 21759 case MeasureSpec.AT_MOST: 21760 case MeasureSpec.EXACTLY: 21761 result = specSize; 21762 break; 21763 } 21764 return result; 21765 } 21766 21767 /** 21768 * Returns the suggested minimum height that the view should use. This 21769 * returns the maximum of the view's minimum height 21770 * and the background's minimum height 21771 * ({@link android.graphics.drawable.Drawable#getMinimumHeight()}). 21772 * <p> 21773 * When being used in {@link #onMeasure(int, int)}, the caller should still 21774 * ensure the returned height is within the requirements of the parent. 21775 * 21776 * @return The suggested minimum height of the view. 21777 */ 21778 protected int getSuggestedMinimumHeight() { 21779 return (mBackground == null) ? mMinHeight : max(mMinHeight, mBackground.getMinimumHeight()); 21780 21781 } 21782 21783 /** 21784 * Returns the suggested minimum width that the view should use. This 21785 * returns the maximum of the view's minimum width 21786 * and the background's minimum width 21787 * ({@link android.graphics.drawable.Drawable#getMinimumWidth()}). 21788 * <p> 21789 * When being used in {@link #onMeasure(int, int)}, the caller should still 21790 * ensure the returned width is within the requirements of the parent. 21791 * 21792 * @return The suggested minimum width of the view. 21793 */ 21794 protected int getSuggestedMinimumWidth() { 21795 return (mBackground == null) ? mMinWidth : max(mMinWidth, mBackground.getMinimumWidth()); 21796 } 21797 21798 /** 21799 * Returns the minimum height of the view. 21800 * 21801 * @return the minimum height the view will try to be, in pixels 21802 * 21803 * @see #setMinimumHeight(int) 21804 * 21805 * @attr ref android.R.styleable#View_minHeight 21806 */ 21807 public int getMinimumHeight() { 21808 return mMinHeight; 21809 } 21810 21811 /** 21812 * Sets the minimum height of the view. It is not guaranteed the view will 21813 * be able to achieve this minimum height (for example, if its parent layout 21814 * constrains it with less available height). 21815 * 21816 * @param minHeight The minimum height the view will try to be, in pixels 21817 * 21818 * @see #getMinimumHeight() 21819 * 21820 * @attr ref android.R.styleable#View_minHeight 21821 */ 21822 @RemotableViewMethod 21823 public void setMinimumHeight(int minHeight) { 21824 mMinHeight = minHeight; 21825 requestLayout(); 21826 } 21827 21828 /** 21829 * Returns the minimum width of the view. 21830 * 21831 * @return the minimum width the view will try to be, in pixels 21832 * 21833 * @see #setMinimumWidth(int) 21834 * 21835 * @attr ref android.R.styleable#View_minWidth 21836 */ 21837 public int getMinimumWidth() { 21838 return mMinWidth; 21839 } 21840 21841 /** 21842 * Sets the minimum width of the view. It is not guaranteed the view will 21843 * be able to achieve this minimum width (for example, if its parent layout 21844 * constrains it with less available width). 21845 * 21846 * @param minWidth The minimum width the view will try to be, in pixels 21847 * 21848 * @see #getMinimumWidth() 21849 * 21850 * @attr ref android.R.styleable#View_minWidth 21851 */ 21852 public void setMinimumWidth(int minWidth) { 21853 mMinWidth = minWidth; 21854 requestLayout(); 21855 21856 } 21857 21858 /** 21859 * Get the animation currently associated with this view. 21860 * 21861 * @return The animation that is currently playing or 21862 * scheduled to play for this view. 21863 */ 21864 public Animation getAnimation() { 21865 return mCurrentAnimation; 21866 } 21867 21868 /** 21869 * Start the specified animation now. 21870 * 21871 * @param animation the animation to start now 21872 */ 21873 public void startAnimation(Animation animation) { 21874 animation.setStartTime(Animation.START_ON_FIRST_FRAME); 21875 setAnimation(animation); 21876 invalidateParentCaches(); 21877 invalidate(true); 21878 } 21879 21880 /** 21881 * Cancels any animations for this view. 21882 */ 21883 public void clearAnimation() { 21884 if (mCurrentAnimation != null) { 21885 mCurrentAnimation.detach(); 21886 } 21887 mCurrentAnimation = null; 21888 invalidateParentIfNeeded(); 21889 } 21890 21891 /** 21892 * Sets the next animation to play for this view. 21893 * If you want the animation to play immediately, use 21894 * {@link #startAnimation(android.view.animation.Animation)} instead. 21895 * This method provides allows fine-grained 21896 * control over the start time and invalidation, but you 21897 * must make sure that 1) the animation has a start time set, and 21898 * 2) the view's parent (which controls animations on its children) 21899 * will be invalidated when the animation is supposed to 21900 * start. 21901 * 21902 * @param animation The next animation, or null. 21903 */ 21904 public void setAnimation(Animation animation) { 21905 mCurrentAnimation = animation; 21906 21907 if (animation != null) { 21908 // If the screen is off assume the animation start time is now instead of 21909 // the next frame we draw. Keeping the START_ON_FIRST_FRAME start time 21910 // would cause the animation to start when the screen turns back on 21911 if (mAttachInfo != null && mAttachInfo.mDisplayState == Display.STATE_OFF 21912 && animation.getStartTime() == Animation.START_ON_FIRST_FRAME) { 21913 animation.setStartTime(AnimationUtils.currentAnimationTimeMillis()); 21914 } 21915 animation.reset(); 21916 } 21917 } 21918 21919 /** 21920 * Invoked by a parent ViewGroup to notify the start of the animation 21921 * currently associated with this view. If you override this method, 21922 * always call super.onAnimationStart(); 21923 * 21924 * @see #setAnimation(android.view.animation.Animation) 21925 * @see #getAnimation() 21926 */ 21927 @CallSuper 21928 protected void onAnimationStart() { 21929 mPrivateFlags |= PFLAG_ANIMATION_STARTED; 21930 } 21931 21932 /** 21933 * Invoked by a parent ViewGroup to notify the end of the animation 21934 * currently associated with this view. If you override this method, 21935 * always call super.onAnimationEnd(); 21936 * 21937 * @see #setAnimation(android.view.animation.Animation) 21938 * @see #getAnimation() 21939 */ 21940 @CallSuper 21941 protected void onAnimationEnd() { 21942 mPrivateFlags &= ~PFLAG_ANIMATION_STARTED; 21943 } 21944 21945 /** 21946 * Invoked if there is a Transform that involves alpha. Subclass that can 21947 * draw themselves with the specified alpha should return true, and then 21948 * respect that alpha when their onDraw() is called. If this returns false 21949 * then the view may be redirected to draw into an offscreen buffer to 21950 * fulfill the request, which will look fine, but may be slower than if the 21951 * subclass handles it internally. The default implementation returns false. 21952 * 21953 * @param alpha The alpha (0..255) to apply to the view's drawing 21954 * @return true if the view can draw with the specified alpha. 21955 */ 21956 protected boolean onSetAlpha(int alpha) { 21957 return false; 21958 } 21959 21960 /** 21961 * This is used by the RootView to perform an optimization when 21962 * the view hierarchy contains one or several SurfaceView. 21963 * SurfaceView is always considered transparent, but its children are not, 21964 * therefore all View objects remove themselves from the global transparent 21965 * region (passed as a parameter to this function). 21966 * 21967 * @param region The transparent region for this ViewAncestor (window). 21968 * 21969 * @return Returns true if the effective visibility of the view at this 21970 * point is opaque, regardless of the transparent region; returns false 21971 * if it is possible for underlying windows to be seen behind the view. 21972 * 21973 * {@hide} 21974 */ 21975 public boolean gatherTransparentRegion(Region region) { 21976 final AttachInfo attachInfo = mAttachInfo; 21977 if (region != null && attachInfo != null) { 21978 final int pflags = mPrivateFlags; 21979 if ((pflags & PFLAG_SKIP_DRAW) == 0) { 21980 // The SKIP_DRAW flag IS NOT set, so this view draws. We need to 21981 // remove it from the transparent region. 21982 final int[] location = attachInfo.mTransparentLocation; 21983 getLocationInWindow(location); 21984 // When a view has Z value, then it will be better to leave some area below the view 21985 // for drawing shadow. The shadow outset is proportional to the Z value. Note that 21986 // the bottom part needs more offset than the left, top and right parts due to the 21987 // spot light effects. 21988 int shadowOffset = getZ() > 0 ? (int) getZ() : 0; 21989 region.op(location[0] - shadowOffset, location[1] - shadowOffset, 21990 location[0] + mRight - mLeft + shadowOffset, 21991 location[1] + mBottom - mTop + (shadowOffset * 3), Region.Op.DIFFERENCE); 21992 } else { 21993 if (mBackground != null && mBackground.getOpacity() != PixelFormat.TRANSPARENT) { 21994 // The SKIP_DRAW flag IS set and the background drawable exists, we remove 21995 // the background drawable's non-transparent parts from this transparent region. 21996 applyDrawableToTransparentRegion(mBackground, region); 21997 } 21998 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null 21999 && mForegroundInfo.mDrawable.getOpacity() != PixelFormat.TRANSPARENT) { 22000 // Similarly, we remove the foreground drawable's non-transparent parts. 22001 applyDrawableToTransparentRegion(mForegroundInfo.mDrawable, region); 22002 } 22003 if (mDefaultFocusHighlight != null 22004 && mDefaultFocusHighlight.getOpacity() != PixelFormat.TRANSPARENT) { 22005 // Similarly, we remove the default focus highlight's non-transparent parts. 22006 applyDrawableToTransparentRegion(mDefaultFocusHighlight, region); 22007 } 22008 } 22009 } 22010 return true; 22011 } 22012 22013 /** 22014 * Play a sound effect for this view. 22015 * 22016 * <p>The framework will play sound effects for some built in actions, such as 22017 * clicking, but you may wish to play these effects in your widget, 22018 * for instance, for internal navigation. 22019 * 22020 * <p>The sound effect will only be played if sound effects are enabled by the user, and 22021 * {@link #isSoundEffectsEnabled()} is true. 22022 * 22023 * @param soundConstant One of the constants defined in {@link SoundEffectConstants} 22024 */ 22025 public void playSoundEffect(int soundConstant) { 22026 if (mAttachInfo == null || mAttachInfo.mRootCallbacks == null || !isSoundEffectsEnabled()) { 22027 return; 22028 } 22029 mAttachInfo.mRootCallbacks.playSoundEffect(soundConstant); 22030 } 22031 22032 /** 22033 * BZZZTT!!1! 22034 * 22035 * <p>Provide haptic feedback to the user for this view. 22036 * 22037 * <p>The framework will provide haptic feedback for some built in actions, 22038 * such as long presses, but you may wish to provide feedback for your 22039 * own widget. 22040 * 22041 * <p>The feedback will only be performed if 22042 * {@link #isHapticFeedbackEnabled()} is true. 22043 * 22044 * @param feedbackConstant One of the constants defined in 22045 * {@link HapticFeedbackConstants} 22046 */ 22047 public boolean performHapticFeedback(int feedbackConstant) { 22048 return performHapticFeedback(feedbackConstant, 0); 22049 } 22050 22051 /** 22052 * BZZZTT!!1! 22053 * 22054 * <p>Like {@link #performHapticFeedback(int)}, with additional options. 22055 * 22056 * @param feedbackConstant One of the constants defined in 22057 * {@link HapticFeedbackConstants} 22058 * @param flags Additional flags as per {@link HapticFeedbackConstants}. 22059 */ 22060 public boolean performHapticFeedback(int feedbackConstant, int flags) { 22061 if (mAttachInfo == null) { 22062 return false; 22063 } 22064 //noinspection SimplifiableIfStatement 22065 if ((flags & HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING) == 0 22066 && !isHapticFeedbackEnabled()) { 22067 return false; 22068 } 22069 return mAttachInfo.mRootCallbacks.performHapticFeedback(feedbackConstant, 22070 (flags & HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING) != 0); 22071 } 22072 22073 /** 22074 * Request that the visibility of the status bar or other screen/window 22075 * decorations be changed. 22076 * 22077 * <p>This method is used to put the over device UI into temporary modes 22078 * where the user's attention is focused more on the application content, 22079 * by dimming or hiding surrounding system affordances. This is typically 22080 * used in conjunction with {@link Window#FEATURE_ACTION_BAR_OVERLAY 22081 * Window.FEATURE_ACTION_BAR_OVERLAY}, allowing the applications content 22082 * to be placed behind the action bar (and with these flags other system 22083 * affordances) so that smooth transitions between hiding and showing them 22084 * can be done. 22085 * 22086 * <p>Two representative examples of the use of system UI visibility is 22087 * implementing a content browsing application (like a magazine reader) 22088 * and a video playing application. 22089 * 22090 * <p>The first code shows a typical implementation of a View in a content 22091 * browsing application. In this implementation, the application goes 22092 * into a content-oriented mode by hiding the status bar and action bar, 22093 * and putting the navigation elements into lights out mode. The user can 22094 * then interact with content while in this mode. Such an application should 22095 * provide an easy way for the user to toggle out of the mode (such as to 22096 * check information in the status bar or access notifications). In the 22097 * implementation here, this is done simply by tapping on the content. 22098 * 22099 * {@sample development/samples/ApiDemos/src/com/example/android/apis/view/ContentBrowserActivity.java 22100 * content} 22101 * 22102 * <p>This second code sample shows a typical implementation of a View 22103 * in a video playing application. In this situation, while the video is 22104 * playing the application would like to go into a complete full-screen mode, 22105 * to use as much of the display as possible for the video. When in this state 22106 * the user can not interact with the application; the system intercepts 22107 * touching on the screen to pop the UI out of full screen mode. See 22108 * {@link #fitSystemWindows(Rect)} for a sample layout that goes with this code. 22109 * 22110 * {@sample development/samples/ApiDemos/src/com/example/android/apis/view/VideoPlayerActivity.java 22111 * content} 22112 * 22113 * @param visibility Bitwise-or of flags {@link #SYSTEM_UI_FLAG_LOW_PROFILE}, 22114 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, {@link #SYSTEM_UI_FLAG_FULLSCREEN}, 22115 * {@link #SYSTEM_UI_FLAG_LAYOUT_STABLE}, {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION}, 22116 * {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN}, {@link #SYSTEM_UI_FLAG_IMMERSIVE}, 22117 * and {@link #SYSTEM_UI_FLAG_IMMERSIVE_STICKY}. 22118 */ 22119 public void setSystemUiVisibility(int visibility) { 22120 if (visibility != mSystemUiVisibility) { 22121 mSystemUiVisibility = visibility; 22122 if (mParent != null && mAttachInfo != null && !mAttachInfo.mRecomputeGlobalAttributes) { 22123 mParent.recomputeViewAttributes(this); 22124 } 22125 } 22126 } 22127 22128 /** 22129 * Returns the last {@link #setSystemUiVisibility(int)} that this view has requested. 22130 * @return Bitwise-or of flags {@link #SYSTEM_UI_FLAG_LOW_PROFILE}, 22131 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, {@link #SYSTEM_UI_FLAG_FULLSCREEN}, 22132 * {@link #SYSTEM_UI_FLAG_LAYOUT_STABLE}, {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION}, 22133 * {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN}, {@link #SYSTEM_UI_FLAG_IMMERSIVE}, 22134 * and {@link #SYSTEM_UI_FLAG_IMMERSIVE_STICKY}. 22135 */ 22136 public int getSystemUiVisibility() { 22137 return mSystemUiVisibility; 22138 } 22139 22140 /** 22141 * Returns the current system UI visibility that is currently set for 22142 * the entire window. This is the combination of the 22143 * {@link #setSystemUiVisibility(int)} values supplied by all of the 22144 * views in the window. 22145 */ 22146 public int getWindowSystemUiVisibility() { 22147 return mAttachInfo != null ? mAttachInfo.mSystemUiVisibility : 0; 22148 } 22149 22150 /** 22151 * Override to find out when the window's requested system UI visibility 22152 * has changed, that is the value returned by {@link #getWindowSystemUiVisibility()}. 22153 * This is different from the callbacks received through 22154 * {@link #setOnSystemUiVisibilityChangeListener(OnSystemUiVisibilityChangeListener)} 22155 * in that this is only telling you about the local request of the window, 22156 * not the actual values applied by the system. 22157 */ 22158 public void onWindowSystemUiVisibilityChanged(int visible) { 22159 } 22160 22161 /** 22162 * Dispatch callbacks to {@link #onWindowSystemUiVisibilityChanged(int)} down 22163 * the view hierarchy. 22164 */ 22165 public void dispatchWindowSystemUiVisiblityChanged(int visible) { 22166 onWindowSystemUiVisibilityChanged(visible); 22167 } 22168 22169 /** 22170 * Set a listener to receive callbacks when the visibility of the system bar changes. 22171 * @param l The {@link OnSystemUiVisibilityChangeListener} to receive callbacks. 22172 */ 22173 public void setOnSystemUiVisibilityChangeListener(OnSystemUiVisibilityChangeListener l) { 22174 getListenerInfo().mOnSystemUiVisibilityChangeListener = l; 22175 if (mParent != null && mAttachInfo != null && !mAttachInfo.mRecomputeGlobalAttributes) { 22176 mParent.recomputeViewAttributes(this); 22177 } 22178 } 22179 22180 /** 22181 * Dispatch callbacks to {@link #setOnSystemUiVisibilityChangeListener} down 22182 * the view hierarchy. 22183 */ 22184 public void dispatchSystemUiVisibilityChanged(int visibility) { 22185 ListenerInfo li = mListenerInfo; 22186 if (li != null && li.mOnSystemUiVisibilityChangeListener != null) { 22187 li.mOnSystemUiVisibilityChangeListener.onSystemUiVisibilityChange( 22188 visibility & PUBLIC_STATUS_BAR_VISIBILITY_MASK); 22189 } 22190 } 22191 22192 boolean updateLocalSystemUiVisibility(int localValue, int localChanges) { 22193 int val = (mSystemUiVisibility&~localChanges) | (localValue&localChanges); 22194 if (val != mSystemUiVisibility) { 22195 setSystemUiVisibility(val); 22196 return true; 22197 } 22198 return false; 22199 } 22200 22201 /** @hide */ 22202 public void setDisabledSystemUiVisibility(int flags) { 22203 if (mAttachInfo != null) { 22204 if (mAttachInfo.mDisabledSystemUiVisibility != flags) { 22205 mAttachInfo.mDisabledSystemUiVisibility = flags; 22206 if (mParent != null) { 22207 mParent.recomputeViewAttributes(this); 22208 } 22209 } 22210 } 22211 } 22212 22213 /** 22214 * Creates an image that the system displays during the drag and drop 22215 * operation. This is called a "drag shadow". The default implementation 22216 * for a DragShadowBuilder based on a View returns an image that has exactly the same 22217 * appearance as the given View. The default also positions the center of the drag shadow 22218 * directly under the touch point. If no View is provided (the constructor with no parameters 22219 * is used), and {@link #onProvideShadowMetrics(Point,Point) onProvideShadowMetrics()} and 22220 * {@link #onDrawShadow(Canvas) onDrawShadow()} are not overridden, then the 22221 * default is an invisible drag shadow. 22222 * <p> 22223 * You are not required to use the View you provide to the constructor as the basis of the 22224 * drag shadow. The {@link #onDrawShadow(Canvas) onDrawShadow()} method allows you to draw 22225 * anything you want as the drag shadow. 22226 * </p> 22227 * <p> 22228 * You pass a DragShadowBuilder object to the system when you start the drag. The system 22229 * calls {@link #onProvideShadowMetrics(Point,Point) onProvideShadowMetrics()} to get the 22230 * size and position of the drag shadow. It uses this data to construct a 22231 * {@link android.graphics.Canvas} object, then it calls {@link #onDrawShadow(Canvas) onDrawShadow()} 22232 * so that your application can draw the shadow image in the Canvas. 22233 * </p> 22234 * 22235 * <div class="special reference"> 22236 * <h3>Developer Guides</h3> 22237 * <p>For a guide to implementing drag and drop features, read the 22238 * <a href="{@docRoot}guide/topics/ui/drag-drop.html">Drag and Drop</a> developer guide.</p> 22239 * </div> 22240 */ 22241 public static class DragShadowBuilder { 22242 private final WeakReference<View> mView; 22243 22244 /** 22245 * Constructs a shadow image builder based on a View. By default, the resulting drag 22246 * shadow will have the same appearance and dimensions as the View, with the touch point 22247 * over the center of the View. 22248 * @param view A View. Any View in scope can be used. 22249 */ 22250 public DragShadowBuilder(View view) { 22251 mView = new WeakReference<View>(view); 22252 } 22253 22254 /** 22255 * Construct a shadow builder object with no associated View. This 22256 * constructor variant is only useful when the {@link #onProvideShadowMetrics(Point, Point)} 22257 * and {@link #onDrawShadow(Canvas)} methods are also overridden in order 22258 * to supply the drag shadow's dimensions and appearance without 22259 * reference to any View object. If they are not overridden, then the result is an 22260 * invisible drag shadow. 22261 */ 22262 public DragShadowBuilder() { 22263 mView = new WeakReference<View>(null); 22264 } 22265 22266 /** 22267 * Returns the View object that had been passed to the 22268 * {@link #View.DragShadowBuilder(View)} 22269 * constructor. If that View parameter was {@code null} or if the 22270 * {@link #View.DragShadowBuilder()} 22271 * constructor was used to instantiate the builder object, this method will return 22272 * null. 22273 * 22274 * @return The View object associate with this builder object. 22275 */ 22276 @SuppressWarnings({"JavadocReference"}) 22277 final public View getView() { 22278 return mView.get(); 22279 } 22280 22281 /** 22282 * Provides the metrics for the shadow image. These include the dimensions of 22283 * the shadow image, and the point within that shadow that should 22284 * be centered under the touch location while dragging. 22285 * <p> 22286 * The default implementation sets the dimensions of the shadow to be the 22287 * same as the dimensions of the View itself and centers the shadow under 22288 * the touch point. 22289 * </p> 22290 * 22291 * @param outShadowSize A {@link android.graphics.Point} containing the width and height 22292 * of the shadow image. Your application must set {@link android.graphics.Point#x} to the 22293 * desired width and must set {@link android.graphics.Point#y} to the desired height of the 22294 * image. 22295 * 22296 * @param outShadowTouchPoint A {@link android.graphics.Point} for the position within the 22297 * shadow image that should be underneath the touch point during the drag and drop 22298 * operation. Your application must set {@link android.graphics.Point#x} to the 22299 * X coordinate and {@link android.graphics.Point#y} to the Y coordinate of this position. 22300 */ 22301 public void onProvideShadowMetrics(Point outShadowSize, Point outShadowTouchPoint) { 22302 final View view = mView.get(); 22303 if (view != null) { 22304 outShadowSize.set(view.getWidth(), view.getHeight()); 22305 outShadowTouchPoint.set(outShadowSize.x / 2, outShadowSize.y / 2); 22306 } else { 22307 Log.e(View.VIEW_LOG_TAG, "Asked for drag thumb metrics but no view"); 22308 } 22309 } 22310 22311 /** 22312 * Draws the shadow image. The system creates the {@link android.graphics.Canvas} object 22313 * based on the dimensions it received from the 22314 * {@link #onProvideShadowMetrics(Point, Point)} callback. 22315 * 22316 * @param canvas A {@link android.graphics.Canvas} object in which to draw the shadow image. 22317 */ 22318 public void onDrawShadow(Canvas canvas) { 22319 final View view = mView.get(); 22320 if (view != null) { 22321 view.draw(canvas); 22322 } else { 22323 Log.e(View.VIEW_LOG_TAG, "Asked to draw drag shadow but no view"); 22324 } 22325 } 22326 } 22327 22328 /** 22329 * @deprecated Use {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, int) 22330 * startDragAndDrop()} for newer platform versions. 22331 */ 22332 @Deprecated 22333 public final boolean startDrag(ClipData data, DragShadowBuilder shadowBuilder, 22334 Object myLocalState, int flags) { 22335 return startDragAndDrop(data, shadowBuilder, myLocalState, flags); 22336 } 22337 22338 /** 22339 * Starts a drag and drop operation. When your application calls this method, it passes a 22340 * {@link android.view.View.DragShadowBuilder} object to the system. The 22341 * system calls this object's {@link DragShadowBuilder#onProvideShadowMetrics(Point, Point)} 22342 * to get metrics for the drag shadow, and then calls the object's 22343 * {@link DragShadowBuilder#onDrawShadow(Canvas)} to draw the drag shadow itself. 22344 * <p> 22345 * Once the system has the drag shadow, it begins the drag and drop operation by sending 22346 * drag events to all the View objects in your application that are currently visible. It does 22347 * this either by calling the View object's drag listener (an implementation of 22348 * {@link android.view.View.OnDragListener#onDrag(View,DragEvent) onDrag()} or by calling the 22349 * View object's {@link android.view.View#onDragEvent(DragEvent) onDragEvent()} method. 22350 * Both are passed a {@link android.view.DragEvent} object that has a 22351 * {@link android.view.DragEvent#getAction()} value of 22352 * {@link android.view.DragEvent#ACTION_DRAG_STARTED}. 22353 * </p> 22354 * <p> 22355 * Your application can invoke {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, 22356 * int) startDragAndDrop()} on any attached View object. The View object does not need to be 22357 * the one used in {@link android.view.View.DragShadowBuilder}, nor does it need to be related 22358 * to the View the user selected for dragging. 22359 * </p> 22360 * @param data A {@link android.content.ClipData} object pointing to the data to be 22361 * transferred by the drag and drop operation. 22362 * @param shadowBuilder A {@link android.view.View.DragShadowBuilder} object for building the 22363 * drag shadow. 22364 * @param myLocalState An {@link java.lang.Object} containing local data about the drag and 22365 * drop operation. When dispatching drag events to views in the same activity this object 22366 * will be available through {@link android.view.DragEvent#getLocalState()}. Views in other 22367 * activities will not have access to this data ({@link android.view.DragEvent#getLocalState()} 22368 * will return null). 22369 * <p> 22370 * myLocalState is a lightweight mechanism for the sending information from the dragged View 22371 * to the target Views. For example, it can contain flags that differentiate between a 22372 * a copy operation and a move operation. 22373 * </p> 22374 * @param flags Flags that control the drag and drop operation. This can be set to 0 for no 22375 * flags, or any combination of the following: 22376 * <ul> 22377 * <li>{@link #DRAG_FLAG_GLOBAL}</li> 22378 * <li>{@link #DRAG_FLAG_GLOBAL_PERSISTABLE_URI_PERMISSION}</li> 22379 * <li>{@link #DRAG_FLAG_GLOBAL_PREFIX_URI_PERMISSION}</li> 22380 * <li>{@link #DRAG_FLAG_GLOBAL_URI_READ}</li> 22381 * <li>{@link #DRAG_FLAG_GLOBAL_URI_WRITE}</li> 22382 * <li>{@link #DRAG_FLAG_OPAQUE}</li> 22383 * </ul> 22384 * @return {@code true} if the method completes successfully, or 22385 * {@code false} if it fails anywhere. Returning {@code false} means the system was unable to 22386 * do a drag, and so no drag operation is in progress. 22387 */ 22388 public final boolean startDragAndDrop(ClipData data, DragShadowBuilder shadowBuilder, 22389 Object myLocalState, int flags) { 22390 if (ViewDebug.DEBUG_DRAG) { 22391 Log.d(VIEW_LOG_TAG, "startDragAndDrop: data=" + data + " flags=" + flags); 22392 } 22393 if (mAttachInfo == null) { 22394 Log.w(VIEW_LOG_TAG, "startDragAndDrop called on a detached view."); 22395 return false; 22396 } 22397 22398 if (data != null) { 22399 data.prepareToLeaveProcess((flags & View.DRAG_FLAG_GLOBAL) != 0); 22400 } 22401 22402 boolean okay = false; 22403 22404 Point shadowSize = new Point(); 22405 Point shadowTouchPoint = new Point(); 22406 shadowBuilder.onProvideShadowMetrics(shadowSize, shadowTouchPoint); 22407 22408 if ((shadowSize.x < 0) || (shadowSize.y < 0) || 22409 (shadowTouchPoint.x < 0) || (shadowTouchPoint.y < 0)) { 22410 throw new IllegalStateException("Drag shadow dimensions must not be negative"); 22411 } 22412 22413 if (ViewDebug.DEBUG_DRAG) { 22414 Log.d(VIEW_LOG_TAG, "drag shadow: width=" + shadowSize.x + " height=" + shadowSize.y 22415 + " shadowX=" + shadowTouchPoint.x + " shadowY=" + shadowTouchPoint.y); 22416 } 22417 if (mAttachInfo.mDragSurface != null) { 22418 mAttachInfo.mDragSurface.release(); 22419 } 22420 mAttachInfo.mDragSurface = new Surface(); 22421 try { 22422 mAttachInfo.mDragToken = mAttachInfo.mSession.prepareDrag(mAttachInfo.mWindow, 22423 flags, shadowSize.x, shadowSize.y, mAttachInfo.mDragSurface); 22424 if (ViewDebug.DEBUG_DRAG) Log.d(VIEW_LOG_TAG, "prepareDrag returned token=" 22425 + mAttachInfo.mDragToken + " surface=" + mAttachInfo.mDragSurface); 22426 if (mAttachInfo.mDragToken != null) { 22427 Canvas canvas = mAttachInfo.mDragSurface.lockCanvas(null); 22428 try { 22429 canvas.drawColor(0, PorterDuff.Mode.CLEAR); 22430 shadowBuilder.onDrawShadow(canvas); 22431 } finally { 22432 mAttachInfo.mDragSurface.unlockCanvasAndPost(canvas); 22433 } 22434 22435 final ViewRootImpl root = getViewRootImpl(); 22436 22437 // Cache the local state object for delivery with DragEvents 22438 root.setLocalDragState(myLocalState); 22439 22440 // repurpose 'shadowSize' for the last touch point 22441 root.getLastTouchPoint(shadowSize); 22442 22443 okay = mAttachInfo.mSession.performDrag(mAttachInfo.mWindow, mAttachInfo.mDragToken, 22444 root.getLastTouchSource(), shadowSize.x, shadowSize.y, 22445 shadowTouchPoint.x, shadowTouchPoint.y, data); 22446 if (ViewDebug.DEBUG_DRAG) Log.d(VIEW_LOG_TAG, "performDrag returned " + okay); 22447 } 22448 } catch (Exception e) { 22449 Log.e(VIEW_LOG_TAG, "Unable to initiate drag", e); 22450 mAttachInfo.mDragSurface.destroy(); 22451 mAttachInfo.mDragSurface = null; 22452 } 22453 22454 return okay; 22455 } 22456 22457 /** 22458 * Cancels an ongoing drag and drop operation. 22459 * <p> 22460 * A {@link android.view.DragEvent} object with 22461 * {@link android.view.DragEvent#getAction()} value of 22462 * {@link android.view.DragEvent#ACTION_DRAG_ENDED} and 22463 * {@link android.view.DragEvent#getResult()} value of {@code false} 22464 * will be sent to every 22465 * View that received {@link android.view.DragEvent#ACTION_DRAG_STARTED} 22466 * even if they are not currently visible. 22467 * </p> 22468 * <p> 22469 * This method can be called on any View in the same window as the View on which 22470 * {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, int) startDragAndDrop} 22471 * was called. 22472 * </p> 22473 */ 22474 public final void cancelDragAndDrop() { 22475 if (ViewDebug.DEBUG_DRAG) { 22476 Log.d(VIEW_LOG_TAG, "cancelDragAndDrop"); 22477 } 22478 if (mAttachInfo == null) { 22479 Log.w(VIEW_LOG_TAG, "cancelDragAndDrop called on a detached view."); 22480 return; 22481 } 22482 if (mAttachInfo.mDragToken != null) { 22483 try { 22484 mAttachInfo.mSession.cancelDragAndDrop(mAttachInfo.mDragToken); 22485 } catch (Exception e) { 22486 Log.e(VIEW_LOG_TAG, "Unable to cancel drag", e); 22487 } 22488 mAttachInfo.mDragToken = null; 22489 } else { 22490 Log.e(VIEW_LOG_TAG, "No active drag to cancel"); 22491 } 22492 } 22493 22494 /** 22495 * Updates the drag shadow for the ongoing drag and drop operation. 22496 * 22497 * @param shadowBuilder A {@link android.view.View.DragShadowBuilder} object for building the 22498 * new drag shadow. 22499 */ 22500 public final void updateDragShadow(DragShadowBuilder shadowBuilder) { 22501 if (ViewDebug.DEBUG_DRAG) { 22502 Log.d(VIEW_LOG_TAG, "updateDragShadow"); 22503 } 22504 if (mAttachInfo == null) { 22505 Log.w(VIEW_LOG_TAG, "updateDragShadow called on a detached view."); 22506 return; 22507 } 22508 if (mAttachInfo.mDragToken != null) { 22509 try { 22510 Canvas canvas = mAttachInfo.mDragSurface.lockCanvas(null); 22511 try { 22512 canvas.drawColor(0, PorterDuff.Mode.CLEAR); 22513 shadowBuilder.onDrawShadow(canvas); 22514 } finally { 22515 mAttachInfo.mDragSurface.unlockCanvasAndPost(canvas); 22516 } 22517 } catch (Exception e) { 22518 Log.e(VIEW_LOG_TAG, "Unable to update drag shadow", e); 22519 } 22520 } else { 22521 Log.e(VIEW_LOG_TAG, "No active drag"); 22522 } 22523 } 22524 22525 /** 22526 * Starts a move from {startX, startY}, the amount of the movement will be the offset 22527 * between {startX, startY} and the new cursor positon. 22528 * @param startX horizontal coordinate where the move started. 22529 * @param startY vertical coordinate where the move started. 22530 * @return whether moving was started successfully. 22531 * @hide 22532 */ 22533 public final boolean startMovingTask(float startX, float startY) { 22534 if (ViewDebug.DEBUG_POSITIONING) { 22535 Log.d(VIEW_LOG_TAG, "startMovingTask: {" + startX + "," + startY + "}"); 22536 } 22537 try { 22538 return mAttachInfo.mSession.startMovingTask(mAttachInfo.mWindow, startX, startY); 22539 } catch (RemoteException e) { 22540 Log.e(VIEW_LOG_TAG, "Unable to start moving", e); 22541 } 22542 return false; 22543 } 22544 22545 /** 22546 * Handles drag events sent by the system following a call to 22547 * {@link android.view.View#startDragAndDrop(ClipData,DragShadowBuilder,Object,int) 22548 * startDragAndDrop()}. 22549 *<p> 22550 * When the system calls this method, it passes a 22551 * {@link android.view.DragEvent} object. A call to 22552 * {@link android.view.DragEvent#getAction()} returns one of the action type constants defined 22553 * in DragEvent. The method uses these to determine what is happening in the drag and drop 22554 * operation. 22555 * @param event The {@link android.view.DragEvent} sent by the system. 22556 * The {@link android.view.DragEvent#getAction()} method returns an action type constant defined 22557 * in DragEvent, indicating the type of drag event represented by this object. 22558 * @return {@code true} if the method was successful, otherwise {@code false}. 22559 * <p> 22560 * The method should return {@code true} in response to an action type of 22561 * {@link android.view.DragEvent#ACTION_DRAG_STARTED} to receive drag events for the current 22562 * operation. 22563 * </p> 22564 * <p> 22565 * The method should also return {@code true} in response to an action type of 22566 * {@link android.view.DragEvent#ACTION_DROP} if it consumed the drop, or 22567 * {@code false} if it didn't. 22568 * </p> 22569 * <p> 22570 * For all other events, the return value is ignored. 22571 * </p> 22572 */ 22573 public boolean onDragEvent(DragEvent event) { 22574 return false; 22575 } 22576 22577 // Dispatches ACTION_DRAG_ENTERED and ACTION_DRAG_EXITED events for pre-Nougat apps. 22578 boolean dispatchDragEnterExitInPreN(DragEvent event) { 22579 return callDragEventHandler(event); 22580 } 22581 22582 /** 22583 * Detects if this View is enabled and has a drag event listener. 22584 * If both are true, then it calls the drag event listener with the 22585 * {@link android.view.DragEvent} it received. If the drag event listener returns 22586 * {@code true}, then dispatchDragEvent() returns {@code true}. 22587 * <p> 22588 * For all other cases, the method calls the 22589 * {@link android.view.View#onDragEvent(DragEvent) onDragEvent()} drag event handler 22590 * method and returns its result. 22591 * </p> 22592 * <p> 22593 * This ensures that a drag event is always consumed, even if the View does not have a drag 22594 * event listener. However, if the View has a listener and the listener returns true, then 22595 * onDragEvent() is not called. 22596 * </p> 22597 */ 22598 public boolean dispatchDragEvent(DragEvent event) { 22599 event.mEventHandlerWasCalled = true; 22600 if (event.mAction == DragEvent.ACTION_DRAG_LOCATION || 22601 event.mAction == DragEvent.ACTION_DROP) { 22602 // About to deliver an event with coordinates to this view. Notify that now this view 22603 // has drag focus. This will send exit/enter events as needed. 22604 getViewRootImpl().setDragFocus(this, event); 22605 } 22606 return callDragEventHandler(event); 22607 } 22608 22609 final boolean callDragEventHandler(DragEvent event) { 22610 final boolean result; 22611 22612 ListenerInfo li = mListenerInfo; 22613 //noinspection SimplifiableIfStatement 22614 if (li != null && li.mOnDragListener != null && (mViewFlags & ENABLED_MASK) == ENABLED 22615 && li.mOnDragListener.onDrag(this, event)) { 22616 result = true; 22617 } else { 22618 result = onDragEvent(event); 22619 } 22620 22621 switch (event.mAction) { 22622 case DragEvent.ACTION_DRAG_ENTERED: { 22623 mPrivateFlags2 |= View.PFLAG2_DRAG_HOVERED; 22624 refreshDrawableState(); 22625 } break; 22626 case DragEvent.ACTION_DRAG_EXITED: { 22627 mPrivateFlags2 &= ~View.PFLAG2_DRAG_HOVERED; 22628 refreshDrawableState(); 22629 } break; 22630 case DragEvent.ACTION_DRAG_ENDED: { 22631 mPrivateFlags2 &= ~View.DRAG_MASK; 22632 refreshDrawableState(); 22633 } break; 22634 } 22635 22636 return result; 22637 } 22638 22639 boolean canAcceptDrag() { 22640 return (mPrivateFlags2 & PFLAG2_DRAG_CAN_ACCEPT) != 0; 22641 } 22642 22643 /** 22644 * This needs to be a better API (NOT ON VIEW) before it is exposed. If 22645 * it is ever exposed at all. 22646 * @hide 22647 */ 22648 public void onCloseSystemDialogs(String reason) { 22649 } 22650 22651 /** 22652 * Given a Drawable whose bounds have been set to draw into this view, 22653 * update a Region being computed for 22654 * {@link #gatherTransparentRegion(android.graphics.Region)} so 22655 * that any non-transparent parts of the Drawable are removed from the 22656 * given transparent region. 22657 * 22658 * @param dr The Drawable whose transparency is to be applied to the region. 22659 * @param region A Region holding the current transparency information, 22660 * where any parts of the region that are set are considered to be 22661 * transparent. On return, this region will be modified to have the 22662 * transparency information reduced by the corresponding parts of the 22663 * Drawable that are not transparent. 22664 * {@hide} 22665 */ 22666 public void applyDrawableToTransparentRegion(Drawable dr, Region region) { 22667 if (DBG) { 22668 Log.i("View", "Getting transparent region for: " + this); 22669 } 22670 final Region r = dr.getTransparentRegion(); 22671 final Rect db = dr.getBounds(); 22672 final AttachInfo attachInfo = mAttachInfo; 22673 if (r != null && attachInfo != null) { 22674 final int w = getRight()-getLeft(); 22675 final int h = getBottom()-getTop(); 22676 if (db.left > 0) { 22677 //Log.i("VIEW", "Drawable left " + db.left + " > view 0"); 22678 r.op(0, 0, db.left, h, Region.Op.UNION); 22679 } 22680 if (db.right < w) { 22681 //Log.i("VIEW", "Drawable right " + db.right + " < view " + w); 22682 r.op(db.right, 0, w, h, Region.Op.UNION); 22683 } 22684 if (db.top > 0) { 22685 //Log.i("VIEW", "Drawable top " + db.top + " > view 0"); 22686 r.op(0, 0, w, db.top, Region.Op.UNION); 22687 } 22688 if (db.bottom < h) { 22689 //Log.i("VIEW", "Drawable bottom " + db.bottom + " < view " + h); 22690 r.op(0, db.bottom, w, h, Region.Op.UNION); 22691 } 22692 final int[] location = attachInfo.mTransparentLocation; 22693 getLocationInWindow(location); 22694 r.translate(location[0], location[1]); 22695 region.op(r, Region.Op.INTERSECT); 22696 } else { 22697 region.op(db, Region.Op.DIFFERENCE); 22698 } 22699 } 22700 22701 private void checkForLongClick(int delayOffset, float x, float y) { 22702 if ((mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE || (mViewFlags & TOOLTIP) == TOOLTIP) { 22703 mHasPerformedLongPress = false; 22704 22705 if (mPendingCheckForLongPress == null) { 22706 mPendingCheckForLongPress = new CheckForLongPress(); 22707 } 22708 mPendingCheckForLongPress.setAnchor(x, y); 22709 mPendingCheckForLongPress.rememberWindowAttachCount(); 22710 mPendingCheckForLongPress.rememberPressedState(); 22711 postDelayed(mPendingCheckForLongPress, 22712 ViewConfiguration.getLongPressTimeout() - delayOffset); 22713 } 22714 } 22715 22716 /** 22717 * Inflate a view from an XML resource. This convenience method wraps the {@link 22718 * LayoutInflater} class, which provides a full range of options for view inflation. 22719 * 22720 * @param context The Context object for your activity or application. 22721 * @param resource The resource ID to inflate 22722 * @param root A view group that will be the parent. Used to properly inflate the 22723 * layout_* parameters. 22724 * @see LayoutInflater 22725 */ 22726 public static View inflate(Context context, @LayoutRes int resource, ViewGroup root) { 22727 LayoutInflater factory = LayoutInflater.from(context); 22728 return factory.inflate(resource, root); 22729 } 22730 22731 /** 22732 * Scroll the view with standard behavior for scrolling beyond the normal 22733 * content boundaries. Views that call this method should override 22734 * {@link #onOverScrolled(int, int, boolean, boolean)} to respond to the 22735 * results of an over-scroll operation. 22736 * 22737 * Views can use this method to handle any touch or fling-based scrolling. 22738 * 22739 * @param deltaX Change in X in pixels 22740 * @param deltaY Change in Y in pixels 22741 * @param scrollX Current X scroll value in pixels before applying deltaX 22742 * @param scrollY Current Y scroll value in pixels before applying deltaY 22743 * @param scrollRangeX Maximum content scroll range along the X axis 22744 * @param scrollRangeY Maximum content scroll range along the Y axis 22745 * @param maxOverScrollX Number of pixels to overscroll by in either direction 22746 * along the X axis. 22747 * @param maxOverScrollY Number of pixels to overscroll by in either direction 22748 * along the Y axis. 22749 * @param isTouchEvent true if this scroll operation is the result of a touch event. 22750 * @return true if scrolling was clamped to an over-scroll boundary along either 22751 * axis, false otherwise. 22752 */ 22753 @SuppressWarnings({"UnusedParameters"}) 22754 protected boolean overScrollBy(int deltaX, int deltaY, 22755 int scrollX, int scrollY, 22756 int scrollRangeX, int scrollRangeY, 22757 int maxOverScrollX, int maxOverScrollY, 22758 boolean isTouchEvent) { 22759 final int overScrollMode = mOverScrollMode; 22760 final boolean canScrollHorizontal = 22761 computeHorizontalScrollRange() > computeHorizontalScrollExtent(); 22762 final boolean canScrollVertical = 22763 computeVerticalScrollRange() > computeVerticalScrollExtent(); 22764 final boolean overScrollHorizontal = overScrollMode == OVER_SCROLL_ALWAYS || 22765 (overScrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && canScrollHorizontal); 22766 final boolean overScrollVertical = overScrollMode == OVER_SCROLL_ALWAYS || 22767 (overScrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && canScrollVertical); 22768 22769 int newScrollX = scrollX + deltaX; 22770 if (!overScrollHorizontal) { 22771 maxOverScrollX = 0; 22772 } 22773 22774 int newScrollY = scrollY + deltaY; 22775 if (!overScrollVertical) { 22776 maxOverScrollY = 0; 22777 } 22778 22779 // Clamp values if at the limits and record 22780 final int left = -maxOverScrollX; 22781 final int right = maxOverScrollX + scrollRangeX; 22782 final int top = -maxOverScrollY; 22783 final int bottom = maxOverScrollY + scrollRangeY; 22784 22785 boolean clampedX = false; 22786 if (newScrollX > right) { 22787 newScrollX = right; 22788 clampedX = true; 22789 } else if (newScrollX < left) { 22790 newScrollX = left; 22791 clampedX = true; 22792 } 22793 22794 boolean clampedY = false; 22795 if (newScrollY > bottom) { 22796 newScrollY = bottom; 22797 clampedY = true; 22798 } else if (newScrollY < top) { 22799 newScrollY = top; 22800 clampedY = true; 22801 } 22802 22803 onOverScrolled(newScrollX, newScrollY, clampedX, clampedY); 22804 22805 return clampedX || clampedY; 22806 } 22807 22808 /** 22809 * Called by {@link #overScrollBy(int, int, int, int, int, int, int, int, boolean)} to 22810 * respond to the results of an over-scroll operation. 22811 * 22812 * @param scrollX New X scroll value in pixels 22813 * @param scrollY New Y scroll value in pixels 22814 * @param clampedX True if scrollX was clamped to an over-scroll boundary 22815 * @param clampedY True if scrollY was clamped to an over-scroll boundary 22816 */ 22817 protected void onOverScrolled(int scrollX, int scrollY, 22818 boolean clampedX, boolean clampedY) { 22819 // Intentionally empty. 22820 } 22821 22822 /** 22823 * Returns the over-scroll mode for this view. The result will be 22824 * one of {@link #OVER_SCROLL_ALWAYS} (default), {@link #OVER_SCROLL_IF_CONTENT_SCROLLS} 22825 * (allow over-scrolling only if the view content is larger than the container), 22826 * or {@link #OVER_SCROLL_NEVER}. 22827 * 22828 * @return This view's over-scroll mode. 22829 */ 22830 public int getOverScrollMode() { 22831 return mOverScrollMode; 22832 } 22833 22834 /** 22835 * Set the over-scroll mode for this view. Valid over-scroll modes are 22836 * {@link #OVER_SCROLL_ALWAYS} (default), {@link #OVER_SCROLL_IF_CONTENT_SCROLLS} 22837 * (allow over-scrolling only if the view content is larger than the container), 22838 * or {@link #OVER_SCROLL_NEVER}. 22839 * 22840 * Setting the over-scroll mode of a view will have an effect only if the 22841 * view is capable of scrolling. 22842 * 22843 * @param overScrollMode The new over-scroll mode for this view. 22844 */ 22845 public void setOverScrollMode(int overScrollMode) { 22846 if (overScrollMode != OVER_SCROLL_ALWAYS && 22847 overScrollMode != OVER_SCROLL_IF_CONTENT_SCROLLS && 22848 overScrollMode != OVER_SCROLL_NEVER) { 22849 throw new IllegalArgumentException("Invalid overscroll mode " + overScrollMode); 22850 } 22851 mOverScrollMode = overScrollMode; 22852 } 22853 22854 /** 22855 * Enable or disable nested scrolling for this view. 22856 * 22857 * <p>If this property is set to true the view will be permitted to initiate nested 22858 * scrolling operations with a compatible parent view in the current hierarchy. If this 22859 * view does not implement nested scrolling this will have no effect. Disabling nested scrolling 22860 * while a nested scroll is in progress has the effect of {@link #stopNestedScroll() stopping} 22861 * the nested scroll.</p> 22862 * 22863 * @param enabled true to enable nested scrolling, false to disable 22864 * 22865 * @see #isNestedScrollingEnabled() 22866 */ 22867 public void setNestedScrollingEnabled(boolean enabled) { 22868 if (enabled) { 22869 mPrivateFlags3 |= PFLAG3_NESTED_SCROLLING_ENABLED; 22870 } else { 22871 stopNestedScroll(); 22872 mPrivateFlags3 &= ~PFLAG3_NESTED_SCROLLING_ENABLED; 22873 } 22874 } 22875 22876 /** 22877 * Returns true if nested scrolling is enabled for this view. 22878 * 22879 * <p>If nested scrolling is enabled and this View class implementation supports it, 22880 * this view will act as a nested scrolling child view when applicable, forwarding data 22881 * about the scroll operation in progress to a compatible and cooperating nested scrolling 22882 * parent.</p> 22883 * 22884 * @return true if nested scrolling is enabled 22885 * 22886 * @see #setNestedScrollingEnabled(boolean) 22887 */ 22888 public boolean isNestedScrollingEnabled() { 22889 return (mPrivateFlags3 & PFLAG3_NESTED_SCROLLING_ENABLED) == 22890 PFLAG3_NESTED_SCROLLING_ENABLED; 22891 } 22892 22893 /** 22894 * Begin a nestable scroll operation along the given axes. 22895 * 22896 * <p>A view starting a nested scroll promises to abide by the following contract:</p> 22897 * 22898 * <p>The view will call startNestedScroll upon initiating a scroll operation. In the case 22899 * of a touch scroll this corresponds to the initial {@link MotionEvent#ACTION_DOWN}. 22900 * In the case of touch scrolling the nested scroll will be terminated automatically in 22901 * the same manner as {@link ViewParent#requestDisallowInterceptTouchEvent(boolean)}. 22902 * In the event of programmatic scrolling the caller must explicitly call 22903 * {@link #stopNestedScroll()} to indicate the end of the nested scroll.</p> 22904 * 22905 * <p>If <code>startNestedScroll</code> returns true, a cooperative parent was found. 22906 * If it returns false the caller may ignore the rest of this contract until the next scroll. 22907 * Calling startNestedScroll while a nested scroll is already in progress will return true.</p> 22908 * 22909 * <p>At each incremental step of the scroll the caller should invoke 22910 * {@link #dispatchNestedPreScroll(int, int, int[], int[]) dispatchNestedPreScroll} 22911 * once it has calculated the requested scrolling delta. If it returns true the nested scrolling 22912 * parent at least partially consumed the scroll and the caller should adjust the amount it 22913 * scrolls by.</p> 22914 * 22915 * <p>After applying the remainder of the scroll delta the caller should invoke 22916 * {@link #dispatchNestedScroll(int, int, int, int, int[]) dispatchNestedScroll}, passing 22917 * both the delta consumed and the delta unconsumed. A nested scrolling parent may treat 22918 * these values differently. See {@link ViewParent#onNestedScroll(View, int, int, int, int)}. 22919 * </p> 22920 * 22921 * @param axes Flags consisting of a combination of {@link #SCROLL_AXIS_HORIZONTAL} and/or 22922 * {@link #SCROLL_AXIS_VERTICAL}. 22923 * @return true if a cooperative parent was found and nested scrolling has been enabled for 22924 * the current gesture. 22925 * 22926 * @see #stopNestedScroll() 22927 * @see #dispatchNestedPreScroll(int, int, int[], int[]) 22928 * @see #dispatchNestedScroll(int, int, int, int, int[]) 22929 */ 22930 public boolean startNestedScroll(int axes) { 22931 if (hasNestedScrollingParent()) { 22932 // Already in progress 22933 return true; 22934 } 22935 if (isNestedScrollingEnabled()) { 22936 ViewParent p = getParent(); 22937 View child = this; 22938 while (p != null) { 22939 try { 22940 if (p.onStartNestedScroll(child, this, axes)) { 22941 mNestedScrollingParent = p; 22942 p.onNestedScrollAccepted(child, this, axes); 22943 return true; 22944 } 22945 } catch (AbstractMethodError e) { 22946 Log.e(VIEW_LOG_TAG, "ViewParent " + p + " does not implement interface " + 22947 "method onStartNestedScroll", e); 22948 // Allow the search upward to continue 22949 } 22950 if (p instanceof View) { 22951 child = (View) p; 22952 } 22953 p = p.getParent(); 22954 } 22955 } 22956 return false; 22957 } 22958 22959 /** 22960 * Stop a nested scroll in progress. 22961 * 22962 * <p>Calling this method when a nested scroll is not currently in progress is harmless.</p> 22963 * 22964 * @see #startNestedScroll(int) 22965 */ 22966 public void stopNestedScroll() { 22967 if (mNestedScrollingParent != null) { 22968 mNestedScrollingParent.onStopNestedScroll(this); 22969 mNestedScrollingParent = null; 22970 } 22971 } 22972 22973 /** 22974 * Returns true if this view has a nested scrolling parent. 22975 * 22976 * <p>The presence of a nested scrolling parent indicates that this view has initiated 22977 * a nested scroll and it was accepted by an ancestor view further up the view hierarchy.</p> 22978 * 22979 * @return whether this view has a nested scrolling parent 22980 */ 22981 public boolean hasNestedScrollingParent() { 22982 return mNestedScrollingParent != null; 22983 } 22984 22985 /** 22986 * Dispatch one step of a nested scroll in progress. 22987 * 22988 * <p>Implementations of views that support nested scrolling should call this to report 22989 * info about a scroll in progress to the current nested scrolling parent. If a nested scroll 22990 * is not currently in progress or nested scrolling is not 22991 * {@link #isNestedScrollingEnabled() enabled} for this view this method does nothing.</p> 22992 * 22993 * <p>Compatible View implementations should also call 22994 * {@link #dispatchNestedPreScroll(int, int, int[], int[]) dispatchNestedPreScroll} before 22995 * consuming a component of the scroll event themselves.</p> 22996 * 22997 * @param dxConsumed Horizontal distance in pixels consumed by this view during this scroll step 22998 * @param dyConsumed Vertical distance in pixels consumed by this view during this scroll step 22999 * @param dxUnconsumed Horizontal scroll distance in pixels not consumed by this view 23000 * @param dyUnconsumed Horizontal scroll distance in pixels not consumed by this view 23001 * @param offsetInWindow Optional. If not null, on return this will contain the offset 23002 * in local view coordinates of this view from before this operation 23003 * to after it completes. View implementations may use this to adjust 23004 * expected input coordinate tracking. 23005 * @return true if the event was dispatched, false if it could not be dispatched. 23006 * @see #dispatchNestedPreScroll(int, int, int[], int[]) 23007 */ 23008 public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed, 23009 int dxUnconsumed, int dyUnconsumed, @Nullable @Size(2) int[] offsetInWindow) { 23010 if (isNestedScrollingEnabled() && mNestedScrollingParent != null) { 23011 if (dxConsumed != 0 || dyConsumed != 0 || dxUnconsumed != 0 || dyUnconsumed != 0) { 23012 int startX = 0; 23013 int startY = 0; 23014 if (offsetInWindow != null) { 23015 getLocationInWindow(offsetInWindow); 23016 startX = offsetInWindow[0]; 23017 startY = offsetInWindow[1]; 23018 } 23019 23020 mNestedScrollingParent.onNestedScroll(this, dxConsumed, dyConsumed, 23021 dxUnconsumed, dyUnconsumed); 23022 23023 if (offsetInWindow != null) { 23024 getLocationInWindow(offsetInWindow); 23025 offsetInWindow[0] -= startX; 23026 offsetInWindow[1] -= startY; 23027 } 23028 return true; 23029 } else if (offsetInWindow != null) { 23030 // No motion, no dispatch. Keep offsetInWindow up to date. 23031 offsetInWindow[0] = 0; 23032 offsetInWindow[1] = 0; 23033 } 23034 } 23035 return false; 23036 } 23037 23038 /** 23039 * Dispatch one step of a nested scroll in progress before this view consumes any portion of it. 23040 * 23041 * <p>Nested pre-scroll events are to nested scroll events what touch intercept is to touch. 23042 * <code>dispatchNestedPreScroll</code> offers an opportunity for the parent view in a nested 23043 * scrolling operation to consume some or all of the scroll operation before the child view 23044 * consumes it.</p> 23045 * 23046 * @param dx Horizontal scroll distance in pixels 23047 * @param dy Vertical scroll distance in pixels 23048 * @param consumed Output. If not null, consumed[0] will contain the consumed component of dx 23049 * and consumed[1] the consumed dy. 23050 * @param offsetInWindow Optional. If not null, on return this will contain the offset 23051 * in local view coordinates of this view from before this operation 23052 * to after it completes. View implementations may use this to adjust 23053 * expected input coordinate tracking. 23054 * @return true if the parent consumed some or all of the scroll delta 23055 * @see #dispatchNestedScroll(int, int, int, int, int[]) 23056 */ 23057 public boolean dispatchNestedPreScroll(int dx, int dy, 23058 @Nullable @Size(2) int[] consumed, @Nullable @Size(2) int[] offsetInWindow) { 23059 if (isNestedScrollingEnabled() && mNestedScrollingParent != null) { 23060 if (dx != 0 || dy != 0) { 23061 int startX = 0; 23062 int startY = 0; 23063 if (offsetInWindow != null) { 23064 getLocationInWindow(offsetInWindow); 23065 startX = offsetInWindow[0]; 23066 startY = offsetInWindow[1]; 23067 } 23068 23069 if (consumed == null) { 23070 if (mTempNestedScrollConsumed == null) { 23071 mTempNestedScrollConsumed = new int[2]; 23072 } 23073 consumed = mTempNestedScrollConsumed; 23074 } 23075 consumed[0] = 0; 23076 consumed[1] = 0; 23077 mNestedScrollingParent.onNestedPreScroll(this, dx, dy, consumed); 23078 23079 if (offsetInWindow != null) { 23080 getLocationInWindow(offsetInWindow); 23081 offsetInWindow[0] -= startX; 23082 offsetInWindow[1] -= startY; 23083 } 23084 return consumed[0] != 0 || consumed[1] != 0; 23085 } else if (offsetInWindow != null) { 23086 offsetInWindow[0] = 0; 23087 offsetInWindow[1] = 0; 23088 } 23089 } 23090 return false; 23091 } 23092 23093 /** 23094 * Dispatch a fling to a nested scrolling parent. 23095 * 23096 * <p>This method should be used to indicate that a nested scrolling child has detected 23097 * suitable conditions for a fling. Generally this means that a touch scroll has ended with a 23098 * {@link VelocityTracker velocity} in the direction of scrolling that meets or exceeds 23099 * the {@link ViewConfiguration#getScaledMinimumFlingVelocity() minimum fling velocity} 23100 * along a scrollable axis.</p> 23101 * 23102 * <p>If a nested scrolling child view would normally fling but it is at the edge of 23103 * its own content, it can use this method to delegate the fling to its nested scrolling 23104 * parent instead. The parent may optionally consume the fling or observe a child fling.</p> 23105 * 23106 * @param velocityX Horizontal fling velocity in pixels per second 23107 * @param velocityY Vertical fling velocity in pixels per second 23108 * @param consumed true if the child consumed the fling, false otherwise 23109 * @return true if the nested scrolling parent consumed or otherwise reacted to the fling 23110 */ 23111 public boolean dispatchNestedFling(float velocityX, float velocityY, boolean consumed) { 23112 if (isNestedScrollingEnabled() && mNestedScrollingParent != null) { 23113 return mNestedScrollingParent.onNestedFling(this, velocityX, velocityY, consumed); 23114 } 23115 return false; 23116 } 23117 23118 /** 23119 * Dispatch a fling to a nested scrolling parent before it is processed by this view. 23120 * 23121 * <p>Nested pre-fling events are to nested fling events what touch intercept is to touch 23122 * and what nested pre-scroll is to nested scroll. <code>dispatchNestedPreFling</code> 23123 * offsets an opportunity for the parent view in a nested fling to fully consume the fling 23124 * before the child view consumes it. If this method returns <code>true</code>, a nested 23125 * parent view consumed the fling and this view should not scroll as a result.</p> 23126 * 23127 * <p>For a better user experience, only one view in a nested scrolling chain should consume 23128 * the fling at a time. If a parent view consumed the fling this method will return false. 23129 * Custom view implementations should account for this in two ways:</p> 23130 * 23131 * <ul> 23132 * <li>If a custom view is paged and needs to settle to a fixed page-point, do not 23133 * call <code>dispatchNestedPreFling</code>; consume the fling and settle to a valid 23134 * position regardless.</li> 23135 * <li>If a nested parent does consume the fling, this view should not scroll at all, 23136 * even to settle back to a valid idle position.</li> 23137 * </ul> 23138 * 23139 * <p>Views should also not offer fling velocities to nested parent views along an axis 23140 * where scrolling is not currently supported; a {@link android.widget.ScrollView ScrollView} 23141 * should not offer a horizontal fling velocity to its parents since scrolling along that 23142 * axis is not permitted and carrying velocity along that motion does not make sense.</p> 23143 * 23144 * @param velocityX Horizontal fling velocity in pixels per second 23145 * @param velocityY Vertical fling velocity in pixels per second 23146 * @return true if a nested scrolling parent consumed the fling 23147 */ 23148 public boolean dispatchNestedPreFling(float velocityX, float velocityY) { 23149 if (isNestedScrollingEnabled() && mNestedScrollingParent != null) { 23150 return mNestedScrollingParent.onNestedPreFling(this, velocityX, velocityY); 23151 } 23152 return false; 23153 } 23154 23155 /** 23156 * Gets a scale factor that determines the distance the view should scroll 23157 * vertically in response to {@link MotionEvent#ACTION_SCROLL}. 23158 * @return The vertical scroll scale factor. 23159 * @hide 23160 */ 23161 protected float getVerticalScrollFactor() { 23162 if (mVerticalScrollFactor == 0) { 23163 TypedValue outValue = new TypedValue(); 23164 if (!mContext.getTheme().resolveAttribute( 23165 com.android.internal.R.attr.listPreferredItemHeight, outValue, true)) { 23166 throw new IllegalStateException( 23167 "Expected theme to define listPreferredItemHeight."); 23168 } 23169 mVerticalScrollFactor = outValue.getDimension( 23170 mContext.getResources().getDisplayMetrics()); 23171 } 23172 return mVerticalScrollFactor; 23173 } 23174 23175 /** 23176 * Gets a scale factor that determines the distance the view should scroll 23177 * horizontally in response to {@link MotionEvent#ACTION_SCROLL}. 23178 * @return The horizontal scroll scale factor. 23179 * @hide 23180 */ 23181 protected float getHorizontalScrollFactor() { 23182 // TODO: Should use something else. 23183 return getVerticalScrollFactor(); 23184 } 23185 23186 /** 23187 * Return the value specifying the text direction or policy that was set with 23188 * {@link #setTextDirection(int)}. 23189 * 23190 * @return the defined text direction. It can be one of: 23191 * 23192 * {@link #TEXT_DIRECTION_INHERIT}, 23193 * {@link #TEXT_DIRECTION_FIRST_STRONG}, 23194 * {@link #TEXT_DIRECTION_ANY_RTL}, 23195 * {@link #TEXT_DIRECTION_LTR}, 23196 * {@link #TEXT_DIRECTION_RTL}, 23197 * {@link #TEXT_DIRECTION_LOCALE}, 23198 * {@link #TEXT_DIRECTION_FIRST_STRONG_LTR}, 23199 * {@link #TEXT_DIRECTION_FIRST_STRONG_RTL} 23200 * 23201 * @attr ref android.R.styleable#View_textDirection 23202 * 23203 * @hide 23204 */ 23205 @ViewDebug.ExportedProperty(category = "text", mapping = { 23206 @ViewDebug.IntToString(from = TEXT_DIRECTION_INHERIT, to = "INHERIT"), 23207 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG, to = "FIRST_STRONG"), 23208 @ViewDebug.IntToString(from = TEXT_DIRECTION_ANY_RTL, to = "ANY_RTL"), 23209 @ViewDebug.IntToString(from = TEXT_DIRECTION_LTR, to = "LTR"), 23210 @ViewDebug.IntToString(from = TEXT_DIRECTION_RTL, to = "RTL"), 23211 @ViewDebug.IntToString(from = TEXT_DIRECTION_LOCALE, to = "LOCALE"), 23212 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_LTR, to = "FIRST_STRONG_LTR"), 23213 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_RTL, to = "FIRST_STRONG_RTL") 23214 }) 23215 public int getRawTextDirection() { 23216 return (mPrivateFlags2 & PFLAG2_TEXT_DIRECTION_MASK) >> PFLAG2_TEXT_DIRECTION_MASK_SHIFT; 23217 } 23218 23219 /** 23220 * Set the text direction. 23221 * 23222 * @param textDirection the direction to set. Should be one of: 23223 * 23224 * {@link #TEXT_DIRECTION_INHERIT}, 23225 * {@link #TEXT_DIRECTION_FIRST_STRONG}, 23226 * {@link #TEXT_DIRECTION_ANY_RTL}, 23227 * {@link #TEXT_DIRECTION_LTR}, 23228 * {@link #TEXT_DIRECTION_RTL}, 23229 * {@link #TEXT_DIRECTION_LOCALE} 23230 * {@link #TEXT_DIRECTION_FIRST_STRONG_LTR}, 23231 * {@link #TEXT_DIRECTION_FIRST_STRONG_RTL}, 23232 * 23233 * Resolution will be done if the value is set to TEXT_DIRECTION_INHERIT. The resolution 23234 * proceeds up the parent chain of the view to get the value. If there is no parent, then it will 23235 * return the default {@link #TEXT_DIRECTION_FIRST_STRONG}. 23236 * 23237 * @attr ref android.R.styleable#View_textDirection 23238 */ 23239 public void setTextDirection(int textDirection) { 23240 if (getRawTextDirection() != textDirection) { 23241 // Reset the current text direction and the resolved one 23242 mPrivateFlags2 &= ~PFLAG2_TEXT_DIRECTION_MASK; 23243 resetResolvedTextDirection(); 23244 // Set the new text direction 23245 mPrivateFlags2 |= ((textDirection << PFLAG2_TEXT_DIRECTION_MASK_SHIFT) & PFLAG2_TEXT_DIRECTION_MASK); 23246 // Do resolution 23247 resolveTextDirection(); 23248 // Notify change 23249 onRtlPropertiesChanged(getLayoutDirection()); 23250 // Refresh 23251 requestLayout(); 23252 invalidate(true); 23253 } 23254 } 23255 23256 /** 23257 * Return the resolved text direction. 23258 * 23259 * @return the resolved text direction. Returns one of: 23260 * 23261 * {@link #TEXT_DIRECTION_FIRST_STRONG}, 23262 * {@link #TEXT_DIRECTION_ANY_RTL}, 23263 * {@link #TEXT_DIRECTION_LTR}, 23264 * {@link #TEXT_DIRECTION_RTL}, 23265 * {@link #TEXT_DIRECTION_LOCALE}, 23266 * {@link #TEXT_DIRECTION_FIRST_STRONG_LTR}, 23267 * {@link #TEXT_DIRECTION_FIRST_STRONG_RTL} 23268 * 23269 * @attr ref android.R.styleable#View_textDirection 23270 */ 23271 @ViewDebug.ExportedProperty(category = "text", mapping = { 23272 @ViewDebug.IntToString(from = TEXT_DIRECTION_INHERIT, to = "INHERIT"), 23273 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG, to = "FIRST_STRONG"), 23274 @ViewDebug.IntToString(from = TEXT_DIRECTION_ANY_RTL, to = "ANY_RTL"), 23275 @ViewDebug.IntToString(from = TEXT_DIRECTION_LTR, to = "LTR"), 23276 @ViewDebug.IntToString(from = TEXT_DIRECTION_RTL, to = "RTL"), 23277 @ViewDebug.IntToString(from = TEXT_DIRECTION_LOCALE, to = "LOCALE"), 23278 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_LTR, to = "FIRST_STRONG_LTR"), 23279 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_RTL, to = "FIRST_STRONG_RTL") 23280 }) 23281 public int getTextDirection() { 23282 return (mPrivateFlags2 & PFLAG2_TEXT_DIRECTION_RESOLVED_MASK) >> PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT; 23283 } 23284 23285 /** 23286 * Resolve the text direction. 23287 * 23288 * @return true if resolution has been done, false otherwise. 23289 * 23290 * @hide 23291 */ 23292 public boolean resolveTextDirection() { 23293 // Reset any previous text direction resolution 23294 mPrivateFlags2 &= ~(PFLAG2_TEXT_DIRECTION_RESOLVED | PFLAG2_TEXT_DIRECTION_RESOLVED_MASK); 23295 23296 if (hasRtlSupport()) { 23297 // Set resolved text direction flag depending on text direction flag 23298 final int textDirection = getRawTextDirection(); 23299 switch(textDirection) { 23300 case TEXT_DIRECTION_INHERIT: 23301 if (!canResolveTextDirection()) { 23302 // We cannot do the resolution if there is no parent, so use the default one 23303 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 23304 // Resolution will need to happen again later 23305 return false; 23306 } 23307 23308 // Parent has not yet resolved, so we still return the default 23309 try { 23310 if (!mParent.isTextDirectionResolved()) { 23311 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 23312 // Resolution will need to happen again later 23313 return false; 23314 } 23315 } catch (AbstractMethodError e) { 23316 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 23317 " does not fully implement ViewParent", e); 23318 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED | 23319 PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 23320 return true; 23321 } 23322 23323 // Set current resolved direction to the same value as the parent's one 23324 int parentResolvedDirection; 23325 try { 23326 parentResolvedDirection = mParent.getTextDirection(); 23327 } catch (AbstractMethodError e) { 23328 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 23329 " does not fully implement ViewParent", e); 23330 parentResolvedDirection = TEXT_DIRECTION_LTR; 23331 } 23332 switch (parentResolvedDirection) { 23333 case TEXT_DIRECTION_FIRST_STRONG: 23334 case TEXT_DIRECTION_ANY_RTL: 23335 case TEXT_DIRECTION_LTR: 23336 case TEXT_DIRECTION_RTL: 23337 case TEXT_DIRECTION_LOCALE: 23338 case TEXT_DIRECTION_FIRST_STRONG_LTR: 23339 case TEXT_DIRECTION_FIRST_STRONG_RTL: 23340 mPrivateFlags2 |= 23341 (parentResolvedDirection << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT); 23342 break; 23343 default: 23344 // Default resolved direction is "first strong" heuristic 23345 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 23346 } 23347 break; 23348 case TEXT_DIRECTION_FIRST_STRONG: 23349 case TEXT_DIRECTION_ANY_RTL: 23350 case TEXT_DIRECTION_LTR: 23351 case TEXT_DIRECTION_RTL: 23352 case TEXT_DIRECTION_LOCALE: 23353 case TEXT_DIRECTION_FIRST_STRONG_LTR: 23354 case TEXT_DIRECTION_FIRST_STRONG_RTL: 23355 // Resolved direction is the same as text direction 23356 mPrivateFlags2 |= (textDirection << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT); 23357 break; 23358 default: 23359 // Default resolved direction is "first strong" heuristic 23360 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 23361 } 23362 } else { 23363 // Default resolved direction is "first strong" heuristic 23364 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 23365 } 23366 23367 // Set to resolved 23368 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED; 23369 return true; 23370 } 23371 23372 /** 23373 * Check if text direction resolution can be done. 23374 * 23375 * @return true if text direction resolution can be done otherwise return false. 23376 */ 23377 public boolean canResolveTextDirection() { 23378 switch (getRawTextDirection()) { 23379 case TEXT_DIRECTION_INHERIT: 23380 if (mParent != null) { 23381 try { 23382 return mParent.canResolveTextDirection(); 23383 } catch (AbstractMethodError e) { 23384 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 23385 " does not fully implement ViewParent", e); 23386 } 23387 } 23388 return false; 23389 23390 default: 23391 return true; 23392 } 23393 } 23394 23395 /** 23396 * Reset resolved text direction. Text direction will be resolved during a call to 23397 * {@link #onMeasure(int, int)}. 23398 * 23399 * @hide 23400 */ 23401 public void resetResolvedTextDirection() { 23402 // Reset any previous text direction resolution 23403 mPrivateFlags2 &= ~(PFLAG2_TEXT_DIRECTION_RESOLVED | PFLAG2_TEXT_DIRECTION_RESOLVED_MASK); 23404 // Set to default value 23405 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 23406 } 23407 23408 /** 23409 * @return true if text direction is inherited. 23410 * 23411 * @hide 23412 */ 23413 public boolean isTextDirectionInherited() { 23414 return (getRawTextDirection() == TEXT_DIRECTION_INHERIT); 23415 } 23416 23417 /** 23418 * @return true if text direction is resolved. 23419 */ 23420 public boolean isTextDirectionResolved() { 23421 return (mPrivateFlags2 & PFLAG2_TEXT_DIRECTION_RESOLVED) == PFLAG2_TEXT_DIRECTION_RESOLVED; 23422 } 23423 23424 /** 23425 * Return the value specifying the text alignment or policy that was set with 23426 * {@link #setTextAlignment(int)}. 23427 * 23428 * @return the defined text alignment. It can be one of: 23429 * 23430 * {@link #TEXT_ALIGNMENT_INHERIT}, 23431 * {@link #TEXT_ALIGNMENT_GRAVITY}, 23432 * {@link #TEXT_ALIGNMENT_CENTER}, 23433 * {@link #TEXT_ALIGNMENT_TEXT_START}, 23434 * {@link #TEXT_ALIGNMENT_TEXT_END}, 23435 * {@link #TEXT_ALIGNMENT_VIEW_START}, 23436 * {@link #TEXT_ALIGNMENT_VIEW_END} 23437 * 23438 * @attr ref android.R.styleable#View_textAlignment 23439 * 23440 * @hide 23441 */ 23442 @ViewDebug.ExportedProperty(category = "text", mapping = { 23443 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_INHERIT, to = "INHERIT"), 23444 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_GRAVITY, to = "GRAVITY"), 23445 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_TEXT_START, to = "TEXT_START"), 23446 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_TEXT_END, to = "TEXT_END"), 23447 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_CENTER, to = "CENTER"), 23448 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_START, to = "VIEW_START"), 23449 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_END, to = "VIEW_END") 23450 }) 23451 @TextAlignment 23452 public int getRawTextAlignment() { 23453 return (mPrivateFlags2 & PFLAG2_TEXT_ALIGNMENT_MASK) >> PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT; 23454 } 23455 23456 /** 23457 * Set the text alignment. 23458 * 23459 * @param textAlignment The text alignment to set. Should be one of 23460 * 23461 * {@link #TEXT_ALIGNMENT_INHERIT}, 23462 * {@link #TEXT_ALIGNMENT_GRAVITY}, 23463 * {@link #TEXT_ALIGNMENT_CENTER}, 23464 * {@link #TEXT_ALIGNMENT_TEXT_START}, 23465 * {@link #TEXT_ALIGNMENT_TEXT_END}, 23466 * {@link #TEXT_ALIGNMENT_VIEW_START}, 23467 * {@link #TEXT_ALIGNMENT_VIEW_END} 23468 * 23469 * Resolution will be done if the value is set to TEXT_ALIGNMENT_INHERIT. The resolution 23470 * proceeds up the parent chain of the view to get the value. If there is no parent, then it 23471 * will return the default {@link #TEXT_ALIGNMENT_GRAVITY}. 23472 * 23473 * @attr ref android.R.styleable#View_textAlignment 23474 */ 23475 public void setTextAlignment(@TextAlignment int textAlignment) { 23476 if (textAlignment != getRawTextAlignment()) { 23477 // Reset the current and resolved text alignment 23478 mPrivateFlags2 &= ~PFLAG2_TEXT_ALIGNMENT_MASK; 23479 resetResolvedTextAlignment(); 23480 // Set the new text alignment 23481 mPrivateFlags2 |= 23482 ((textAlignment << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT) & PFLAG2_TEXT_ALIGNMENT_MASK); 23483 // Do resolution 23484 resolveTextAlignment(); 23485 // Notify change 23486 onRtlPropertiesChanged(getLayoutDirection()); 23487 // Refresh 23488 requestLayout(); 23489 invalidate(true); 23490 } 23491 } 23492 23493 /** 23494 * Return the resolved text alignment. 23495 * 23496 * @return the resolved text alignment. Returns one of: 23497 * 23498 * {@link #TEXT_ALIGNMENT_GRAVITY}, 23499 * {@link #TEXT_ALIGNMENT_CENTER}, 23500 * {@link #TEXT_ALIGNMENT_TEXT_START}, 23501 * {@link #TEXT_ALIGNMENT_TEXT_END}, 23502 * {@link #TEXT_ALIGNMENT_VIEW_START}, 23503 * {@link #TEXT_ALIGNMENT_VIEW_END} 23504 * 23505 * @attr ref android.R.styleable#View_textAlignment 23506 */ 23507 @ViewDebug.ExportedProperty(category = "text", mapping = { 23508 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_INHERIT, to = "INHERIT"), 23509 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_GRAVITY, to = "GRAVITY"), 23510 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_TEXT_START, to = "TEXT_START"), 23511 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_TEXT_END, to = "TEXT_END"), 23512 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_CENTER, to = "CENTER"), 23513 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_START, to = "VIEW_START"), 23514 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_END, to = "VIEW_END") 23515 }) 23516 @TextAlignment 23517 public int getTextAlignment() { 23518 return (mPrivateFlags2 & PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK) >> 23519 PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT; 23520 } 23521 23522 /** 23523 * Resolve the text alignment. 23524 * 23525 * @return true if resolution has been done, false otherwise. 23526 * 23527 * @hide 23528 */ 23529 public boolean resolveTextAlignment() { 23530 // Reset any previous text alignment resolution 23531 mPrivateFlags2 &= ~(PFLAG2_TEXT_ALIGNMENT_RESOLVED | PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK); 23532 23533 if (hasRtlSupport()) { 23534 // Set resolved text alignment flag depending on text alignment flag 23535 final int textAlignment = getRawTextAlignment(); 23536 switch (textAlignment) { 23537 case TEXT_ALIGNMENT_INHERIT: 23538 // Check if we can resolve the text alignment 23539 if (!canResolveTextAlignment()) { 23540 // We cannot do the resolution if there is no parent so use the default 23541 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 23542 // Resolution will need to happen again later 23543 return false; 23544 } 23545 23546 // Parent has not yet resolved, so we still return the default 23547 try { 23548 if (!mParent.isTextAlignmentResolved()) { 23549 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 23550 // Resolution will need to happen again later 23551 return false; 23552 } 23553 } catch (AbstractMethodError e) { 23554 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 23555 " does not fully implement ViewParent", e); 23556 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED | 23557 PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 23558 return true; 23559 } 23560 23561 int parentResolvedTextAlignment; 23562 try { 23563 parentResolvedTextAlignment = mParent.getTextAlignment(); 23564 } catch (AbstractMethodError e) { 23565 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 23566 " does not fully implement ViewParent", e); 23567 parentResolvedTextAlignment = TEXT_ALIGNMENT_GRAVITY; 23568 } 23569 switch (parentResolvedTextAlignment) { 23570 case TEXT_ALIGNMENT_GRAVITY: 23571 case TEXT_ALIGNMENT_TEXT_START: 23572 case TEXT_ALIGNMENT_TEXT_END: 23573 case TEXT_ALIGNMENT_CENTER: 23574 case TEXT_ALIGNMENT_VIEW_START: 23575 case TEXT_ALIGNMENT_VIEW_END: 23576 // Resolved text alignment is the same as the parent resolved 23577 // text alignment 23578 mPrivateFlags2 |= 23579 (parentResolvedTextAlignment << PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT); 23580 break; 23581 default: 23582 // Use default resolved text alignment 23583 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 23584 } 23585 break; 23586 case TEXT_ALIGNMENT_GRAVITY: 23587 case TEXT_ALIGNMENT_TEXT_START: 23588 case TEXT_ALIGNMENT_TEXT_END: 23589 case TEXT_ALIGNMENT_CENTER: 23590 case TEXT_ALIGNMENT_VIEW_START: 23591 case TEXT_ALIGNMENT_VIEW_END: 23592 // Resolved text alignment is the same as text alignment 23593 mPrivateFlags2 |= (textAlignment << PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT); 23594 break; 23595 default: 23596 // Use default resolved text alignment 23597 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 23598 } 23599 } else { 23600 // Use default resolved text alignment 23601 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 23602 } 23603 23604 // Set the resolved 23605 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED; 23606 return true; 23607 } 23608 23609 /** 23610 * Check if text alignment resolution can be done. 23611 * 23612 * @return true if text alignment resolution can be done otherwise return false. 23613 */ 23614 public boolean canResolveTextAlignment() { 23615 switch (getRawTextAlignment()) { 23616 case TEXT_DIRECTION_INHERIT: 23617 if (mParent != null) { 23618 try { 23619 return mParent.canResolveTextAlignment(); 23620 } catch (AbstractMethodError e) { 23621 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 23622 " does not fully implement ViewParent", e); 23623 } 23624 } 23625 return false; 23626 23627 default: 23628 return true; 23629 } 23630 } 23631 23632 /** 23633 * Reset resolved text alignment. Text alignment will be resolved during a call to 23634 * {@link #onMeasure(int, int)}. 23635 * 23636 * @hide 23637 */ 23638 public void resetResolvedTextAlignment() { 23639 // Reset any previous text alignment resolution 23640 mPrivateFlags2 &= ~(PFLAG2_TEXT_ALIGNMENT_RESOLVED | PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK); 23641 // Set to default 23642 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 23643 } 23644 23645 /** 23646 * @return true if text alignment is inherited. 23647 * 23648 * @hide 23649 */ 23650 public boolean isTextAlignmentInherited() { 23651 return (getRawTextAlignment() == TEXT_ALIGNMENT_INHERIT); 23652 } 23653 23654 /** 23655 * @return true if text alignment is resolved. 23656 */ 23657 public boolean isTextAlignmentResolved() { 23658 return (mPrivateFlags2 & PFLAG2_TEXT_ALIGNMENT_RESOLVED) == PFLAG2_TEXT_ALIGNMENT_RESOLVED; 23659 } 23660 23661 /** 23662 * Generate a value suitable for use in {@link #setId(int)}. 23663 * This value will not collide with ID values generated at build time by aapt for R.id. 23664 * 23665 * @return a generated ID value 23666 */ 23667 public static int generateViewId() { 23668 for (;;) { 23669 final int result = sNextGeneratedId.get(); 23670 // aapt-generated IDs have the high byte nonzero; clamp to the range under that. 23671 int newValue = result + 1; 23672 if (newValue > 0x00FFFFFF) newValue = 1; // Roll over to 1, not 0. 23673 if (sNextGeneratedId.compareAndSet(result, newValue)) { 23674 return result; 23675 } 23676 } 23677 } 23678 23679 private static boolean isViewIdGenerated(int id) { 23680 return (id & 0xFF000000) == 0 && (id & 0x00FFFFFF) != 0; 23681 } 23682 23683 /** 23684 * Gets the Views in the hierarchy affected by entering and exiting Activity Scene transitions. 23685 * @param transitioningViews This View will be added to transitioningViews if it is VISIBLE and 23686 * a normal View or a ViewGroup with 23687 * {@link android.view.ViewGroup#isTransitionGroup()} true. 23688 * @hide 23689 */ 23690 public void captureTransitioningViews(List<View> transitioningViews) { 23691 if (getVisibility() == View.VISIBLE) { 23692 transitioningViews.add(this); 23693 } 23694 } 23695 23696 /** 23697 * Adds all Views that have {@link #getTransitionName()} non-null to namedElements. 23698 * @param namedElements Will contain all Views in the hierarchy having a transitionName. 23699 * @hide 23700 */ 23701 public void findNamedViews(Map<String, View> namedElements) { 23702 if (getVisibility() == VISIBLE || mGhostView != null) { 23703 String transitionName = getTransitionName(); 23704 if (transitionName != null) { 23705 namedElements.put(transitionName, this); 23706 } 23707 } 23708 } 23709 23710 /** 23711 * Returns the pointer icon for the motion event, or null if it doesn't specify the icon. 23712 * The default implementation does not care the location or event types, but some subclasses 23713 * may use it (such as WebViews). 23714 * @param event The MotionEvent from a mouse 23715 * @param pointerIndex The index of the pointer for which to retrieve the {@link PointerIcon}. 23716 * This will be between 0 and {@link MotionEvent#getPointerCount()}. 23717 * @see PointerIcon 23718 */ 23719 public PointerIcon onResolvePointerIcon(MotionEvent event, int pointerIndex) { 23720 final float x = event.getX(pointerIndex); 23721 final float y = event.getY(pointerIndex); 23722 if (isDraggingScrollBar() || isOnScrollbarThumb(x, y)) { 23723 return PointerIcon.getSystemIcon(mContext, PointerIcon.TYPE_ARROW); 23724 } 23725 return mPointerIcon; 23726 } 23727 23728 /** 23729 * Set the pointer icon for the current view. 23730 * Passing {@code null} will restore the pointer icon to its default value. 23731 * @param pointerIcon A PointerIcon instance which will be shown when the mouse hovers. 23732 */ 23733 public void setPointerIcon(PointerIcon pointerIcon) { 23734 mPointerIcon = pointerIcon; 23735 if (mAttachInfo == null || mAttachInfo.mHandlingPointerEvent) { 23736 return; 23737 } 23738 try { 23739 mAttachInfo.mSession.updatePointerIcon(mAttachInfo.mWindow); 23740 } catch (RemoteException e) { 23741 } 23742 } 23743 23744 /** 23745 * Gets the pointer icon for the current view. 23746 */ 23747 public PointerIcon getPointerIcon() { 23748 return mPointerIcon; 23749 } 23750 23751 /** 23752 * Checks pointer capture status. 23753 * 23754 * @return true if the view has pointer capture. 23755 * @see #requestPointerCapture() 23756 * @see #hasPointerCapture() 23757 */ 23758 public boolean hasPointerCapture() { 23759 final ViewRootImpl viewRootImpl = getViewRootImpl(); 23760 if (viewRootImpl == null) { 23761 return false; 23762 } 23763 return viewRootImpl.hasPointerCapture(); 23764 } 23765 23766 /** 23767 * Requests pointer capture mode. 23768 * <p> 23769 * When the window has pointer capture, the mouse pointer icon will disappear and will not 23770 * change its position. Further mouse will be dispatched with the source 23771 * {@link InputDevice#SOURCE_MOUSE_RELATIVE}, and relative position changes will be available 23772 * through {@link MotionEvent#getX} and {@link MotionEvent#getY}. Non-mouse events 23773 * (touchscreens, or stylus) will not be affected. 23774 * <p> 23775 * If the window already has pointer capture, this call does nothing. 23776 * <p> 23777 * The capture may be released through {@link #releasePointerCapture()}, or will be lost 23778 * automatically when the window loses focus. 23779 * 23780 * @see #releasePointerCapture() 23781 * @see #hasPointerCapture() 23782 */ 23783 public void requestPointerCapture() { 23784 final ViewRootImpl viewRootImpl = getViewRootImpl(); 23785 if (viewRootImpl != null) { 23786 viewRootImpl.requestPointerCapture(true); 23787 } 23788 } 23789 23790 23791 /** 23792 * Releases the pointer capture. 23793 * <p> 23794 * If the window does not have pointer capture, this call will do nothing. 23795 * @see #requestPointerCapture() 23796 * @see #hasPointerCapture() 23797 */ 23798 public void releasePointerCapture() { 23799 final ViewRootImpl viewRootImpl = getViewRootImpl(); 23800 if (viewRootImpl != null) { 23801 viewRootImpl.requestPointerCapture(false); 23802 } 23803 } 23804 23805 /** 23806 * Called when the window has just acquired or lost pointer capture. 23807 * 23808 * @param hasCapture True if the view now has pointerCapture, false otherwise. 23809 */ 23810 @CallSuper 23811 public void onPointerCaptureChange(boolean hasCapture) { 23812 } 23813 23814 /** 23815 * @see #onPointerCaptureChange 23816 */ 23817 public void dispatchPointerCaptureChanged(boolean hasCapture) { 23818 onPointerCaptureChange(hasCapture); 23819 } 23820 23821 /** 23822 * Implement this method to handle captured pointer events 23823 * 23824 * @param event The captured pointer event. 23825 * @return True if the event was handled, false otherwise. 23826 * @see #requestPointerCapture() 23827 */ 23828 public boolean onCapturedPointerEvent(MotionEvent event) { 23829 return false; 23830 } 23831 23832 /** 23833 * Interface definition for a callback to be invoked when a captured pointer event 23834 * is being dispatched this view. The callback will be invoked before the event is 23835 * given to the view. 23836 */ 23837 public interface OnCapturedPointerListener { 23838 /** 23839 * Called when a captured pointer event is dispatched to a view. 23840 * @param view The view this event has been dispatched to. 23841 * @param event The captured event. 23842 * @return True if the listener has consumed the event, false otherwise. 23843 */ 23844 boolean onCapturedPointer(View view, MotionEvent event); 23845 } 23846 23847 /** 23848 * Set a listener to receive callbacks when the pointer capture state of a view changes. 23849 * @param l The {@link OnCapturedPointerListener} to receive callbacks. 23850 */ 23851 public void setOnCapturedPointerListener(OnCapturedPointerListener l) { 23852 getListenerInfo().mOnCapturedPointerListener = l; 23853 } 23854 23855 // Properties 23856 // 23857 /** 23858 * A Property wrapper around the <code>alpha</code> functionality handled by the 23859 * {@link View#setAlpha(float)} and {@link View#getAlpha()} methods. 23860 */ 23861 public static final Property<View, Float> ALPHA = new FloatProperty<View>("alpha") { 23862 @Override 23863 public void setValue(View object, float value) { 23864 object.setAlpha(value); 23865 } 23866 23867 @Override 23868 public Float get(View object) { 23869 return object.getAlpha(); 23870 } 23871 }; 23872 23873 /** 23874 * A Property wrapper around the <code>translationX</code> functionality handled by the 23875 * {@link View#setTranslationX(float)} and {@link View#getTranslationX()} methods. 23876 */ 23877 public static final Property<View, Float> TRANSLATION_X = new FloatProperty<View>("translationX") { 23878 @Override 23879 public void setValue(View object, float value) { 23880 object.setTranslationX(value); 23881 } 23882 23883 @Override 23884 public Float get(View object) { 23885 return object.getTranslationX(); 23886 } 23887 }; 23888 23889 /** 23890 * A Property wrapper around the <code>translationY</code> functionality handled by the 23891 * {@link View#setTranslationY(float)} and {@link View#getTranslationY()} methods. 23892 */ 23893 public static final Property<View, Float> TRANSLATION_Y = new FloatProperty<View>("translationY") { 23894 @Override 23895 public void setValue(View object, float value) { 23896 object.setTranslationY(value); 23897 } 23898 23899 @Override 23900 public Float get(View object) { 23901 return object.getTranslationY(); 23902 } 23903 }; 23904 23905 /** 23906 * A Property wrapper around the <code>translationZ</code> functionality handled by the 23907 * {@link View#setTranslationZ(float)} and {@link View#getTranslationZ()} methods. 23908 */ 23909 public static final Property<View, Float> TRANSLATION_Z = new FloatProperty<View>("translationZ") { 23910 @Override 23911 public void setValue(View object, float value) { 23912 object.setTranslationZ(value); 23913 } 23914 23915 @Override 23916 public Float get(View object) { 23917 return object.getTranslationZ(); 23918 } 23919 }; 23920 23921 /** 23922 * A Property wrapper around the <code>x</code> functionality handled by the 23923 * {@link View#setX(float)} and {@link View#getX()} methods. 23924 */ 23925 public static final Property<View, Float> X = new FloatProperty<View>("x") { 23926 @Override 23927 public void setValue(View object, float value) { 23928 object.setX(value); 23929 } 23930 23931 @Override 23932 public Float get(View object) { 23933 return object.getX(); 23934 } 23935 }; 23936 23937 /** 23938 * A Property wrapper around the <code>y</code> functionality handled by the 23939 * {@link View#setY(float)} and {@link View#getY()} methods. 23940 */ 23941 public static final Property<View, Float> Y = new FloatProperty<View>("y") { 23942 @Override 23943 public void setValue(View object, float value) { 23944 object.setY(value); 23945 } 23946 23947 @Override 23948 public Float get(View object) { 23949 return object.getY(); 23950 } 23951 }; 23952 23953 /** 23954 * A Property wrapper around the <code>z</code> functionality handled by the 23955 * {@link View#setZ(float)} and {@link View#getZ()} methods. 23956 */ 23957 public static final Property<View, Float> Z = new FloatProperty<View>("z") { 23958 @Override 23959 public void setValue(View object, float value) { 23960 object.setZ(value); 23961 } 23962 23963 @Override 23964 public Float get(View object) { 23965 return object.getZ(); 23966 } 23967 }; 23968 23969 /** 23970 * A Property wrapper around the <code>rotation</code> functionality handled by the 23971 * {@link View#setRotation(float)} and {@link View#getRotation()} methods. 23972 */ 23973 public static final Property<View, Float> ROTATION = new FloatProperty<View>("rotation") { 23974 @Override 23975 public void setValue(View object, float value) { 23976 object.setRotation(value); 23977 } 23978 23979 @Override 23980 public Float get(View object) { 23981 return object.getRotation(); 23982 } 23983 }; 23984 23985 /** 23986 * A Property wrapper around the <code>rotationX</code> functionality handled by the 23987 * {@link View#setRotationX(float)} and {@link View#getRotationX()} methods. 23988 */ 23989 public static final Property<View, Float> ROTATION_X = new FloatProperty<View>("rotationX") { 23990 @Override 23991 public void setValue(View object, float value) { 23992 object.setRotationX(value); 23993 } 23994 23995 @Override 23996 public Float get(View object) { 23997 return object.getRotationX(); 23998 } 23999 }; 24000 24001 /** 24002 * A Property wrapper around the <code>rotationY</code> functionality handled by the 24003 * {@link View#setRotationY(float)} and {@link View#getRotationY()} methods. 24004 */ 24005 public static final Property<View, Float> ROTATION_Y = new FloatProperty<View>("rotationY") { 24006 @Override 24007 public void setValue(View object, float value) { 24008 object.setRotationY(value); 24009 } 24010 24011 @Override 24012 public Float get(View object) { 24013 return object.getRotationY(); 24014 } 24015 }; 24016 24017 /** 24018 * A Property wrapper around the <code>scaleX</code> functionality handled by the 24019 * {@link View#setScaleX(float)} and {@link View#getScaleX()} methods. 24020 */ 24021 public static final Property<View, Float> SCALE_X = new FloatProperty<View>("scaleX") { 24022 @Override 24023 public void setValue(View object, float value) { 24024 object.setScaleX(value); 24025 } 24026 24027 @Override 24028 public Float get(View object) { 24029 return object.getScaleX(); 24030 } 24031 }; 24032 24033 /** 24034 * A Property wrapper around the <code>scaleY</code> functionality handled by the 24035 * {@link View#setScaleY(float)} and {@link View#getScaleY()} methods. 24036 */ 24037 public static final Property<View, Float> SCALE_Y = new FloatProperty<View>("scaleY") { 24038 @Override 24039 public void setValue(View object, float value) { 24040 object.setScaleY(value); 24041 } 24042 24043 @Override 24044 public Float get(View object) { 24045 return object.getScaleY(); 24046 } 24047 }; 24048 24049 /** 24050 * A MeasureSpec encapsulates the layout requirements passed from parent to child. 24051 * Each MeasureSpec represents a requirement for either the width or the height. 24052 * A MeasureSpec is comprised of a size and a mode. There are three possible 24053 * modes: 24054 * <dl> 24055 * <dt>UNSPECIFIED</dt> 24056 * <dd> 24057 * The parent has not imposed any constraint on the child. It can be whatever size 24058 * it wants. 24059 * </dd> 24060 * 24061 * <dt>EXACTLY</dt> 24062 * <dd> 24063 * The parent has determined an exact size for the child. The child is going to be 24064 * given those bounds regardless of how big it wants to be. 24065 * </dd> 24066 * 24067 * <dt>AT_MOST</dt> 24068 * <dd> 24069 * The child can be as large as it wants up to the specified size. 24070 * </dd> 24071 * </dl> 24072 * 24073 * MeasureSpecs are implemented as ints to reduce object allocation. This class 24074 * is provided to pack and unpack the <size, mode> tuple into the int. 24075 */ 24076 public static class MeasureSpec { 24077 private static final int MODE_SHIFT = 30; 24078 private static final int MODE_MASK = 0x3 << MODE_SHIFT; 24079 24080 /** @hide */ 24081 @IntDef({UNSPECIFIED, EXACTLY, AT_MOST}) 24082 @Retention(RetentionPolicy.SOURCE) 24083 public @interface MeasureSpecMode {} 24084 24085 /** 24086 * Measure specification mode: The parent has not imposed any constraint 24087 * on the child. It can be whatever size it wants. 24088 */ 24089 public static final int UNSPECIFIED = 0 << MODE_SHIFT; 24090 24091 /** 24092 * Measure specification mode: The parent has determined an exact size 24093 * for the child. The child is going to be given those bounds regardless 24094 * of how big it wants to be. 24095 */ 24096 public static final int EXACTLY = 1 << MODE_SHIFT; 24097 24098 /** 24099 * Measure specification mode: The child can be as large as it wants up 24100 * to the specified size. 24101 */ 24102 public static final int AT_MOST = 2 << MODE_SHIFT; 24103 24104 /** 24105 * Creates a measure specification based on the supplied size and mode. 24106 * 24107 * The mode must always be one of the following: 24108 * <ul> 24109 * <li>{@link android.view.View.MeasureSpec#UNSPECIFIED}</li> 24110 * <li>{@link android.view.View.MeasureSpec#EXACTLY}</li> 24111 * <li>{@link android.view.View.MeasureSpec#AT_MOST}</li> 24112 * </ul> 24113 * 24114 * <p><strong>Note:</strong> On API level 17 and lower, makeMeasureSpec's 24115 * implementation was such that the order of arguments did not matter 24116 * and overflow in either value could impact the resulting MeasureSpec. 24117 * {@link android.widget.RelativeLayout} was affected by this bug. 24118 * Apps targeting API levels greater than 17 will get the fixed, more strict 24119 * behavior.</p> 24120 * 24121 * @param size the size of the measure specification 24122 * @param mode the mode of the measure specification 24123 * @return the measure specification based on size and mode 24124 */ 24125 public static int makeMeasureSpec(@IntRange(from = 0, to = (1 << MeasureSpec.MODE_SHIFT) - 1) int size, 24126 @MeasureSpecMode int mode) { 24127 if (sUseBrokenMakeMeasureSpec) { 24128 return size + mode; 24129 } else { 24130 return (size & ~MODE_MASK) | (mode & MODE_MASK); 24131 } 24132 } 24133 24134 /** 24135 * Like {@link #makeMeasureSpec(int, int)}, but any spec with a mode of UNSPECIFIED 24136 * will automatically get a size of 0. Older apps expect this. 24137 * 24138 * @hide internal use only for compatibility with system widgets and older apps 24139 */ 24140 public static int makeSafeMeasureSpec(int size, int mode) { 24141 if (sUseZeroUnspecifiedMeasureSpec && mode == UNSPECIFIED) { 24142 return 0; 24143 } 24144 return makeMeasureSpec(size, mode); 24145 } 24146 24147 /** 24148 * Extracts the mode from the supplied measure specification. 24149 * 24150 * @param measureSpec the measure specification to extract the mode from 24151 * @return {@link android.view.View.MeasureSpec#UNSPECIFIED}, 24152 * {@link android.view.View.MeasureSpec#AT_MOST} or 24153 * {@link android.view.View.MeasureSpec#EXACTLY} 24154 */ 24155 @MeasureSpecMode 24156 public static int getMode(int measureSpec) { 24157 //noinspection ResourceType 24158 return (measureSpec & MODE_MASK); 24159 } 24160 24161 /** 24162 * Extracts the size from the supplied measure specification. 24163 * 24164 * @param measureSpec the measure specification to extract the size from 24165 * @return the size in pixels defined in the supplied measure specification 24166 */ 24167 public static int getSize(int measureSpec) { 24168 return (measureSpec & ~MODE_MASK); 24169 } 24170 24171 static int adjust(int measureSpec, int delta) { 24172 final int mode = getMode(measureSpec); 24173 int size = getSize(measureSpec); 24174 if (mode == UNSPECIFIED) { 24175 // No need to adjust size for UNSPECIFIED mode. 24176 return makeMeasureSpec(size, UNSPECIFIED); 24177 } 24178 size += delta; 24179 if (size < 0) { 24180 Log.e(VIEW_LOG_TAG, "MeasureSpec.adjust: new size would be negative! (" + size + 24181 ") spec: " + toString(measureSpec) + " delta: " + delta); 24182 size = 0; 24183 } 24184 return makeMeasureSpec(size, mode); 24185 } 24186 24187 /** 24188 * Returns a String representation of the specified measure 24189 * specification. 24190 * 24191 * @param measureSpec the measure specification to convert to a String 24192 * @return a String with the following format: "MeasureSpec: MODE SIZE" 24193 */ 24194 public static String toString(int measureSpec) { 24195 int mode = getMode(measureSpec); 24196 int size = getSize(measureSpec); 24197 24198 StringBuilder sb = new StringBuilder("MeasureSpec: "); 24199 24200 if (mode == UNSPECIFIED) 24201 sb.append("UNSPECIFIED "); 24202 else if (mode == EXACTLY) 24203 sb.append("EXACTLY "); 24204 else if (mode == AT_MOST) 24205 sb.append("AT_MOST "); 24206 else 24207 sb.append(mode).append(" "); 24208 24209 sb.append(size); 24210 return sb.toString(); 24211 } 24212 } 24213 24214 private final class CheckForLongPress implements Runnable { 24215 private int mOriginalWindowAttachCount; 24216 private float mX; 24217 private float mY; 24218 private boolean mOriginalPressedState; 24219 24220 @Override 24221 public void run() { 24222 if ((mOriginalPressedState == isPressed()) && (mParent != null) 24223 && mOriginalWindowAttachCount == mWindowAttachCount) { 24224 if (performLongClick(mX, mY)) { 24225 mHasPerformedLongPress = true; 24226 } 24227 } 24228 } 24229 24230 public void setAnchor(float x, float y) { 24231 mX = x; 24232 mY = y; 24233 } 24234 24235 public void rememberWindowAttachCount() { 24236 mOriginalWindowAttachCount = mWindowAttachCount; 24237 } 24238 24239 public void rememberPressedState() { 24240 mOriginalPressedState = isPressed(); 24241 } 24242 } 24243 24244 private final class CheckForTap implements Runnable { 24245 public float x; 24246 public float y; 24247 24248 @Override 24249 public void run() { 24250 mPrivateFlags &= ~PFLAG_PREPRESSED; 24251 setPressed(true, x, y); 24252 checkForLongClick(ViewConfiguration.getTapTimeout(), x, y); 24253 } 24254 } 24255 24256 private final class PerformClick implements Runnable { 24257 @Override 24258 public void run() { 24259 performClick(); 24260 } 24261 } 24262 24263 /** 24264 * This method returns a ViewPropertyAnimator object, which can be used to animate 24265 * specific properties on this View. 24266 * 24267 * @return ViewPropertyAnimator The ViewPropertyAnimator associated with this View. 24268 */ 24269 public ViewPropertyAnimator animate() { 24270 if (mAnimator == null) { 24271 mAnimator = new ViewPropertyAnimator(this); 24272 } 24273 return mAnimator; 24274 } 24275 24276 /** 24277 * Sets the name of the View to be used to identify Views in Transitions. 24278 * Names should be unique in the View hierarchy. 24279 * 24280 * @param transitionName The name of the View to uniquely identify it for Transitions. 24281 */ 24282 public final void setTransitionName(String transitionName) { 24283 mTransitionName = transitionName; 24284 } 24285 24286 /** 24287 * Returns the name of the View to be used to identify Views in Transitions. 24288 * Names should be unique in the View hierarchy. 24289 * 24290 * <p>This returns null if the View has not been given a name.</p> 24291 * 24292 * @return The name used of the View to be used to identify Views in Transitions or null 24293 * if no name has been given. 24294 */ 24295 @ViewDebug.ExportedProperty 24296 public String getTransitionName() { 24297 return mTransitionName; 24298 } 24299 24300 /** 24301 * @hide 24302 */ 24303 public void requestKeyboardShortcuts(List<KeyboardShortcutGroup> data, int deviceId) { 24304 // Do nothing. 24305 } 24306 24307 /** 24308 * Interface definition for a callback to be invoked when a hardware key event is 24309 * dispatched to this view. The callback will be invoked before the key event is 24310 * given to the view. This is only useful for hardware keyboards; a software input 24311 * method has no obligation to trigger this listener. 24312 */ 24313 public interface OnKeyListener { 24314 /** 24315 * Called when a hardware key is dispatched to a view. This allows listeners to 24316 * get a chance to respond before the target view. 24317 * <p>Key presses in software keyboards will generally NOT trigger this method, 24318 * although some may elect to do so in some situations. Do not assume a 24319 * software input method has to be key-based; even if it is, it may use key presses 24320 * in a different way than you expect, so there is no way to reliably catch soft 24321 * input key presses. 24322 * 24323 * @param v The view the key has been dispatched to. 24324 * @param keyCode The code for the physical key that was pressed 24325 * @param event The KeyEvent object containing full information about 24326 * the event. 24327 * @return True if the listener has consumed the event, false otherwise. 24328 */ 24329 boolean onKey(View v, int keyCode, KeyEvent event); 24330 } 24331 24332 /** 24333 * Interface definition for a callback to be invoked when a touch event is 24334 * dispatched to this view. The callback will be invoked before the touch 24335 * event is given to the view. 24336 */ 24337 public interface OnTouchListener { 24338 /** 24339 * Called when a touch event is dispatched to a view. This allows listeners to 24340 * get a chance to respond before the target view. 24341 * 24342 * @param v The view the touch event has been dispatched to. 24343 * @param event The MotionEvent object containing full information about 24344 * the event. 24345 * @return True if the listener has consumed the event, false otherwise. 24346 */ 24347 boolean onTouch(View v, MotionEvent event); 24348 } 24349 24350 /** 24351 * Interface definition for a callback to be invoked when a hover event is 24352 * dispatched to this view. The callback will be invoked before the hover 24353 * event is given to the view. 24354 */ 24355 public interface OnHoverListener { 24356 /** 24357 * Called when a hover event is dispatched to a view. This allows listeners to 24358 * get a chance to respond before the target view. 24359 * 24360 * @param v The view the hover event has been dispatched to. 24361 * @param event The MotionEvent object containing full information about 24362 * the event. 24363 * @return True if the listener has consumed the event, false otherwise. 24364 */ 24365 boolean onHover(View v, MotionEvent event); 24366 } 24367 24368 /** 24369 * Interface definition for a callback to be invoked when a generic motion event is 24370 * dispatched to this view. The callback will be invoked before the generic motion 24371 * event is given to the view. 24372 */ 24373 public interface OnGenericMotionListener { 24374 /** 24375 * Called when a generic motion event is dispatched to a view. This allows listeners to 24376 * get a chance to respond before the target view. 24377 * 24378 * @param v The view the generic motion event has been dispatched to. 24379 * @param event The MotionEvent object containing full information about 24380 * the event. 24381 * @return True if the listener has consumed the event, false otherwise. 24382 */ 24383 boolean onGenericMotion(View v, MotionEvent event); 24384 } 24385 24386 /** 24387 * Interface definition for a callback to be invoked when a view has been clicked and held. 24388 */ 24389 public interface OnLongClickListener { 24390 /** 24391 * Called when a view has been clicked and held. 24392 * 24393 * @param v The view that was clicked and held. 24394 * 24395 * @return true if the callback consumed the long click, false otherwise. 24396 */ 24397 boolean onLongClick(View v); 24398 } 24399 24400 /** 24401 * Interface definition for a callback to be invoked when a drag is being dispatched 24402 * to this view. The callback will be invoked before the hosting view's own 24403 * onDrag(event) method. If the listener wants to fall back to the hosting view's 24404 * onDrag(event) behavior, it should return 'false' from this callback. 24405 * 24406 * <div class="special reference"> 24407 * <h3>Developer Guides</h3> 24408 * <p>For a guide to implementing drag and drop features, read the 24409 * <a href="{@docRoot}guide/topics/ui/drag-drop.html">Drag and Drop</a> developer guide.</p> 24410 * </div> 24411 */ 24412 public interface OnDragListener { 24413 /** 24414 * Called when a drag event is dispatched to a view. This allows listeners 24415 * to get a chance to override base View behavior. 24416 * 24417 * @param v The View that received the drag event. 24418 * @param event The {@link android.view.DragEvent} object for the drag event. 24419 * @return {@code true} if the drag event was handled successfully, or {@code false} 24420 * if the drag event was not handled. Note that {@code false} will trigger the View 24421 * to call its {@link #onDragEvent(DragEvent) onDragEvent()} handler. 24422 */ 24423 boolean onDrag(View v, DragEvent event); 24424 } 24425 24426 /** 24427 * Interface definition for a callback to be invoked when the focus state of 24428 * a view changed. 24429 */ 24430 public interface OnFocusChangeListener { 24431 /** 24432 * Called when the focus state of a view has changed. 24433 * 24434 * @param v The view whose state has changed. 24435 * @param hasFocus The new focus state of v. 24436 */ 24437 void onFocusChange(View v, boolean hasFocus); 24438 } 24439 24440 /** 24441 * Interface definition for a callback to be invoked when a view is clicked. 24442 */ 24443 public interface OnClickListener { 24444 /** 24445 * Called when a view has been clicked. 24446 * 24447 * @param v The view that was clicked. 24448 */ 24449 void onClick(View v); 24450 } 24451 24452 /** 24453 * Interface definition for a callback to be invoked when a view is context clicked. 24454 */ 24455 public interface OnContextClickListener { 24456 /** 24457 * Called when a view is context clicked. 24458 * 24459 * @param v The view that has been context clicked. 24460 * @return true if the callback consumed the context click, false otherwise. 24461 */ 24462 boolean onContextClick(View v); 24463 } 24464 24465 /** 24466 * Interface definition for a callback to be invoked when the context menu 24467 * for this view is being built. 24468 */ 24469 public interface OnCreateContextMenuListener { 24470 /** 24471 * Called when the context menu for this view is being built. It is not 24472 * safe to hold onto the menu after this method returns. 24473 * 24474 * @param menu The context menu that is being built 24475 * @param v The view for which the context menu is being built 24476 * @param menuInfo Extra information about the item for which the 24477 * context menu should be shown. This information will vary 24478 * depending on the class of v. 24479 */ 24480 void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo); 24481 } 24482 24483 /** 24484 * Interface definition for a callback to be invoked when the status bar changes 24485 * visibility. This reports <strong>global</strong> changes to the system UI 24486 * state, not what the application is requesting. 24487 * 24488 * @see View#setOnSystemUiVisibilityChangeListener(android.view.View.OnSystemUiVisibilityChangeListener) 24489 */ 24490 public interface OnSystemUiVisibilityChangeListener { 24491 /** 24492 * Called when the status bar changes visibility because of a call to 24493 * {@link View#setSystemUiVisibility(int)}. 24494 * 24495 * @param visibility Bitwise-or of flags {@link #SYSTEM_UI_FLAG_LOW_PROFILE}, 24496 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, and {@link #SYSTEM_UI_FLAG_FULLSCREEN}. 24497 * This tells you the <strong>global</strong> state of these UI visibility 24498 * flags, not what your app is currently applying. 24499 */ 24500 public void onSystemUiVisibilityChange(int visibility); 24501 } 24502 24503 /** 24504 * Interface definition for a callback to be invoked when this view is attached 24505 * or detached from its window. 24506 */ 24507 public interface OnAttachStateChangeListener { 24508 /** 24509 * Called when the view is attached to a window. 24510 * @param v The view that was attached 24511 */ 24512 public void onViewAttachedToWindow(View v); 24513 /** 24514 * Called when the view is detached from a window. 24515 * @param v The view that was detached 24516 */ 24517 public void onViewDetachedFromWindow(View v); 24518 } 24519 24520 /** 24521 * Listener for applying window insets on a view in a custom way. 24522 * 24523 * <p>Apps may choose to implement this interface if they want to apply custom policy 24524 * to the way that window insets are treated for a view. If an OnApplyWindowInsetsListener 24525 * is set, its 24526 * {@link OnApplyWindowInsetsListener#onApplyWindowInsets(View, WindowInsets) onApplyWindowInsets} 24527 * method will be called instead of the View's own 24528 * {@link #onApplyWindowInsets(WindowInsets) onApplyWindowInsets} method. The listener 24529 * may optionally call the parameter View's <code>onApplyWindowInsets</code> method to apply 24530 * the View's normal behavior as part of its own.</p> 24531 */ 24532 public interface OnApplyWindowInsetsListener { 24533 /** 24534 * When {@link View#setOnApplyWindowInsetsListener(View.OnApplyWindowInsetsListener) set} 24535 * on a View, this listener method will be called instead of the view's own 24536 * {@link View#onApplyWindowInsets(WindowInsets) onApplyWindowInsets} method. 24537 * 24538 * @param v The view applying window insets 24539 * @param insets The insets to apply 24540 * @return The insets supplied, minus any insets that were consumed 24541 */ 24542 public WindowInsets onApplyWindowInsets(View v, WindowInsets insets); 24543 } 24544 24545 private final class UnsetPressedState implements Runnable { 24546 @Override 24547 public void run() { 24548 setPressed(false); 24549 } 24550 } 24551 24552 /** 24553 * When a view becomes invisible checks if autofill considers the view invisible too. This 24554 * happens after the regular removal operation to make sure the operation is finished by the 24555 * time this is called. 24556 */ 24557 private static class VisibilityChangeForAutofillHandler extends Handler { 24558 private final AutofillManager mAfm; 24559 private final View mView; 24560 24561 private VisibilityChangeForAutofillHandler(@NonNull AutofillManager afm, 24562 @NonNull View view) { 24563 mAfm = afm; 24564 mView = view; 24565 } 24566 24567 @Override 24568 public void handleMessage(Message msg) { 24569 mAfm.notifyViewVisibilityChange(mView, mView.isShown()); 24570 } 24571 } 24572 24573 /** 24574 * Base class for derived classes that want to save and restore their own 24575 * state in {@link android.view.View#onSaveInstanceState()}. 24576 */ 24577 public static class BaseSavedState extends AbsSavedState { 24578 static final int START_ACTIVITY_REQUESTED_WHO_SAVED = 0b1; 24579 static final int IS_AUTOFILLED = 0b10; 24580 static final int ACCESSIBILITY_ID = 0b100; 24581 24582 // Flags that describe what data in this state is valid 24583 int mSavedData; 24584 String mStartActivityRequestWhoSaved; 24585 boolean mIsAutofilled; 24586 int mAccessibilityViewId; 24587 24588 /** 24589 * Constructor used when reading from a parcel. Reads the state of the superclass. 24590 * 24591 * @param source parcel to read from 24592 */ 24593 public BaseSavedState(Parcel source) { 24594 this(source, null); 24595 } 24596 24597 /** 24598 * Constructor used when reading from a parcel using a given class loader. 24599 * Reads the state of the superclass. 24600 * 24601 * @param source parcel to read from 24602 * @param loader ClassLoader to use for reading 24603 */ 24604 public BaseSavedState(Parcel source, ClassLoader loader) { 24605 super(source, loader); 24606 mSavedData = source.readInt(); 24607 mStartActivityRequestWhoSaved = source.readString(); 24608 mIsAutofilled = source.readBoolean(); 24609 mAccessibilityViewId = source.readInt(); 24610 } 24611 24612 /** 24613 * Constructor called by derived classes when creating their SavedState objects 24614 * 24615 * @param superState The state of the superclass of this view 24616 */ 24617 public BaseSavedState(Parcelable superState) { 24618 super(superState); 24619 } 24620 24621 @Override 24622 public void writeToParcel(Parcel out, int flags) { 24623 super.writeToParcel(out, flags); 24624 24625 out.writeInt(mSavedData); 24626 out.writeString(mStartActivityRequestWhoSaved); 24627 out.writeBoolean(mIsAutofilled); 24628 out.writeInt(mAccessibilityViewId); 24629 } 24630 24631 public static final Parcelable.Creator<BaseSavedState> CREATOR 24632 = new Parcelable.ClassLoaderCreator<BaseSavedState>() { 24633 @Override 24634 public BaseSavedState createFromParcel(Parcel in) { 24635 return new BaseSavedState(in); 24636 } 24637 24638 @Override 24639 public BaseSavedState createFromParcel(Parcel in, ClassLoader loader) { 24640 return new BaseSavedState(in, loader); 24641 } 24642 24643 @Override 24644 public BaseSavedState[] newArray(int size) { 24645 return new BaseSavedState[size]; 24646 } 24647 }; 24648 } 24649 24650 /** 24651 * A set of information given to a view when it is attached to its parent 24652 * window. 24653 */ 24654 final static class AttachInfo { 24655 interface Callbacks { 24656 void playSoundEffect(int effectId); 24657 boolean performHapticFeedback(int effectId, boolean always); 24658 } 24659 24660 /** 24661 * InvalidateInfo is used to post invalidate(int, int, int, int) messages 24662 * to a Handler. This class contains the target (View) to invalidate and 24663 * the coordinates of the dirty rectangle. 24664 * 24665 * For performance purposes, this class also implements a pool of up to 24666 * POOL_LIMIT objects that get reused. This reduces memory allocations 24667 * whenever possible. 24668 */ 24669 static class InvalidateInfo { 24670 private static final int POOL_LIMIT = 10; 24671 24672 private static final SynchronizedPool<InvalidateInfo> sPool = 24673 new SynchronizedPool<InvalidateInfo>(POOL_LIMIT); 24674 24675 View target; 24676 24677 int left; 24678 int top; 24679 int right; 24680 int bottom; 24681 24682 public static InvalidateInfo obtain() { 24683 InvalidateInfo instance = sPool.acquire(); 24684 return (instance != null) ? instance : new InvalidateInfo(); 24685 } 24686 24687 public void recycle() { 24688 target = null; 24689 sPool.release(this); 24690 } 24691 } 24692 24693 final IWindowSession mSession; 24694 24695 final IWindow mWindow; 24696 24697 final IBinder mWindowToken; 24698 24699 Display mDisplay; 24700 24701 final Callbacks mRootCallbacks; 24702 24703 IWindowId mIWindowId; 24704 WindowId mWindowId; 24705 24706 /** 24707 * The top view of the hierarchy. 24708 */ 24709 View mRootView; 24710 24711 IBinder mPanelParentWindowToken; 24712 24713 boolean mHardwareAccelerated; 24714 boolean mHardwareAccelerationRequested; 24715 ThreadedRenderer mThreadedRenderer; 24716 List<RenderNode> mPendingAnimatingRenderNodes; 24717 24718 /** 24719 * The state of the display to which the window is attached, as reported 24720 * by {@link Display#getState()}. Note that the display state constants 24721 * declared by {@link Display} do not exactly line up with the screen state 24722 * constants declared by {@link View} (there are more display states than 24723 * screen states). 24724 */ 24725 int mDisplayState = Display.STATE_UNKNOWN; 24726 24727 /** 24728 * Scale factor used by the compatibility mode 24729 */ 24730 float mApplicationScale; 24731 24732 /** 24733 * Indicates whether the application is in compatibility mode 24734 */ 24735 boolean mScalingRequired; 24736 24737 /** 24738 * Left position of this view's window 24739 */ 24740 int mWindowLeft; 24741 24742 /** 24743 * Top position of this view's window 24744 */ 24745 int mWindowTop; 24746 24747 /** 24748 * Indicates whether views need to use 32-bit drawing caches 24749 */ 24750 boolean mUse32BitDrawingCache; 24751 24752 /** 24753 * For windows that are full-screen but using insets to layout inside 24754 * of the screen areas, these are the current insets to appear inside 24755 * the overscan area of the display. 24756 */ 24757 final Rect mOverscanInsets = new Rect(); 24758 24759 /** 24760 * For windows that are full-screen but using insets to layout inside 24761 * of the screen decorations, these are the current insets for the 24762 * content of the window. 24763 */ 24764 final Rect mContentInsets = new Rect(); 24765 24766 /** 24767 * For windows that are full-screen but using insets to layout inside 24768 * of the screen decorations, these are the current insets for the 24769 * actual visible parts of the window. 24770 */ 24771 final Rect mVisibleInsets = new Rect(); 24772 24773 /** 24774 * For windows that are full-screen but using insets to layout inside 24775 * of the screen decorations, these are the current insets for the 24776 * stable system windows. 24777 */ 24778 final Rect mStableInsets = new Rect(); 24779 24780 /** 24781 * For windows that include areas that are not covered by real surface these are the outsets 24782 * for real surface. 24783 */ 24784 final Rect mOutsets = new Rect(); 24785 24786 /** 24787 * In multi-window we force show the navigation bar. Because we don't want that the surface 24788 * size changes in this mode, we instead have a flag whether the navigation bar size should 24789 * always be consumed, so the app is treated like there is no virtual navigation bar at all. 24790 */ 24791 boolean mAlwaysConsumeNavBar; 24792 24793 /** 24794 * The internal insets given by this window. This value is 24795 * supplied by the client (through 24796 * {@link ViewTreeObserver.OnComputeInternalInsetsListener}) and will 24797 * be given to the window manager when changed to be used in laying 24798 * out windows behind it. 24799 */ 24800 final ViewTreeObserver.InternalInsetsInfo mGivenInternalInsets 24801 = new ViewTreeObserver.InternalInsetsInfo(); 24802 24803 /** 24804 * Set to true when mGivenInternalInsets is non-empty. 24805 */ 24806 boolean mHasNonEmptyGivenInternalInsets; 24807 24808 /** 24809 * All views in the window's hierarchy that serve as scroll containers, 24810 * used to determine if the window can be resized or must be panned 24811 * to adjust for a soft input area. 24812 */ 24813 final ArrayList<View> mScrollContainers = new ArrayList<View>(); 24814 24815 final KeyEvent.DispatcherState mKeyDispatchState 24816 = new KeyEvent.DispatcherState(); 24817 24818 /** 24819 * Indicates whether the view's window currently has the focus. 24820 */ 24821 boolean mHasWindowFocus; 24822 24823 /** 24824 * The current visibility of the window. 24825 */ 24826 int mWindowVisibility; 24827 24828 /** 24829 * Indicates the time at which drawing started to occur. 24830 */ 24831 long mDrawingTime; 24832 24833 /** 24834 * Indicates whether or not ignoring the DIRTY_MASK flags. 24835 */ 24836 boolean mIgnoreDirtyState; 24837 24838 /** 24839 * This flag tracks when the mIgnoreDirtyState flag is set during draw(), 24840 * to avoid clearing that flag prematurely. 24841 */ 24842 boolean mSetIgnoreDirtyState = false; 24843 24844 /** 24845 * Indicates whether the view's window is currently in touch mode. 24846 */ 24847 boolean mInTouchMode; 24848 24849 /** 24850 * Indicates whether the view has requested unbuffered input dispatching for the current 24851 * event stream. 24852 */ 24853 boolean mUnbufferedDispatchRequested; 24854 24855 /** 24856 * Indicates that ViewAncestor should trigger a global layout change 24857 * the next time it performs a traversal 24858 */ 24859 boolean mRecomputeGlobalAttributes; 24860 24861 /** 24862 * Always report new attributes at next traversal. 24863 */ 24864 boolean mForceReportNewAttributes; 24865 24866 /** 24867 * Set during a traveral if any views want to keep the screen on. 24868 */ 24869 boolean mKeepScreenOn; 24870 24871 /** 24872 * Set during a traveral if the light center needs to be updated. 24873 */ 24874 boolean mNeedsUpdateLightCenter; 24875 24876 /** 24877 * Bitwise-or of all of the values that views have passed to setSystemUiVisibility(). 24878 */ 24879 int mSystemUiVisibility; 24880 24881 /** 24882 * Hack to force certain system UI visibility flags to be cleared. 24883 */ 24884 int mDisabledSystemUiVisibility; 24885 24886 /** 24887 * Last global system UI visibility reported by the window manager. 24888 */ 24889 int mGlobalSystemUiVisibility = -1; 24890 24891 /** 24892 * True if a view in this hierarchy has an OnSystemUiVisibilityChangeListener 24893 * attached. 24894 */ 24895 boolean mHasSystemUiListeners; 24896 24897 /** 24898 * Set if the window has requested to extend into the overscan region 24899 * via WindowManager.LayoutParams.FLAG_LAYOUT_IN_OVERSCAN. 24900 */ 24901 boolean mOverscanRequested; 24902 24903 /** 24904 * Set if the visibility of any views has changed. 24905 */ 24906 boolean mViewVisibilityChanged; 24907 24908 /** 24909 * Set to true if a view has been scrolled. 24910 */ 24911 boolean mViewScrollChanged; 24912 24913 /** 24914 * Set to true if high contrast mode enabled 24915 */ 24916 boolean mHighContrastText; 24917 24918 /** 24919 * Set to true if a pointer event is currently being handled. 24920 */ 24921 boolean mHandlingPointerEvent; 24922 24923 /** 24924 * Global to the view hierarchy used as a temporary for dealing with 24925 * x/y points in the transparent region computations. 24926 */ 24927 final int[] mTransparentLocation = new int[2]; 24928 24929 /** 24930 * Global to the view hierarchy used as a temporary for dealing with 24931 * x/y points in the ViewGroup.invalidateChild implementation. 24932 */ 24933 final int[] mInvalidateChildLocation = new int[2]; 24934 24935 /** 24936 * Global to the view hierarchy used as a temporary for dealing with 24937 * computing absolute on-screen location. 24938 */ 24939 final int[] mTmpLocation = new int[2]; 24940 24941 /** 24942 * Global to the view hierarchy used as a temporary for dealing with 24943 * x/y location when view is transformed. 24944 */ 24945 final float[] mTmpTransformLocation = new float[2]; 24946 24947 /** 24948 * The view tree observer used to dispatch global events like 24949 * layout, pre-draw, touch mode change, etc. 24950 */ 24951 final ViewTreeObserver mTreeObserver; 24952 24953 /** 24954 * A Canvas used by the view hierarchy to perform bitmap caching. 24955 */ 24956 Canvas mCanvas; 24957 24958 /** 24959 * The view root impl. 24960 */ 24961 final ViewRootImpl mViewRootImpl; 24962 24963 /** 24964 * A Handler supplied by a view's {@link android.view.ViewRootImpl}. This 24965 * handler can be used to pump events in the UI events queue. 24966 */ 24967 final Handler mHandler; 24968 24969 /** 24970 * Temporary for use in computing invalidate rectangles while 24971 * calling up the hierarchy. 24972 */ 24973 final Rect mTmpInvalRect = new Rect(); 24974 24975 /** 24976 * Temporary for use in computing hit areas with transformed views 24977 */ 24978 final RectF mTmpTransformRect = new RectF(); 24979 24980 /** 24981 * Temporary for use in computing hit areas with transformed views 24982 */ 24983 final RectF mTmpTransformRect1 = new RectF(); 24984 24985 /** 24986 * Temporary list of rectanges. 24987 */ 24988 final List<RectF> mTmpRectList = new ArrayList<>(); 24989 24990 /** 24991 * Temporary for use in transforming invalidation rect 24992 */ 24993 final Matrix mTmpMatrix = new Matrix(); 24994 24995 /** 24996 * Temporary for use in transforming invalidation rect 24997 */ 24998 final Transformation mTmpTransformation = new Transformation(); 24999 25000 /** 25001 * Temporary for use in querying outlines from OutlineProviders 25002 */ 25003 final Outline mTmpOutline = new Outline(); 25004 25005 /** 25006 * Temporary list for use in collecting focusable descendents of a view. 25007 */ 25008 final ArrayList<View> mTempArrayList = new ArrayList<View>(24); 25009 25010 /** 25011 * The id of the window for accessibility purposes. 25012 */ 25013 int mAccessibilityWindowId = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID; 25014 25015 /** 25016 * Flags related to accessibility processing. 25017 * 25018 * @see AccessibilityNodeInfo#FLAG_INCLUDE_NOT_IMPORTANT_VIEWS 25019 * @see AccessibilityNodeInfo#FLAG_REPORT_VIEW_IDS 25020 */ 25021 int mAccessibilityFetchFlags; 25022 25023 /** 25024 * The drawable for highlighting accessibility focus. 25025 */ 25026 Drawable mAccessibilityFocusDrawable; 25027 25028 /** 25029 * The drawable for highlighting autofilled views. 25030 * 25031 * @see #isAutofilled() 25032 */ 25033 Drawable mAutofilledDrawable; 25034 25035 /** 25036 * Show where the margins, bounds and layout bounds are for each view. 25037 */ 25038 boolean mDebugLayout = SystemProperties.getBoolean(DEBUG_LAYOUT_PROPERTY, false); 25039 25040 /** 25041 * Point used to compute visible regions. 25042 */ 25043 final Point mPoint = new Point(); 25044 25045 /** 25046 * Used to track which View originated a requestLayout() call, used when 25047 * requestLayout() is called during layout. 25048 */ 25049 View mViewRequestingLayout; 25050 25051 /** 25052 * Used to track views that need (at least) a partial relayout at their current size 25053 * during the next traversal. 25054 */ 25055 List<View> mPartialLayoutViews = new ArrayList<>(); 25056 25057 /** 25058 * Swapped with mPartialLayoutViews during layout to avoid concurrent 25059 * modification. Lazily assigned during ViewRootImpl layout. 25060 */ 25061 List<View> mEmptyPartialLayoutViews; 25062 25063 /** 25064 * Used to track the identity of the current drag operation. 25065 */ 25066 IBinder mDragToken; 25067 25068 /** 25069 * The drag shadow surface for the current drag operation. 25070 */ 25071 public Surface mDragSurface; 25072 25073 25074 /** 25075 * The view that currently has a tooltip displayed. 25076 */ 25077 View mTooltipHost; 25078 25079 /** 25080 * Creates a new set of attachment information with the specified 25081 * events handler and thread. 25082 * 25083 * @param handler the events handler the view must use 25084 */ 25085 AttachInfo(IWindowSession session, IWindow window, Display display, 25086 ViewRootImpl viewRootImpl, Handler handler, Callbacks effectPlayer, 25087 Context context) { 25088 mSession = session; 25089 mWindow = window; 25090 mWindowToken = window.asBinder(); 25091 mDisplay = display; 25092 mViewRootImpl = viewRootImpl; 25093 mHandler = handler; 25094 mRootCallbacks = effectPlayer; 25095 mTreeObserver = new ViewTreeObserver(context); 25096 } 25097 } 25098 25099 /** 25100 * <p>ScrollabilityCache holds various fields used by a View when scrolling 25101 * is supported. This avoids keeping too many unused fields in most 25102 * instances of View.</p> 25103 */ 25104 private static class ScrollabilityCache implements Runnable { 25105 25106 /** 25107 * Scrollbars are not visible 25108 */ 25109 public static final int OFF = 0; 25110 25111 /** 25112 * Scrollbars are visible 25113 */ 25114 public static final int ON = 1; 25115 25116 /** 25117 * Scrollbars are fading away 25118 */ 25119 public static final int FADING = 2; 25120 25121 public boolean fadeScrollBars; 25122 25123 public int fadingEdgeLength; 25124 public int scrollBarDefaultDelayBeforeFade; 25125 public int scrollBarFadeDuration; 25126 25127 public int scrollBarSize; 25128 public int scrollBarMinTouchTarget; 25129 public ScrollBarDrawable scrollBar; 25130 public float[] interpolatorValues; 25131 public View host; 25132 25133 public final Paint paint; 25134 public final Matrix matrix; 25135 public Shader shader; 25136 25137 public final Interpolator scrollBarInterpolator = new Interpolator(1, 2); 25138 25139 private static final float[] OPAQUE = { 255 }; 25140 private static final float[] TRANSPARENT = { 0.0f }; 25141 25142 /** 25143 * When fading should start. This time moves into the future every time 25144 * a new scroll happens. Measured based on SystemClock.uptimeMillis() 25145 */ 25146 public long fadeStartTime; 25147 25148 25149 /** 25150 * The current state of the scrollbars: ON, OFF, or FADING 25151 */ 25152 public int state = OFF; 25153 25154 private int mLastColor; 25155 25156 public final Rect mScrollBarBounds = new Rect(); 25157 public final Rect mScrollBarTouchBounds = new Rect(); 25158 25159 public static final int NOT_DRAGGING = 0; 25160 public static final int DRAGGING_VERTICAL_SCROLL_BAR = 1; 25161 public static final int DRAGGING_HORIZONTAL_SCROLL_BAR = 2; 25162 public int mScrollBarDraggingState = NOT_DRAGGING; 25163 25164 public float mScrollBarDraggingPos = 0; 25165 25166 public ScrollabilityCache(ViewConfiguration configuration, View host) { 25167 fadingEdgeLength = configuration.getScaledFadingEdgeLength(); 25168 scrollBarSize = configuration.getScaledScrollBarSize(); 25169 scrollBarMinTouchTarget = configuration.getScaledMinScrollbarTouchTarget(); 25170 scrollBarDefaultDelayBeforeFade = ViewConfiguration.getScrollDefaultDelay(); 25171 scrollBarFadeDuration = ViewConfiguration.getScrollBarFadeDuration(); 25172 25173 paint = new Paint(); 25174 matrix = new Matrix(); 25175 // use use a height of 1, and then wack the matrix each time we 25176 // actually use it. 25177 shader = new LinearGradient(0, 0, 0, 1, 0xFF000000, 0, Shader.TileMode.CLAMP); 25178 paint.setShader(shader); 25179 paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); 25180 25181 this.host = host; 25182 } 25183 25184 public void setFadeColor(int color) { 25185 if (color != mLastColor) { 25186 mLastColor = color; 25187 25188 if (color != 0) { 25189 shader = new LinearGradient(0, 0, 0, 1, color | 0xFF000000, 25190 color & 0x00FFFFFF, Shader.TileMode.CLAMP); 25191 paint.setShader(shader); 25192 // Restore the default transfer mode (src_over) 25193 paint.setXfermode(null); 25194 } else { 25195 shader = new LinearGradient(0, 0, 0, 1, 0xFF000000, 0, Shader.TileMode.CLAMP); 25196 paint.setShader(shader); 25197 paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); 25198 } 25199 } 25200 } 25201 25202 public void run() { 25203 long now = AnimationUtils.currentAnimationTimeMillis(); 25204 if (now >= fadeStartTime) { 25205 25206 // the animation fades the scrollbars out by changing 25207 // the opacity (alpha) from fully opaque to fully 25208 // transparent 25209 int nextFrame = (int) now; 25210 int framesCount = 0; 25211 25212 Interpolator interpolator = scrollBarInterpolator; 25213 25214 // Start opaque 25215 interpolator.setKeyFrame(framesCount++, nextFrame, OPAQUE); 25216 25217 // End transparent 25218 nextFrame += scrollBarFadeDuration; 25219 interpolator.setKeyFrame(framesCount, nextFrame, TRANSPARENT); 25220 25221 state = FADING; 25222 25223 // Kick off the fade animation 25224 host.invalidate(true); 25225 } 25226 } 25227 } 25228 25229 /** 25230 * Resuable callback for sending 25231 * {@link AccessibilityEvent#TYPE_VIEW_SCROLLED} accessibility event. 25232 */ 25233 private class SendViewScrolledAccessibilityEvent implements Runnable { 25234 public volatile boolean mIsPending; 25235 25236 public void run() { 25237 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SCROLLED); 25238 mIsPending = false; 25239 } 25240 } 25241 25242 /** 25243 * <p> 25244 * This class represents a delegate that can be registered in a {@link View} 25245 * to enhance accessibility support via composition rather via inheritance. 25246 * It is specifically targeted to widget developers that extend basic View 25247 * classes i.e. classes in package android.view, that would like their 25248 * applications to be backwards compatible. 25249 * </p> 25250 * <div class="special reference"> 25251 * <h3>Developer Guides</h3> 25252 * <p>For more information about making applications accessible, read the 25253 * <a href="{@docRoot}guide/topics/ui/accessibility/index.html">Accessibility</a> 25254 * developer guide.</p> 25255 * </div> 25256 * <p> 25257 * A scenario in which a developer would like to use an accessibility delegate 25258 * is overriding a method introduced in a later API version than the minimal API 25259 * version supported by the application. For example, the method 25260 * {@link View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} is not available 25261 * in API version 4 when the accessibility APIs were first introduced. If a 25262 * developer would like his application to run on API version 4 devices (assuming 25263 * all other APIs used by the application are version 4 or lower) and take advantage 25264 * of this method, instead of overriding the method which would break the application's 25265 * backwards compatibility, he can override the corresponding method in this 25266 * delegate and register the delegate in the target View if the API version of 25267 * the system is high enough, i.e. the API version is the same as or higher than the API 25268 * version that introduced 25269 * {@link View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)}. 25270 * </p> 25271 * <p> 25272 * Here is an example implementation: 25273 * </p> 25274 * <code><pre><p> 25275 * if (Build.VERSION.SDK_INT >= 14) { 25276 * // If the API version is equal of higher than the version in 25277 * // which onInitializeAccessibilityNodeInfo was introduced we 25278 * // register a delegate with a customized implementation. 25279 * View view = findViewById(R.id.view_id); 25280 * view.setAccessibilityDelegate(new AccessibilityDelegate() { 25281 * public void onInitializeAccessibilityNodeInfo(View host, 25282 * AccessibilityNodeInfo info) { 25283 * // Let the default implementation populate the info. 25284 * super.onInitializeAccessibilityNodeInfo(host, info); 25285 * // Set some other information. 25286 * info.setEnabled(host.isEnabled()); 25287 * } 25288 * }); 25289 * } 25290 * </code></pre></p> 25291 * <p> 25292 * This delegate contains methods that correspond to the accessibility methods 25293 * in View. If a delegate has been specified the implementation in View hands 25294 * off handling to the corresponding method in this delegate. The default 25295 * implementation the delegate methods behaves exactly as the corresponding 25296 * method in View for the case of no accessibility delegate been set. Hence, 25297 * to customize the behavior of a View method, clients can override only the 25298 * corresponding delegate method without altering the behavior of the rest 25299 * accessibility related methods of the host view. 25300 * </p> 25301 * <p> 25302 * <strong>Note:</strong> On platform versions prior to 25303 * {@link android.os.Build.VERSION_CODES#M API 23}, delegate methods on 25304 * views in the {@code android.widget.*} package are called <i>before</i> 25305 * host methods. This prevents certain properties such as class name from 25306 * being modified by overriding 25307 * {@link AccessibilityDelegate#onInitializeAccessibilityNodeInfo(View, AccessibilityNodeInfo)}, 25308 * as any changes will be overwritten by the host class. 25309 * <p> 25310 * Starting in {@link android.os.Build.VERSION_CODES#M API 23}, delegate 25311 * methods are called <i>after</i> host methods, which all properties to be 25312 * modified without being overwritten by the host class. 25313 */ 25314 public static class AccessibilityDelegate { 25315 25316 /** 25317 * Sends an accessibility event of the given type. If accessibility is not 25318 * enabled this method has no effect. 25319 * <p> 25320 * The default implementation behaves as {@link View#sendAccessibilityEvent(int) 25321 * View#sendAccessibilityEvent(int)} for the case of no accessibility delegate 25322 * been set. 25323 * </p> 25324 * 25325 * @param host The View hosting the delegate. 25326 * @param eventType The type of the event to send. 25327 * 25328 * @see View#sendAccessibilityEvent(int) View#sendAccessibilityEvent(int) 25329 */ 25330 public void sendAccessibilityEvent(View host, int eventType) { 25331 host.sendAccessibilityEventInternal(eventType); 25332 } 25333 25334 /** 25335 * Performs the specified accessibility action on the view. For 25336 * possible accessibility actions look at {@link AccessibilityNodeInfo}. 25337 * <p> 25338 * The default implementation behaves as 25339 * {@link View#performAccessibilityAction(int, Bundle) 25340 * View#performAccessibilityAction(int, Bundle)} for the case of 25341 * no accessibility delegate been set. 25342 * </p> 25343 * 25344 * @param action The action to perform. 25345 * @return Whether the action was performed. 25346 * 25347 * @see View#performAccessibilityAction(int, Bundle) 25348 * View#performAccessibilityAction(int, Bundle) 25349 */ 25350 public boolean performAccessibilityAction(View host, int action, Bundle args) { 25351 return host.performAccessibilityActionInternal(action, args); 25352 } 25353 25354 /** 25355 * Sends an accessibility event. This method behaves exactly as 25356 * {@link #sendAccessibilityEvent(View, int)} but takes as an argument an 25357 * empty {@link AccessibilityEvent} and does not perform a check whether 25358 * accessibility is enabled. 25359 * <p> 25360 * The default implementation behaves as 25361 * {@link View#sendAccessibilityEventUnchecked(AccessibilityEvent) 25362 * View#sendAccessibilityEventUnchecked(AccessibilityEvent)} for 25363 * the case of no accessibility delegate been set. 25364 * </p> 25365 * 25366 * @param host The View hosting the delegate. 25367 * @param event The event to send. 25368 * 25369 * @see View#sendAccessibilityEventUnchecked(AccessibilityEvent) 25370 * View#sendAccessibilityEventUnchecked(AccessibilityEvent) 25371 */ 25372 public void sendAccessibilityEventUnchecked(View host, AccessibilityEvent event) { 25373 host.sendAccessibilityEventUncheckedInternal(event); 25374 } 25375 25376 /** 25377 * Dispatches an {@link AccessibilityEvent} to the host {@link View} first and then 25378 * to its children for adding their text content to the event. 25379 * <p> 25380 * The default implementation behaves as 25381 * {@link View#dispatchPopulateAccessibilityEvent(AccessibilityEvent) 25382 * View#dispatchPopulateAccessibilityEvent(AccessibilityEvent)} for 25383 * the case of no accessibility delegate been set. 25384 * </p> 25385 * 25386 * @param host The View hosting the delegate. 25387 * @param event The event. 25388 * @return True if the event population was completed. 25389 * 25390 * @see View#dispatchPopulateAccessibilityEvent(AccessibilityEvent) 25391 * View#dispatchPopulateAccessibilityEvent(AccessibilityEvent) 25392 */ 25393 public boolean dispatchPopulateAccessibilityEvent(View host, AccessibilityEvent event) { 25394 return host.dispatchPopulateAccessibilityEventInternal(event); 25395 } 25396 25397 /** 25398 * Gives a chance to the host View to populate the accessibility event with its 25399 * text content. 25400 * <p> 25401 * The default implementation behaves as 25402 * {@link View#onPopulateAccessibilityEvent(AccessibilityEvent) 25403 * View#onPopulateAccessibilityEvent(AccessibilityEvent)} for 25404 * the case of no accessibility delegate been set. 25405 * </p> 25406 * 25407 * @param host The View hosting the delegate. 25408 * @param event The accessibility event which to populate. 25409 * 25410 * @see View#onPopulateAccessibilityEvent(AccessibilityEvent) 25411 * View#onPopulateAccessibilityEvent(AccessibilityEvent) 25412 */ 25413 public void onPopulateAccessibilityEvent(View host, AccessibilityEvent event) { 25414 host.onPopulateAccessibilityEventInternal(event); 25415 } 25416 25417 /** 25418 * Initializes an {@link AccessibilityEvent} with information about the 25419 * the host View which is the event source. 25420 * <p> 25421 * The default implementation behaves as 25422 * {@link View#onInitializeAccessibilityEvent(AccessibilityEvent) 25423 * View#onInitializeAccessibilityEvent(AccessibilityEvent)} for 25424 * the case of no accessibility delegate been set. 25425 * </p> 25426 * 25427 * @param host The View hosting the delegate. 25428 * @param event The event to initialize. 25429 * 25430 * @see View#onInitializeAccessibilityEvent(AccessibilityEvent) 25431 * View#onInitializeAccessibilityEvent(AccessibilityEvent) 25432 */ 25433 public void onInitializeAccessibilityEvent(View host, AccessibilityEvent event) { 25434 host.onInitializeAccessibilityEventInternal(event); 25435 } 25436 25437 /** 25438 * Initializes an {@link AccessibilityNodeInfo} with information about the host view. 25439 * <p> 25440 * The default implementation behaves as 25441 * {@link View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo) 25442 * View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} for 25443 * the case of no accessibility delegate been set. 25444 * </p> 25445 * 25446 * @param host The View hosting the delegate. 25447 * @param info The instance to initialize. 25448 * 25449 * @see View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo) 25450 * View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo) 25451 */ 25452 public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) { 25453 host.onInitializeAccessibilityNodeInfoInternal(info); 25454 } 25455 25456 /** 25457 * Adds extra data to an {@link AccessibilityNodeInfo} based on an explicit request for the 25458 * additional data. 25459 * <p> 25460 * This method only needs to be implemented if the View offers to provide additional data. 25461 * </p> 25462 * <p> 25463 * The default implementation behaves as 25464 * {@link View#addExtraDataToAccessibilityNodeInfo(AccessibilityNodeInfo, int) for 25465 * the case where no accessibility delegate is set. 25466 * </p> 25467 * 25468 * @param host The View hosting the delegate. Never {@code null}. 25469 * @param info The info to which to add the extra data. Never {@code null}. 25470 * @param extraDataKey A key specifying the type of extra data to add to the info. The 25471 * extra data should be added to the {@link Bundle} returned by 25472 * the info's {@link AccessibilityNodeInfo#getExtras} method. Never 25473 * {@code null}. 25474 * @param arguments A {@link Bundle} holding any arguments relevant for this request. 25475 * May be {@code null} if the if the service provided no arguments. 25476 * 25477 * @see AccessibilityNodeInfo#setExtraAvailableData 25478 */ 25479 public void addExtraDataToAccessibilityNodeInfo(@NonNull View host, 25480 @NonNull AccessibilityNodeInfo info, @NonNull String extraDataKey, 25481 @Nullable Bundle arguments) { 25482 host.addExtraDataToAccessibilityNodeInfo(info, extraDataKey, arguments); 25483 } 25484 25485 /** 25486 * Called when a child of the host View has requested sending an 25487 * {@link AccessibilityEvent} and gives an opportunity to the parent (the host) 25488 * to augment the event. 25489 * <p> 25490 * The default implementation behaves as 25491 * {@link ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent) 25492 * ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent)} for 25493 * the case of no accessibility delegate been set. 25494 * </p> 25495 * 25496 * @param host The View hosting the delegate. 25497 * @param child The child which requests sending the event. 25498 * @param event The event to be sent. 25499 * @return True if the event should be sent 25500 * 25501 * @see ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent) 25502 * ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent) 25503 */ 25504 public boolean onRequestSendAccessibilityEvent(ViewGroup host, View child, 25505 AccessibilityEvent event) { 25506 return host.onRequestSendAccessibilityEventInternal(child, event); 25507 } 25508 25509 /** 25510 * Gets the provider for managing a virtual view hierarchy rooted at this View 25511 * and reported to {@link android.accessibilityservice.AccessibilityService}s 25512 * that explore the window content. 25513 * <p> 25514 * The default implementation behaves as 25515 * {@link View#getAccessibilityNodeProvider() View#getAccessibilityNodeProvider()} for 25516 * the case of no accessibility delegate been set. 25517 * </p> 25518 * 25519 * @return The provider. 25520 * 25521 * @see AccessibilityNodeProvider 25522 */ 25523 public AccessibilityNodeProvider getAccessibilityNodeProvider(View host) { 25524 return null; 25525 } 25526 25527 /** 25528 * Returns an {@link AccessibilityNodeInfo} representing the host view from the 25529 * point of view of an {@link android.accessibilityservice.AccessibilityService}. 25530 * This method is responsible for obtaining an accessibility node info from a 25531 * pool of reusable instances and calling 25532 * {@link #onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} on the host 25533 * view to initialize the former. 25534 * <p> 25535 * <strong>Note:</strong> The client is responsible for recycling the obtained 25536 * instance by calling {@link AccessibilityNodeInfo#recycle()} to minimize object 25537 * creation. 25538 * </p> 25539 * <p> 25540 * The default implementation behaves as 25541 * {@link View#createAccessibilityNodeInfo() View#createAccessibilityNodeInfo()} for 25542 * the case of no accessibility delegate been set. 25543 * </p> 25544 * @return A populated {@link AccessibilityNodeInfo}. 25545 * 25546 * @see AccessibilityNodeInfo 25547 * 25548 * @hide 25549 */ 25550 public AccessibilityNodeInfo createAccessibilityNodeInfo(View host) { 25551 return host.createAccessibilityNodeInfoInternal(); 25552 } 25553 } 25554 25555 private static class MatchIdPredicate implements Predicate<View> { 25556 public int mId; 25557 25558 @Override 25559 public boolean test(View view) { 25560 return (view.mID == mId); 25561 } 25562 } 25563 25564 private static class MatchLabelForPredicate implements Predicate<View> { 25565 private int mLabeledId; 25566 25567 @Override 25568 public boolean test(View view) { 25569 return (view.mLabelForId == mLabeledId); 25570 } 25571 } 25572 25573 private class SendViewStateChangedAccessibilityEvent implements Runnable { 25574 private int mChangeTypes = 0; 25575 private boolean mPosted; 25576 private boolean mPostedWithDelay; 25577 private long mLastEventTimeMillis; 25578 25579 @Override 25580 public void run() { 25581 mPosted = false; 25582 mPostedWithDelay = false; 25583 mLastEventTimeMillis = SystemClock.uptimeMillis(); 25584 if (AccessibilityManager.getInstance(mContext).isEnabled()) { 25585 final AccessibilityEvent event = AccessibilityEvent.obtain(); 25586 event.setEventType(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED); 25587 event.setContentChangeTypes(mChangeTypes); 25588 sendAccessibilityEventUnchecked(event); 25589 } 25590 mChangeTypes = 0; 25591 } 25592 25593 public void runOrPost(int changeType) { 25594 mChangeTypes |= changeType; 25595 25596 // If this is a live region or the child of a live region, collect 25597 // all events from this frame and send them on the next frame. 25598 if (inLiveRegion()) { 25599 // If we're already posted with a delay, remove that. 25600 if (mPostedWithDelay) { 25601 removeCallbacks(this); 25602 mPostedWithDelay = false; 25603 } 25604 // Only post if we're not already posted. 25605 if (!mPosted) { 25606 post(this); 25607 mPosted = true; 25608 } 25609 return; 25610 } 25611 25612 if (mPosted) { 25613 return; 25614 } 25615 25616 final long timeSinceLastMillis = SystemClock.uptimeMillis() - mLastEventTimeMillis; 25617 final long minEventIntevalMillis = 25618 ViewConfiguration.getSendRecurringAccessibilityEventsInterval(); 25619 if (timeSinceLastMillis >= minEventIntevalMillis) { 25620 removeCallbacks(this); 25621 run(); 25622 } else { 25623 postDelayed(this, minEventIntevalMillis - timeSinceLastMillis); 25624 mPostedWithDelay = true; 25625 } 25626 } 25627 } 25628 25629 private boolean inLiveRegion() { 25630 if (getAccessibilityLiveRegion() != View.ACCESSIBILITY_LIVE_REGION_NONE) { 25631 return true; 25632 } 25633 25634 ViewParent parent = getParent(); 25635 while (parent instanceof View) { 25636 if (((View) parent).getAccessibilityLiveRegion() 25637 != View.ACCESSIBILITY_LIVE_REGION_NONE) { 25638 return true; 25639 } 25640 parent = parent.getParent(); 25641 } 25642 25643 return false; 25644 } 25645 25646 /** 25647 * Dump all private flags in readable format, useful for documentation and 25648 * sanity checking. 25649 */ 25650 private static void dumpFlags() { 25651 final HashMap<String, String> found = Maps.newHashMap(); 25652 try { 25653 for (Field field : View.class.getDeclaredFields()) { 25654 final int modifiers = field.getModifiers(); 25655 if (Modifier.isStatic(modifiers) && Modifier.isFinal(modifiers)) { 25656 if (field.getType().equals(int.class)) { 25657 final int value = field.getInt(null); 25658 dumpFlag(found, field.getName(), value); 25659 } else if (field.getType().equals(int[].class)) { 25660 final int[] values = (int[]) field.get(null); 25661 for (int i = 0; i < values.length; i++) { 25662 dumpFlag(found, field.getName() + "[" + i + "]", values[i]); 25663 } 25664 } 25665 } 25666 } 25667 } catch (IllegalAccessException e) { 25668 throw new RuntimeException(e); 25669 } 25670 25671 final ArrayList<String> keys = Lists.newArrayList(); 25672 keys.addAll(found.keySet()); 25673 Collections.sort(keys); 25674 for (String key : keys) { 25675 Log.d(VIEW_LOG_TAG, found.get(key)); 25676 } 25677 } 25678 25679 private static void dumpFlag(HashMap<String, String> found, String name, int value) { 25680 // Sort flags by prefix, then by bits, always keeping unique keys 25681 final String bits = String.format("%32s", Integer.toBinaryString(value)).replace('0', ' '); 25682 final int prefix = name.indexOf('_'); 25683 final String key = (prefix > 0 ? name.substring(0, prefix) : name) + bits + name; 25684 final String output = bits + " " + name; 25685 found.put(key, output); 25686 } 25687 25688 /** {@hide} */ 25689 public void encode(@NonNull ViewHierarchyEncoder stream) { 25690 stream.beginObject(this); 25691 encodeProperties(stream); 25692 stream.endObject(); 25693 } 25694 25695 /** {@hide} */ 25696 @CallSuper 25697 protected void encodeProperties(@NonNull ViewHierarchyEncoder stream) { 25698 Object resolveId = ViewDebug.resolveId(getContext(), mID); 25699 if (resolveId instanceof String) { 25700 stream.addProperty("id", (String) resolveId); 25701 } else { 25702 stream.addProperty("id", mID); 25703 } 25704 25705 stream.addProperty("misc:transformation.alpha", 25706 mTransformationInfo != null ? mTransformationInfo.mAlpha : 0); 25707 stream.addProperty("misc:transitionName", getTransitionName()); 25708 25709 // layout 25710 stream.addProperty("layout:left", mLeft); 25711 stream.addProperty("layout:right", mRight); 25712 stream.addProperty("layout:top", mTop); 25713 stream.addProperty("layout:bottom", mBottom); 25714 stream.addProperty("layout:width", getWidth()); 25715 stream.addProperty("layout:height", getHeight()); 25716 stream.addProperty("layout:layoutDirection", getLayoutDirection()); 25717 stream.addProperty("layout:layoutRtl", isLayoutRtl()); 25718 stream.addProperty("layout:hasTransientState", hasTransientState()); 25719 stream.addProperty("layout:baseline", getBaseline()); 25720 25721 // layout params 25722 ViewGroup.LayoutParams layoutParams = getLayoutParams(); 25723 if (layoutParams != null) { 25724 stream.addPropertyKey("layoutParams"); 25725 layoutParams.encode(stream); 25726 } 25727 25728 // scrolling 25729 stream.addProperty("scrolling:scrollX", mScrollX); 25730 stream.addProperty("scrolling:scrollY", mScrollY); 25731 25732 // padding 25733 stream.addProperty("padding:paddingLeft", mPaddingLeft); 25734 stream.addProperty("padding:paddingRight", mPaddingRight); 25735 stream.addProperty("padding:paddingTop", mPaddingTop); 25736 stream.addProperty("padding:paddingBottom", mPaddingBottom); 25737 stream.addProperty("padding:userPaddingRight", mUserPaddingRight); 25738 stream.addProperty("padding:userPaddingLeft", mUserPaddingLeft); 25739 stream.addProperty("padding:userPaddingBottom", mUserPaddingBottom); 25740 stream.addProperty("padding:userPaddingStart", mUserPaddingStart); 25741 stream.addProperty("padding:userPaddingEnd", mUserPaddingEnd); 25742 25743 // measurement 25744 stream.addProperty("measurement:minHeight", mMinHeight); 25745 stream.addProperty("measurement:minWidth", mMinWidth); 25746 stream.addProperty("measurement:measuredWidth", mMeasuredWidth); 25747 stream.addProperty("measurement:measuredHeight", mMeasuredHeight); 25748 25749 // drawing 25750 stream.addProperty("drawing:elevation", getElevation()); 25751 stream.addProperty("drawing:translationX", getTranslationX()); 25752 stream.addProperty("drawing:translationY", getTranslationY()); 25753 stream.addProperty("drawing:translationZ", getTranslationZ()); 25754 stream.addProperty("drawing:rotation", getRotation()); 25755 stream.addProperty("drawing:rotationX", getRotationX()); 25756 stream.addProperty("drawing:rotationY", getRotationY()); 25757 stream.addProperty("drawing:scaleX", getScaleX()); 25758 stream.addProperty("drawing:scaleY", getScaleY()); 25759 stream.addProperty("drawing:pivotX", getPivotX()); 25760 stream.addProperty("drawing:pivotY", getPivotY()); 25761 stream.addProperty("drawing:opaque", isOpaque()); 25762 stream.addProperty("drawing:alpha", getAlpha()); 25763 stream.addProperty("drawing:transitionAlpha", getTransitionAlpha()); 25764 stream.addProperty("drawing:shadow", hasShadow()); 25765 stream.addProperty("drawing:solidColor", getSolidColor()); 25766 stream.addProperty("drawing:layerType", mLayerType); 25767 stream.addProperty("drawing:willNotDraw", willNotDraw()); 25768 stream.addProperty("drawing:hardwareAccelerated", isHardwareAccelerated()); 25769 stream.addProperty("drawing:willNotCacheDrawing", willNotCacheDrawing()); 25770 stream.addProperty("drawing:drawingCacheEnabled", isDrawingCacheEnabled()); 25771 stream.addProperty("drawing:overlappingRendering", hasOverlappingRendering()); 25772 25773 // focus 25774 stream.addProperty("focus:hasFocus", hasFocus()); 25775 stream.addProperty("focus:isFocused", isFocused()); 25776 stream.addProperty("focus:focusable", getFocusable()); 25777 stream.addProperty("focus:isFocusable", isFocusable()); 25778 stream.addProperty("focus:isFocusableInTouchMode", isFocusableInTouchMode()); 25779 25780 stream.addProperty("misc:clickable", isClickable()); 25781 stream.addProperty("misc:pressed", isPressed()); 25782 stream.addProperty("misc:selected", isSelected()); 25783 stream.addProperty("misc:touchMode", isInTouchMode()); 25784 stream.addProperty("misc:hovered", isHovered()); 25785 stream.addProperty("misc:activated", isActivated()); 25786 25787 stream.addProperty("misc:visibility", getVisibility()); 25788 stream.addProperty("misc:fitsSystemWindows", getFitsSystemWindows()); 25789 stream.addProperty("misc:filterTouchesWhenObscured", getFilterTouchesWhenObscured()); 25790 25791 stream.addProperty("misc:enabled", isEnabled()); 25792 stream.addProperty("misc:soundEffectsEnabled", isSoundEffectsEnabled()); 25793 stream.addProperty("misc:hapticFeedbackEnabled", isHapticFeedbackEnabled()); 25794 25795 // theme attributes 25796 Resources.Theme theme = getContext().getTheme(); 25797 if (theme != null) { 25798 stream.addPropertyKey("theme"); 25799 theme.encode(stream); 25800 } 25801 25802 // view attribute information 25803 int n = mAttributes != null ? mAttributes.length : 0; 25804 stream.addProperty("meta:__attrCount__", n/2); 25805 for (int i = 0; i < n; i += 2) { 25806 stream.addProperty("meta:__attr__" + mAttributes[i], mAttributes[i+1]); 25807 } 25808 25809 stream.addProperty("misc:scrollBarStyle", getScrollBarStyle()); 25810 25811 // text 25812 stream.addProperty("text:textDirection", getTextDirection()); 25813 stream.addProperty("text:textAlignment", getTextAlignment()); 25814 25815 // accessibility 25816 CharSequence contentDescription = getContentDescription(); 25817 stream.addProperty("accessibility:contentDescription", 25818 contentDescription == null ? "" : contentDescription.toString()); 25819 stream.addProperty("accessibility:labelFor", getLabelFor()); 25820 stream.addProperty("accessibility:importantForAccessibility", getImportantForAccessibility()); 25821 } 25822 25823 /** 25824 * Determine if this view is rendered on a round wearable device and is the main view 25825 * on the screen. 25826 */ 25827 boolean shouldDrawRoundScrollbar() { 25828 if (!mResources.getConfiguration().isScreenRound() || mAttachInfo == null) { 25829 return false; 25830 } 25831 25832 final View rootView = getRootView(); 25833 final WindowInsets insets = getRootWindowInsets(); 25834 25835 int height = getHeight(); 25836 int width = getWidth(); 25837 int displayHeight = rootView.getHeight(); 25838 int displayWidth = rootView.getWidth(); 25839 25840 if (height != displayHeight || width != displayWidth) { 25841 return false; 25842 } 25843 25844 getLocationInWindow(mAttachInfo.mTmpLocation); 25845 return mAttachInfo.mTmpLocation[0] == insets.getStableInsetLeft() 25846 && mAttachInfo.mTmpLocation[1] == insets.getStableInsetTop(); 25847 } 25848 25849 /** 25850 * Sets the tooltip text which will be displayed in a small popup next to the view. 25851 * <p> 25852 * The tooltip will be displayed: 25853 * <ul> 25854 * <li>On long click, unless it is handled otherwise (by OnLongClickListener or a context 25855 * menu). </li> 25856 * <li>On hover, after a brief delay since the pointer has stopped moving </li> 25857 * </ul> 25858 * <p> 25859 * <strong>Note:</strong> Do not override this method, as it will have no 25860 * effect on the text displayed in the tooltip. 25861 * 25862 * @param tooltipText the tooltip text, or null if no tooltip is required 25863 * @see #getTooltipText() 25864 * @attr ref android.R.styleable#View_tooltipText 25865 */ 25866 public void setTooltipText(@Nullable CharSequence tooltipText) { 25867 if (TextUtils.isEmpty(tooltipText)) { 25868 setFlags(0, TOOLTIP); 25869 hideTooltip(); 25870 mTooltipInfo = null; 25871 } else { 25872 setFlags(TOOLTIP, TOOLTIP); 25873 if (mTooltipInfo == null) { 25874 mTooltipInfo = new TooltipInfo(); 25875 mTooltipInfo.mShowTooltipRunnable = this::showHoverTooltip; 25876 mTooltipInfo.mHideTooltipRunnable = this::hideTooltip; 25877 } 25878 mTooltipInfo.mTooltipText = tooltipText; 25879 if (mTooltipInfo.mTooltipPopup != null && mTooltipInfo.mTooltipPopup.isShowing()) { 25880 mTooltipInfo.mTooltipPopup.updateContent(mTooltipInfo.mTooltipText); 25881 } 25882 } 25883 } 25884 25885 /** 25886 * @hide Binary compatibility stub. To be removed when we finalize O APIs. 25887 */ 25888 public void setTooltip(@Nullable CharSequence tooltipText) { 25889 setTooltipText(tooltipText); 25890 } 25891 25892 /** 25893 * Returns the view's tooltip text. 25894 * 25895 * <strong>Note:</strong> Do not override this method, as it will have no 25896 * effect on the text displayed in the tooltip. You must call 25897 * {@link #setTooltipText(CharSequence)} to modify the tooltip text. 25898 * 25899 * @return the tooltip text 25900 * @see #setTooltipText(CharSequence) 25901 * @attr ref android.R.styleable#View_tooltipText 25902 */ 25903 @Nullable 25904 public CharSequence getTooltipText() { 25905 return mTooltipInfo != null ? mTooltipInfo.mTooltipText : null; 25906 } 25907 25908 /** 25909 * @hide Binary compatibility stub. To be removed when we finalize O APIs. 25910 */ 25911 @Nullable 25912 public CharSequence getTooltip() { 25913 return getTooltipText(); 25914 } 25915 25916 private boolean showTooltip(int x, int y, boolean fromLongClick) { 25917 if (mAttachInfo == null || mTooltipInfo == null) { 25918 return false; 25919 } 25920 if ((mViewFlags & ENABLED_MASK) != ENABLED) { 25921 return false; 25922 } 25923 if (TextUtils.isEmpty(mTooltipInfo.mTooltipText)) { 25924 return false; 25925 } 25926 hideTooltip(); 25927 mTooltipInfo.mTooltipFromLongClick = fromLongClick; 25928 mTooltipInfo.mTooltipPopup = new TooltipPopup(getContext()); 25929 final boolean fromTouch = (mPrivateFlags3 & PFLAG3_FINGER_DOWN) == PFLAG3_FINGER_DOWN; 25930 mTooltipInfo.mTooltipPopup.show(this, x, y, fromTouch, mTooltipInfo.mTooltipText); 25931 mAttachInfo.mTooltipHost = this; 25932 return true; 25933 } 25934 25935 void hideTooltip() { 25936 if (mTooltipInfo == null) { 25937 return; 25938 } 25939 removeCallbacks(mTooltipInfo.mShowTooltipRunnable); 25940 if (mTooltipInfo.mTooltipPopup == null) { 25941 return; 25942 } 25943 mTooltipInfo.mTooltipPopup.hide(); 25944 mTooltipInfo.mTooltipPopup = null; 25945 mTooltipInfo.mTooltipFromLongClick = false; 25946 if (mAttachInfo != null) { 25947 mAttachInfo.mTooltipHost = null; 25948 } 25949 } 25950 25951 private boolean showLongClickTooltip(int x, int y) { 25952 removeCallbacks(mTooltipInfo.mShowTooltipRunnable); 25953 removeCallbacks(mTooltipInfo.mHideTooltipRunnable); 25954 return showTooltip(x, y, true); 25955 } 25956 25957 private void showHoverTooltip() { 25958 showTooltip(mTooltipInfo.mAnchorX, mTooltipInfo.mAnchorY, false); 25959 } 25960 25961 boolean dispatchTooltipHoverEvent(MotionEvent event) { 25962 if (mTooltipInfo == null) { 25963 return false; 25964 } 25965 switch(event.getAction()) { 25966 case MotionEvent.ACTION_HOVER_MOVE: 25967 if ((mViewFlags & TOOLTIP) != TOOLTIP || (mViewFlags & ENABLED_MASK) != ENABLED) { 25968 break; 25969 } 25970 if (!mTooltipInfo.mTooltipFromLongClick) { 25971 if (mTooltipInfo.mTooltipPopup == null) { 25972 // Schedule showing the tooltip after a timeout. 25973 mTooltipInfo.mAnchorX = (int) event.getX(); 25974 mTooltipInfo.mAnchorY = (int) event.getY(); 25975 removeCallbacks(mTooltipInfo.mShowTooltipRunnable); 25976 postDelayed(mTooltipInfo.mShowTooltipRunnable, 25977 ViewConfiguration.getHoverTooltipShowTimeout()); 25978 } 25979 25980 // Hide hover-triggered tooltip after a period of inactivity. 25981 // Match the timeout used by NativeInputManager to hide the mouse pointer 25982 // (depends on SYSTEM_UI_FLAG_LOW_PROFILE being set). 25983 final int timeout; 25984 if ((getWindowSystemUiVisibility() & SYSTEM_UI_FLAG_LOW_PROFILE) 25985 == SYSTEM_UI_FLAG_LOW_PROFILE) { 25986 timeout = ViewConfiguration.getHoverTooltipHideShortTimeout(); 25987 } else { 25988 timeout = ViewConfiguration.getHoverTooltipHideTimeout(); 25989 } 25990 removeCallbacks(mTooltipInfo.mHideTooltipRunnable); 25991 postDelayed(mTooltipInfo.mHideTooltipRunnable, timeout); 25992 } 25993 return true; 25994 25995 case MotionEvent.ACTION_HOVER_EXIT: 25996 if (!mTooltipInfo.mTooltipFromLongClick) { 25997 hideTooltip(); 25998 } 25999 break; 26000 } 26001 return false; 26002 } 26003 26004 void handleTooltipKey(KeyEvent event) { 26005 switch (event.getAction()) { 26006 case KeyEvent.ACTION_DOWN: 26007 if (event.getRepeatCount() == 0) { 26008 hideTooltip(); 26009 } 26010 break; 26011 26012 case KeyEvent.ACTION_UP: 26013 handleTooltipUp(); 26014 break; 26015 } 26016 } 26017 26018 private void handleTooltipUp() { 26019 if (mTooltipInfo == null || mTooltipInfo.mTooltipPopup == null) { 26020 return; 26021 } 26022 removeCallbacks(mTooltipInfo.mHideTooltipRunnable); 26023 postDelayed(mTooltipInfo.mHideTooltipRunnable, 26024 ViewConfiguration.getLongPressTooltipHideTimeout()); 26025 } 26026 26027 private int getFocusableAttribute(TypedArray attributes) { 26028 TypedValue val = new TypedValue(); 26029 if (attributes.getValue(com.android.internal.R.styleable.View_focusable, val)) { 26030 if (val.type == TypedValue.TYPE_INT_BOOLEAN) { 26031 return (val.data == 0 ? NOT_FOCUSABLE : FOCUSABLE); 26032 } else { 26033 return val.data; 26034 } 26035 } else { 26036 return FOCUSABLE_AUTO; 26037 } 26038 } 26039 26040 /** 26041 * @return The content view of the tooltip popup currently being shown, or null if the tooltip 26042 * is not showing. 26043 * @hide 26044 */ 26045 @TestApi 26046 public View getTooltipView() { 26047 if (mTooltipInfo == null || mTooltipInfo.mTooltipPopup == null) { 26048 return null; 26049 } 26050 return mTooltipInfo.mTooltipPopup.getContentView(); 26051 } 26052} 26053