View.java revision 2102c3211c794ef70f5d038cbe2441b9879dda55
1/* 2 * Copyright (C) 2006 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package android.view; 18 19import static java.lang.Math.max; 20 21import android.animation.AnimatorInflater; 22import android.animation.StateListAnimator; 23import android.annotation.CallSuper; 24import android.annotation.ColorInt; 25import android.annotation.DrawableRes; 26import android.annotation.FloatRange; 27import android.annotation.IdRes; 28import android.annotation.IntDef; 29import android.annotation.IntRange; 30import android.annotation.LayoutRes; 31import android.annotation.NonNull; 32import android.annotation.Nullable; 33import android.annotation.Size; 34import android.annotation.TestApi; 35import android.annotation.UiThread; 36import android.content.ClipData; 37import android.content.Context; 38import android.content.ContextWrapper; 39import android.content.Intent; 40import android.content.res.ColorStateList; 41import android.content.res.Configuration; 42import android.content.res.Resources; 43import android.content.res.TypedArray; 44import android.graphics.Bitmap; 45import android.graphics.Canvas; 46import android.graphics.Color; 47import android.graphics.Insets; 48import android.graphics.Interpolator; 49import android.graphics.LinearGradient; 50import android.graphics.Matrix; 51import android.graphics.Outline; 52import android.graphics.Paint; 53import android.graphics.PixelFormat; 54import android.graphics.Point; 55import android.graphics.PorterDuff; 56import android.graphics.PorterDuffXfermode; 57import android.graphics.Rect; 58import android.graphics.RectF; 59import android.graphics.Region; 60import android.graphics.Shader; 61import android.graphics.drawable.ColorDrawable; 62import android.graphics.drawable.Drawable; 63import android.hardware.display.DisplayManagerGlobal; 64import android.net.Uri; 65import android.os.Build; 66import android.os.Bundle; 67import android.os.Handler; 68import android.os.IBinder; 69import android.os.Message; 70import android.os.Parcel; 71import android.os.Parcelable; 72import android.os.RemoteException; 73import android.os.SystemClock; 74import android.os.SystemProperties; 75import android.os.Trace; 76import android.text.TextUtils; 77import android.util.AttributeSet; 78import android.util.FloatProperty; 79import android.util.LayoutDirection; 80import android.util.Log; 81import android.util.LongSparseLongArray; 82import android.util.Pools.SynchronizedPool; 83import android.util.Property; 84import android.util.SparseArray; 85import android.util.StateSet; 86import android.util.SuperNotCalledException; 87import android.util.TypedValue; 88import android.view.AccessibilityIterators.CharacterTextSegmentIterator; 89import android.view.AccessibilityIterators.ParagraphTextSegmentIterator; 90import android.view.AccessibilityIterators.TextSegmentIterator; 91import android.view.AccessibilityIterators.WordTextSegmentIterator; 92import android.view.ContextMenu.ContextMenuInfo; 93import android.view.accessibility.AccessibilityEvent; 94import android.view.accessibility.AccessibilityEventSource; 95import android.view.accessibility.AccessibilityManager; 96import android.view.accessibility.AccessibilityNodeInfo; 97import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction; 98import android.view.accessibility.AccessibilityNodeProvider; 99import android.view.accessibility.AccessibilityWindowInfo; 100import android.view.animation.Animation; 101import android.view.animation.AnimationUtils; 102import android.view.animation.Transformation; 103import android.view.autofill.AutofillId; 104import android.view.autofill.AutofillManager; 105import android.view.autofill.AutofillValue; 106import android.view.inputmethod.EditorInfo; 107import android.view.inputmethod.InputConnection; 108import android.view.inputmethod.InputMethodManager; 109import android.widget.Checkable; 110import android.widget.FrameLayout; 111import android.widget.ScrollBarDrawable; 112 113import com.android.internal.R; 114import com.android.internal.view.TooltipPopup; 115import com.android.internal.view.menu.MenuBuilder; 116import com.android.internal.widget.ScrollBarUtils; 117 118import com.google.android.collect.Lists; 119import com.google.android.collect.Maps; 120 121import java.lang.annotation.Retention; 122import java.lang.annotation.RetentionPolicy; 123import java.lang.ref.WeakReference; 124import java.lang.reflect.Field; 125import java.lang.reflect.InvocationTargetException; 126import java.lang.reflect.Method; 127import java.lang.reflect.Modifier; 128import java.util.ArrayList; 129import java.util.Arrays; 130import java.util.Collection; 131import java.util.Collections; 132import java.util.HashMap; 133import java.util.List; 134import java.util.Locale; 135import java.util.Map; 136import java.util.concurrent.CopyOnWriteArrayList; 137import java.util.concurrent.atomic.AtomicInteger; 138import java.util.function.Predicate; 139 140/** 141 * <p> 142 * This class represents the basic building block for user interface components. A View 143 * occupies a rectangular area on the screen and is responsible for drawing and 144 * event handling. View is the base class for <em>widgets</em>, which are 145 * used to create interactive UI components (buttons, text fields, etc.). The 146 * {@link android.view.ViewGroup} subclass is the base class for <em>layouts</em>, which 147 * are invisible containers that hold other Views (or other ViewGroups) and define 148 * their layout properties. 149 * </p> 150 * 151 * <div class="special reference"> 152 * <h3>Developer Guides</h3> 153 * <p>For information about using this class to develop your application's user interface, 154 * read the <a href="{@docRoot}guide/topics/ui/index.html">User Interface</a> developer guide. 155 * </div> 156 * 157 * <a name="Using"></a> 158 * <h3>Using Views</h3> 159 * <p> 160 * All of the views in a window are arranged in a single tree. You can add views 161 * either from code or by specifying a tree of views in one or more XML layout 162 * files. There are many specialized subclasses of views that act as controls or 163 * are capable of displaying text, images, or other content. 164 * </p> 165 * <p> 166 * Once you have created a tree of views, there are typically a few types of 167 * common operations you may wish to perform: 168 * <ul> 169 * <li><strong>Set properties:</strong> for example setting the text of a 170 * {@link android.widget.TextView}. The available properties and the methods 171 * that set them will vary among the different subclasses of views. Note that 172 * properties that are known at build time can be set in the XML layout 173 * files.</li> 174 * <li><strong>Set focus:</strong> The framework will handle moving focus in 175 * response to user input. To force focus to a specific view, call 176 * {@link #requestFocus}.</li> 177 * <li><strong>Set up listeners:</strong> Views allow clients to set listeners 178 * that will be notified when something interesting happens to the view. For 179 * example, all views will let you set a listener to be notified when the view 180 * gains or loses focus. You can register such a listener using 181 * {@link #setOnFocusChangeListener(android.view.View.OnFocusChangeListener)}. 182 * Other view subclasses offer more specialized listeners. For example, a Button 183 * exposes a listener to notify clients when the button is clicked.</li> 184 * <li><strong>Set visibility:</strong> You can hide or show views using 185 * {@link #setVisibility(int)}.</li> 186 * </ul> 187 * </p> 188 * <p><em> 189 * Note: The Android framework is responsible for measuring, laying out and 190 * drawing views. You should not call methods that perform these actions on 191 * views yourself unless you are actually implementing a 192 * {@link android.view.ViewGroup}. 193 * </em></p> 194 * 195 * <a name="Lifecycle"></a> 196 * <h3>Implementing a Custom View</h3> 197 * 198 * <p> 199 * To implement a custom view, you will usually begin by providing overrides for 200 * some of the standard methods that the framework calls on all views. You do 201 * not need to override all of these methods. In fact, you can start by just 202 * overriding {@link #onDraw(android.graphics.Canvas)}. 203 * <table border="2" width="85%" align="center" cellpadding="5"> 204 * <thead> 205 * <tr><th>Category</th> <th>Methods</th> <th>Description</th></tr> 206 * </thead> 207 * 208 * <tbody> 209 * <tr> 210 * <td rowspan="2">Creation</td> 211 * <td>Constructors</td> 212 * <td>There is a form of the constructor that are called when the view 213 * is created from code and a form that is called when the view is 214 * inflated from a layout file. The second form should parse and apply 215 * any attributes defined in the layout file. 216 * </td> 217 * </tr> 218 * <tr> 219 * <td><code>{@link #onFinishInflate()}</code></td> 220 * <td>Called after a view and all of its children has been inflated 221 * from XML.</td> 222 * </tr> 223 * 224 * <tr> 225 * <td rowspan="3">Layout</td> 226 * <td><code>{@link #onMeasure(int, int)}</code></td> 227 * <td>Called to determine the size requirements for this view and all 228 * of its children. 229 * </td> 230 * </tr> 231 * <tr> 232 * <td><code>{@link #onLayout(boolean, int, int, int, int)}</code></td> 233 * <td>Called when this view should assign a size and position to all 234 * of its children. 235 * </td> 236 * </tr> 237 * <tr> 238 * <td><code>{@link #onSizeChanged(int, int, int, int)}</code></td> 239 * <td>Called when the size of this view has changed. 240 * </td> 241 * </tr> 242 * 243 * <tr> 244 * <td>Drawing</td> 245 * <td><code>{@link #onDraw(android.graphics.Canvas)}</code></td> 246 * <td>Called when the view should render its content. 247 * </td> 248 * </tr> 249 * 250 * <tr> 251 * <td rowspan="4">Event processing</td> 252 * <td><code>{@link #onKeyDown(int, KeyEvent)}</code></td> 253 * <td>Called when a new hardware key event occurs. 254 * </td> 255 * </tr> 256 * <tr> 257 * <td><code>{@link #onKeyUp(int, KeyEvent)}</code></td> 258 * <td>Called when a hardware key up event occurs. 259 * </td> 260 * </tr> 261 * <tr> 262 * <td><code>{@link #onTrackballEvent(MotionEvent)}</code></td> 263 * <td>Called when a trackball motion event occurs. 264 * </td> 265 * </tr> 266 * <tr> 267 * <td><code>{@link #onTouchEvent(MotionEvent)}</code></td> 268 * <td>Called when a touch screen motion event occurs. 269 * </td> 270 * </tr> 271 * 272 * <tr> 273 * <td rowspan="2">Focus</td> 274 * <td><code>{@link #onFocusChanged(boolean, int, android.graphics.Rect)}</code></td> 275 * <td>Called when the view gains or loses focus. 276 * </td> 277 * </tr> 278 * 279 * <tr> 280 * <td><code>{@link #onWindowFocusChanged(boolean)}</code></td> 281 * <td>Called when the window containing the view gains or loses focus. 282 * </td> 283 * </tr> 284 * 285 * <tr> 286 * <td rowspan="3">Attaching</td> 287 * <td><code>{@link #onAttachedToWindow()}</code></td> 288 * <td>Called when the view is attached to a window. 289 * </td> 290 * </tr> 291 * 292 * <tr> 293 * <td><code>{@link #onDetachedFromWindow}</code></td> 294 * <td>Called when the view is detached from its window. 295 * </td> 296 * </tr> 297 * 298 * <tr> 299 * <td><code>{@link #onWindowVisibilityChanged(int)}</code></td> 300 * <td>Called when the visibility of the window containing the view 301 * has changed. 302 * </td> 303 * </tr> 304 * </tbody> 305 * 306 * </table> 307 * </p> 308 * 309 * <a name="IDs"></a> 310 * <h3>IDs</h3> 311 * Views may have an integer id associated with them. These ids are typically 312 * assigned in the layout XML files, and are used to find specific views within 313 * the view tree. A common pattern is to: 314 * <ul> 315 * <li>Define a Button in the layout file and assign it a unique ID. 316 * <pre> 317 * <Button 318 * android:id="@+id/my_button" 319 * android:layout_width="wrap_content" 320 * android:layout_height="wrap_content" 321 * android:text="@string/my_button_text"/> 322 * </pre></li> 323 * <li>From the onCreate method of an Activity, find the Button 324 * <pre class="prettyprint"> 325 * Button myButton = findViewById(R.id.my_button); 326 * </pre></li> 327 * </ul> 328 * <p> 329 * View IDs need not be unique throughout the tree, but it is good practice to 330 * ensure that they are at least unique within the part of the tree you are 331 * searching. 332 * </p> 333 * 334 * <a name="Position"></a> 335 * <h3>Position</h3> 336 * <p> 337 * The geometry of a view is that of a rectangle. A view has a location, 338 * expressed as a pair of <em>left</em> and <em>top</em> coordinates, and 339 * two dimensions, expressed as a width and a height. The unit for location 340 * and dimensions is the pixel. 341 * </p> 342 * 343 * <p> 344 * It is possible to retrieve the location of a view by invoking the methods 345 * {@link #getLeft()} and {@link #getTop()}. The former returns the left, or X, 346 * coordinate of the rectangle representing the view. The latter returns the 347 * top, or Y, coordinate of the rectangle representing the view. These methods 348 * both return the location of the view relative to its parent. For instance, 349 * when getLeft() returns 20, that means the view is located 20 pixels to the 350 * right of the left edge of its direct parent. 351 * </p> 352 * 353 * <p> 354 * In addition, several convenience methods are offered to avoid unnecessary 355 * computations, namely {@link #getRight()} and {@link #getBottom()}. 356 * These methods return the coordinates of the right and bottom edges of the 357 * rectangle representing the view. For instance, calling {@link #getRight()} 358 * is similar to the following computation: <code>getLeft() + getWidth()</code> 359 * (see <a href="#SizePaddingMargins">Size</a> for more information about the width.) 360 * </p> 361 * 362 * <a name="SizePaddingMargins"></a> 363 * <h3>Size, padding and margins</h3> 364 * <p> 365 * The size of a view is expressed with a width and a height. A view actually 366 * possess two pairs of width and height values. 367 * </p> 368 * 369 * <p> 370 * The first pair is known as <em>measured width</em> and 371 * <em>measured height</em>. These dimensions define how big a view wants to be 372 * within its parent (see <a href="#Layout">Layout</a> for more details.) The 373 * measured dimensions can be obtained by calling {@link #getMeasuredWidth()} 374 * and {@link #getMeasuredHeight()}. 375 * </p> 376 * 377 * <p> 378 * The second pair is simply known as <em>width</em> and <em>height</em>, or 379 * sometimes <em>drawing width</em> and <em>drawing height</em>. These 380 * dimensions define the actual size of the view on screen, at drawing time and 381 * after layout. These values may, but do not have to, be different from the 382 * measured width and height. The width and height can be obtained by calling 383 * {@link #getWidth()} and {@link #getHeight()}. 384 * </p> 385 * 386 * <p> 387 * To measure its dimensions, a view takes into account its padding. The padding 388 * is expressed in pixels for the left, top, right and bottom parts of the view. 389 * Padding can be used to offset the content of the view by a specific amount of 390 * pixels. For instance, a left padding of 2 will push the view's content by 391 * 2 pixels to the right of the left edge. Padding can be set using the 392 * {@link #setPadding(int, int, int, int)} or {@link #setPaddingRelative(int, int, int, int)} 393 * method and queried by calling {@link #getPaddingLeft()}, {@link #getPaddingTop()}, 394 * {@link #getPaddingRight()}, {@link #getPaddingBottom()}, {@link #getPaddingStart()}, 395 * {@link #getPaddingEnd()}. 396 * </p> 397 * 398 * <p> 399 * Even though a view can define a padding, it does not provide any support for 400 * margins. However, view groups provide such a support. Refer to 401 * {@link android.view.ViewGroup} and 402 * {@link android.view.ViewGroup.MarginLayoutParams} for further information. 403 * </p> 404 * 405 * <a name="Layout"></a> 406 * <h3>Layout</h3> 407 * <p> 408 * Layout is a two pass process: a measure pass and a layout pass. The measuring 409 * pass is implemented in {@link #measure(int, int)} and is a top-down traversal 410 * of the view tree. Each view pushes dimension specifications down the tree 411 * during the recursion. At the end of the measure pass, every view has stored 412 * its measurements. The second pass happens in 413 * {@link #layout(int,int,int,int)} and is also top-down. During 414 * this pass each parent is responsible for positioning all of its children 415 * using the sizes computed in the measure pass. 416 * </p> 417 * 418 * <p> 419 * When a view's measure() method returns, its {@link #getMeasuredWidth()} and 420 * {@link #getMeasuredHeight()} values must be set, along with those for all of 421 * that view's descendants. A view's measured width and measured height values 422 * must respect the constraints imposed by the view's parents. This guarantees 423 * that at the end of the measure pass, all parents accept all of their 424 * children's measurements. A parent view may call measure() more than once on 425 * its children. For example, the parent may measure each child once with 426 * unspecified dimensions to find out how big they want to be, then call 427 * measure() on them again with actual numbers if the sum of all the children's 428 * unconstrained sizes is too big or too small. 429 * </p> 430 * 431 * <p> 432 * The measure pass uses two classes to communicate dimensions. The 433 * {@link MeasureSpec} class is used by views to tell their parents how they 434 * want to be measured and positioned. The base LayoutParams class just 435 * describes how big the view wants to be for both width and height. For each 436 * dimension, it can specify one of: 437 * <ul> 438 * <li> an exact number 439 * <li>MATCH_PARENT, which means the view wants to be as big as its parent 440 * (minus padding) 441 * <li> WRAP_CONTENT, which means that the view wants to be just big enough to 442 * enclose its content (plus padding). 443 * </ul> 444 * There are subclasses of LayoutParams for different subclasses of ViewGroup. 445 * For example, AbsoluteLayout has its own subclass of LayoutParams which adds 446 * an X and Y value. 447 * </p> 448 * 449 * <p> 450 * MeasureSpecs are used to push requirements down the tree from parent to 451 * child. A MeasureSpec can be in one of three modes: 452 * <ul> 453 * <li>UNSPECIFIED: This is used by a parent to determine the desired dimension 454 * of a child view. For example, a LinearLayout may call measure() on its child 455 * with the height set to UNSPECIFIED and a width of EXACTLY 240 to find out how 456 * tall the child view wants to be given a width of 240 pixels. 457 * <li>EXACTLY: This is used by the parent to impose an exact size on the 458 * child. The child must use this size, and guarantee that all of its 459 * descendants will fit within this size. 460 * <li>AT_MOST: This is used by the parent to impose a maximum size on the 461 * child. The child must guarantee that it and all of its descendants will fit 462 * within this size. 463 * </ul> 464 * </p> 465 * 466 * <p> 467 * To initiate a layout, call {@link #requestLayout}. This method is typically 468 * called by a view on itself when it believes that is can no longer fit within 469 * its current bounds. 470 * </p> 471 * 472 * <a name="Drawing"></a> 473 * <h3>Drawing</h3> 474 * <p> 475 * Drawing is handled by walking the tree and recording the drawing commands of 476 * any View that needs to update. After this, the drawing commands of the 477 * entire tree are issued to screen, clipped to the newly damaged area. 478 * </p> 479 * 480 * <p> 481 * The tree is largely recorded and drawn in order, with parents drawn before 482 * (i.e., behind) their children, with siblings drawn in the order they appear 483 * in the tree. If you set a background drawable for a View, then the View will 484 * draw it before calling back to its <code>onDraw()</code> method. The child 485 * drawing order can be overridden with 486 * {@link ViewGroup#setChildrenDrawingOrderEnabled(boolean) custom child drawing order} 487 * in a ViewGroup, and with {@link #setZ(float)} custom Z values} set on Views. 488 * </p> 489 * 490 * <p> 491 * To force a view to draw, call {@link #invalidate()}. 492 * </p> 493 * 494 * <a name="EventHandlingThreading"></a> 495 * <h3>Event Handling and Threading</h3> 496 * <p> 497 * The basic cycle of a view is as follows: 498 * <ol> 499 * <li>An event comes in and is dispatched to the appropriate view. The view 500 * handles the event and notifies any listeners.</li> 501 * <li>If in the course of processing the event, the view's bounds may need 502 * to be changed, the view will call {@link #requestLayout()}.</li> 503 * <li>Similarly, if in the course of processing the event the view's appearance 504 * may need to be changed, the view will call {@link #invalidate()}.</li> 505 * <li>If either {@link #requestLayout()} or {@link #invalidate()} were called, 506 * the framework will take care of measuring, laying out, and drawing the tree 507 * as appropriate.</li> 508 * </ol> 509 * </p> 510 * 511 * <p><em>Note: The entire view tree is single threaded. You must always be on 512 * the UI thread when calling any method on any view.</em> 513 * If you are doing work on other threads and want to update the state of a view 514 * from that thread, you should use a {@link Handler}. 515 * </p> 516 * 517 * <a name="FocusHandling"></a> 518 * <h3>Focus Handling</h3> 519 * <p> 520 * The framework will handle routine focus movement in response to user input. 521 * This includes changing the focus as views are removed or hidden, or as new 522 * views become available. Views indicate their willingness to take focus 523 * through the {@link #isFocusable} method. To change whether a view can take 524 * focus, call {@link #setFocusable(boolean)}. When in touch mode (see notes below) 525 * views indicate whether they still would like focus via {@link #isFocusableInTouchMode} 526 * and can change this via {@link #setFocusableInTouchMode(boolean)}. 527 * </p> 528 * <p> 529 * Focus movement is based on an algorithm which finds the nearest neighbor in a 530 * given direction. In rare cases, the default algorithm may not match the 531 * intended behavior of the developer. In these situations, you can provide 532 * explicit overrides by using these XML attributes in the layout file: 533 * <pre> 534 * nextFocusDown 535 * nextFocusLeft 536 * nextFocusRight 537 * nextFocusUp 538 * </pre> 539 * </p> 540 * 541 * 542 * <p> 543 * To get a particular view to take focus, call {@link #requestFocus()}. 544 * </p> 545 * 546 * <a name="TouchMode"></a> 547 * <h3>Touch Mode</h3> 548 * <p> 549 * When a user is navigating a user interface via directional keys such as a D-pad, it is 550 * necessary to give focus to actionable items such as buttons so the user can see 551 * what will take input. If the device has touch capabilities, however, and the user 552 * begins interacting with the interface by touching it, it is no longer necessary to 553 * always highlight, or give focus to, a particular view. This motivates a mode 554 * for interaction named 'touch mode'. 555 * </p> 556 * <p> 557 * For a touch capable device, once the user touches the screen, the device 558 * will enter touch mode. From this point onward, only views for which 559 * {@link #isFocusableInTouchMode} is true will be focusable, such as text editing widgets. 560 * Other views that are touchable, like buttons, will not take focus when touched; they will 561 * only fire the on click listeners. 562 * </p> 563 * <p> 564 * Any time a user hits a directional key, such as a D-pad direction, the view device will 565 * exit touch mode, and find a view to take focus, so that the user may resume interacting 566 * with the user interface without touching the screen again. 567 * </p> 568 * <p> 569 * The touch mode state is maintained across {@link android.app.Activity}s. Call 570 * {@link #isInTouchMode} to see whether the device is currently in touch mode. 571 * </p> 572 * 573 * <a name="Scrolling"></a> 574 * <h3>Scrolling</h3> 575 * <p> 576 * The framework provides basic support for views that wish to internally 577 * scroll their content. This includes keeping track of the X and Y scroll 578 * offset as well as mechanisms for drawing scrollbars. See 579 * {@link #scrollBy(int, int)}, {@link #scrollTo(int, int)}, and 580 * {@link #awakenScrollBars()} for more details. 581 * </p> 582 * 583 * <a name="Tags"></a> 584 * <h3>Tags</h3> 585 * <p> 586 * Unlike IDs, tags are not used to identify views. Tags are essentially an 587 * extra piece of information that can be associated with a view. They are most 588 * often used as a convenience to store data related to views in the views 589 * themselves rather than by putting them in a separate structure. 590 * </p> 591 * <p> 592 * Tags may be specified with character sequence values in layout XML as either 593 * a single tag using the {@link android.R.styleable#View_tag android:tag} 594 * attribute or multiple tags using the {@code <tag>} child element: 595 * <pre> 596 * <View ... 597 * android:tag="@string/mytag_value" /> 598 * <View ...> 599 * <tag android:id="@+id/mytag" 600 * android:value="@string/mytag_value" /> 601 * </View> 602 * </pre> 603 * </p> 604 * <p> 605 * Tags may also be specified with arbitrary objects from code using 606 * {@link #setTag(Object)} or {@link #setTag(int, Object)}. 607 * </p> 608 * 609 * <a name="Themes"></a> 610 * <h3>Themes</h3> 611 * <p> 612 * By default, Views are created using the theme of the Context object supplied 613 * to their constructor; however, a different theme may be specified by using 614 * the {@link android.R.styleable#View_theme android:theme} attribute in layout 615 * XML or by passing a {@link ContextThemeWrapper} to the constructor from 616 * code. 617 * </p> 618 * <p> 619 * When the {@link android.R.styleable#View_theme android:theme} attribute is 620 * used in XML, the specified theme is applied on top of the inflation 621 * context's theme (see {@link LayoutInflater}) and used for the view itself as 622 * well as any child elements. 623 * </p> 624 * <p> 625 * In the following example, both views will be created using the Material dark 626 * color scheme; however, because an overlay theme is used which only defines a 627 * subset of attributes, the value of 628 * {@link android.R.styleable#Theme_colorAccent android:colorAccent} defined on 629 * the inflation context's theme (e.g. the Activity theme) will be preserved. 630 * <pre> 631 * <LinearLayout 632 * ... 633 * android:theme="@android:theme/ThemeOverlay.Material.Dark"> 634 * <View ...> 635 * </LinearLayout> 636 * </pre> 637 * </p> 638 * 639 * <a name="Properties"></a> 640 * <h3>Properties</h3> 641 * <p> 642 * The View class exposes an {@link #ALPHA} property, as well as several transform-related 643 * properties, such as {@link #TRANSLATION_X} and {@link #TRANSLATION_Y}. These properties are 644 * available both in the {@link Property} form as well as in similarly-named setter/getter 645 * methods (such as {@link #setAlpha(float)} for {@link #ALPHA}). These properties can 646 * be used to set persistent state associated with these rendering-related properties on the view. 647 * The properties and methods can also be used in conjunction with 648 * {@link android.animation.Animator Animator}-based animations, described more in the 649 * <a href="#Animation">Animation</a> section. 650 * </p> 651 * 652 * <a name="Animation"></a> 653 * <h3>Animation</h3> 654 * <p> 655 * Starting with Android 3.0, the preferred way of animating views is to use the 656 * {@link android.animation} package APIs. These {@link android.animation.Animator Animator}-based 657 * classes change actual properties of the View object, such as {@link #setAlpha(float) alpha} and 658 * {@link #setTranslationX(float) translationX}. This behavior is contrasted to that of the pre-3.0 659 * {@link android.view.animation.Animation Animation}-based classes, which instead animate only 660 * how the view is drawn on the display. In particular, the {@link ViewPropertyAnimator} class 661 * makes animating these View properties particularly easy and efficient. 662 * </p> 663 * <p> 664 * Alternatively, you can use the pre-3.0 animation classes to animate how Views are rendered. 665 * You can attach an {@link Animation} object to a view using 666 * {@link #setAnimation(Animation)} or 667 * {@link #startAnimation(Animation)}. The animation can alter the scale, 668 * rotation, translation and alpha of a view over time. If the animation is 669 * attached to a view that has children, the animation will affect the entire 670 * subtree rooted by that node. When an animation is started, the framework will 671 * take care of redrawing the appropriate views until the animation completes. 672 * </p> 673 * 674 * <a name="Security"></a> 675 * <h3>Security</h3> 676 * <p> 677 * Sometimes it is essential that an application be able to verify that an action 678 * is being performed with the full knowledge and consent of the user, such as 679 * granting a permission request, making a purchase or clicking on an advertisement. 680 * Unfortunately, a malicious application could try to spoof the user into 681 * performing these actions, unaware, by concealing the intended purpose of the view. 682 * As a remedy, the framework offers a touch filtering mechanism that can be used to 683 * improve the security of views that provide access to sensitive functionality. 684 * </p><p> 685 * To enable touch filtering, call {@link #setFilterTouchesWhenObscured(boolean)} or set the 686 * android:filterTouchesWhenObscured layout attribute to true. When enabled, the framework 687 * will discard touches that are received whenever the view's window is obscured by 688 * another visible window. As a result, the view will not receive touches whenever a 689 * toast, dialog or other window appears above the view's window. 690 * </p><p> 691 * For more fine-grained control over security, consider overriding the 692 * {@link #onFilterTouchEventForSecurity(MotionEvent)} method to implement your own 693 * security policy. See also {@link MotionEvent#FLAG_WINDOW_IS_OBSCURED}. 694 * </p> 695 * 696 * @attr ref android.R.styleable#View_alpha 697 * @attr ref android.R.styleable#View_background 698 * @attr ref android.R.styleable#View_clickable 699 * @attr ref android.R.styleable#View_contentDescription 700 * @attr ref android.R.styleable#View_drawingCacheQuality 701 * @attr ref android.R.styleable#View_duplicateParentState 702 * @attr ref android.R.styleable#View_id 703 * @attr ref android.R.styleable#View_requiresFadingEdge 704 * @attr ref android.R.styleable#View_fadeScrollbars 705 * @attr ref android.R.styleable#View_fadingEdgeLength 706 * @attr ref android.R.styleable#View_filterTouchesWhenObscured 707 * @attr ref android.R.styleable#View_fitsSystemWindows 708 * @attr ref android.R.styleable#View_isScrollContainer 709 * @attr ref android.R.styleable#View_focusable 710 * @attr ref android.R.styleable#View_focusableInTouchMode 711 * @attr ref android.R.styleable#View_focusedByDefault 712 * @attr ref android.R.styleable#View_hapticFeedbackEnabled 713 * @attr ref android.R.styleable#View_keepScreenOn 714 * @attr ref android.R.styleable#View_keyboardNavigationCluster 715 * @attr ref android.R.styleable#View_layerType 716 * @attr ref android.R.styleable#View_layoutDirection 717 * @attr ref android.R.styleable#View_longClickable 718 * @attr ref android.R.styleable#View_minHeight 719 * @attr ref android.R.styleable#View_minWidth 720 * @attr ref android.R.styleable#View_nextClusterForward 721 * @attr ref android.R.styleable#View_nextFocusDown 722 * @attr ref android.R.styleable#View_nextFocusLeft 723 * @attr ref android.R.styleable#View_nextFocusRight 724 * @attr ref android.R.styleable#View_nextFocusUp 725 * @attr ref android.R.styleable#View_onClick 726 * @attr ref android.R.styleable#View_padding 727 * @attr ref android.R.styleable#View_paddingBottom 728 * @attr ref android.R.styleable#View_paddingLeft 729 * @attr ref android.R.styleable#View_paddingRight 730 * @attr ref android.R.styleable#View_paddingTop 731 * @attr ref android.R.styleable#View_paddingStart 732 * @attr ref android.R.styleable#View_paddingEnd 733 * @attr ref android.R.styleable#View_saveEnabled 734 * @attr ref android.R.styleable#View_rotation 735 * @attr ref android.R.styleable#View_rotationX 736 * @attr ref android.R.styleable#View_rotationY 737 * @attr ref android.R.styleable#View_scaleX 738 * @attr ref android.R.styleable#View_scaleY 739 * @attr ref android.R.styleable#View_scrollX 740 * @attr ref android.R.styleable#View_scrollY 741 * @attr ref android.R.styleable#View_scrollbarSize 742 * @attr ref android.R.styleable#View_scrollbarStyle 743 * @attr ref android.R.styleable#View_scrollbars 744 * @attr ref android.R.styleable#View_scrollbarDefaultDelayBeforeFade 745 * @attr ref android.R.styleable#View_scrollbarFadeDuration 746 * @attr ref android.R.styleable#View_scrollbarTrackHorizontal 747 * @attr ref android.R.styleable#View_scrollbarThumbHorizontal 748 * @attr ref android.R.styleable#View_scrollbarThumbVertical 749 * @attr ref android.R.styleable#View_scrollbarTrackVertical 750 * @attr ref android.R.styleable#View_scrollbarAlwaysDrawHorizontalTrack 751 * @attr ref android.R.styleable#View_scrollbarAlwaysDrawVerticalTrack 752 * @attr ref android.R.styleable#View_stateListAnimator 753 * @attr ref android.R.styleable#View_transitionName 754 * @attr ref android.R.styleable#View_soundEffectsEnabled 755 * @attr ref android.R.styleable#View_tag 756 * @attr ref android.R.styleable#View_textAlignment 757 * @attr ref android.R.styleable#View_textDirection 758 * @attr ref android.R.styleable#View_transformPivotX 759 * @attr ref android.R.styleable#View_transformPivotY 760 * @attr ref android.R.styleable#View_translationX 761 * @attr ref android.R.styleable#View_translationY 762 * @attr ref android.R.styleable#View_translationZ 763 * @attr ref android.R.styleable#View_visibility 764 * @attr ref android.R.styleable#View_theme 765 * 766 * @see android.view.ViewGroup 767 */ 768@UiThread 769public class View implements Drawable.Callback, KeyEvent.Callback, 770 AccessibilityEventSource { 771 private static final boolean DBG = false; 772 773 /** @hide */ 774 public static boolean DEBUG_DRAW = false; 775 776 /** 777 * The logging tag used by this class with android.util.Log. 778 */ 779 protected static final String VIEW_LOG_TAG = "View"; 780 781 /** 782 * When set to true, apps will draw debugging information about their layouts. 783 * 784 * @hide 785 */ 786 public static final String DEBUG_LAYOUT_PROPERTY = "debug.layout"; 787 788 /** 789 * When set to true, this view will save its attribute data. 790 * 791 * @hide 792 */ 793 public static boolean mDebugViewAttributes = false; 794 795 /** 796 * Used to mark a View that has no ID. 797 */ 798 public static final int NO_ID = -1; 799 800 /** 801 * Last ID that is given to Views that are no part of activities. 802 * 803 * {@hide} 804 */ 805 public static final int LAST_APP_AUTOFILL_ID = Integer.MAX_VALUE / 2; 806 807 /** 808 * Attribute to find the autofilled highlight 809 * 810 * @see #getAutofilledDrawable() 811 */ 812 private static final int[] AUTOFILL_HIGHLIGHT_ATTR = 813 new int[]{android.R.attr.autofilledHighlight}; 814 815 /** 816 * Signals that compatibility booleans have been initialized according to 817 * target SDK versions. 818 */ 819 private static boolean sCompatibilityDone = false; 820 821 /** 822 * Use the old (broken) way of building MeasureSpecs. 823 */ 824 private static boolean sUseBrokenMakeMeasureSpec = false; 825 826 /** 827 * Always return a size of 0 for MeasureSpec values with a mode of UNSPECIFIED 828 */ 829 static boolean sUseZeroUnspecifiedMeasureSpec = false; 830 831 /** 832 * Ignore any optimizations using the measure cache. 833 */ 834 private static boolean sIgnoreMeasureCache = false; 835 836 /** 837 * Ignore an optimization that skips unnecessary EXACTLY layout passes. 838 */ 839 private static boolean sAlwaysRemeasureExactly = false; 840 841 /** 842 * Relax constraints around whether setLayoutParams() must be called after 843 * modifying the layout params. 844 */ 845 private static boolean sLayoutParamsAlwaysChanged = false; 846 847 /** 848 * Allow setForeground/setBackground to be called (and ignored) on a textureview, 849 * without throwing 850 */ 851 static boolean sTextureViewIgnoresDrawableSetters = false; 852 853 /** 854 * Prior to N, some ViewGroups would not convert LayoutParams properly even though both extend 855 * MarginLayoutParams. For instance, converting LinearLayout.LayoutParams to 856 * RelativeLayout.LayoutParams would lose margin information. This is fixed on N but target API 857 * check is implemented for backwards compatibility. 858 * 859 * {@hide} 860 */ 861 protected static boolean sPreserveMarginParamsInLayoutParamConversion; 862 863 /** 864 * Prior to N, when drag enters into child of a view that has already received an 865 * ACTION_DRAG_ENTERED event, the parent doesn't get a ACTION_DRAG_EXITED event. 866 * ACTION_DRAG_LOCATION and ACTION_DROP were delivered to the parent of a view that returned 867 * false from its event handler for these events. 868 * Starting from N, the parent will get ACTION_DRAG_EXITED event before the child gets its 869 * ACTION_DRAG_ENTERED. ACTION_DRAG_LOCATION and ACTION_DROP are never propagated to the parent. 870 * sCascadedDragDrop is true for pre-N apps for backwards compatibility implementation. 871 */ 872 static boolean sCascadedDragDrop; 873 874 /** 875 * Prior to O, auto-focusable didn't exist and widgets such as ListView use hasFocusable 876 * to determine things like whether or not to permit item click events. We can't break 877 * apps that do this just because more things (clickable things) are now auto-focusable 878 * and they would get different results, so give old behavior to old apps. 879 */ 880 static boolean sHasFocusableExcludeAutoFocusable; 881 882 /** 883 * Prior to O, auto-focusable didn't exist and views marked as clickable weren't implicitly 884 * made focusable by default. As a result, apps could (incorrectly) change the clickable 885 * setting of views off the UI thread. Now that clickable can effect the focusable state, 886 * changing the clickable attribute off the UI thread will cause an exception (since changing 887 * the focusable state checks). In order to prevent apps from crashing, we will handle this 888 * specific case and just not notify parents on new focusables resulting from marking views 889 * clickable from outside the UI thread. 890 */ 891 private static boolean sAutoFocusableOffUIThreadWontNotifyParents; 892 893 /** @hide */ 894 @IntDef({NOT_FOCUSABLE, FOCUSABLE, FOCUSABLE_AUTO}) 895 @Retention(RetentionPolicy.SOURCE) 896 public @interface Focusable {} 897 898 /** 899 * This view does not want keystrokes. 900 * <p> 901 * Use with {@link #setFocusable(int)} and <a href="#attr_android:focusable">{@code 902 * android:focusable}. 903 */ 904 public static final int NOT_FOCUSABLE = 0x00000000; 905 906 /** 907 * This view wants keystrokes. 908 * <p> 909 * Use with {@link #setFocusable(int)} and <a href="#attr_android:focusable">{@code 910 * android:focusable}. 911 */ 912 public static final int FOCUSABLE = 0x00000001; 913 914 /** 915 * This view determines focusability automatically. This is the default. 916 * <p> 917 * Use with {@link #setFocusable(int)} and <a href="#attr_android:focusable">{@code 918 * android:focusable}. 919 */ 920 public static final int FOCUSABLE_AUTO = 0x00000010; 921 922 /** 923 * Mask for use with setFlags indicating bits used for focus. 924 */ 925 private static final int FOCUSABLE_MASK = 0x00000011; 926 927 /** 928 * This view will adjust its padding to fit sytem windows (e.g. status bar) 929 */ 930 private static final int FITS_SYSTEM_WINDOWS = 0x00000002; 931 932 /** @hide */ 933 @IntDef({VISIBLE, INVISIBLE, GONE}) 934 @Retention(RetentionPolicy.SOURCE) 935 public @interface Visibility {} 936 937 /** 938 * This view is visible. 939 * Use with {@link #setVisibility} and <a href="#attr_android:visibility">{@code 940 * android:visibility}. 941 */ 942 public static final int VISIBLE = 0x00000000; 943 944 /** 945 * This view is invisible, but it still takes up space for layout purposes. 946 * Use with {@link #setVisibility} and <a href="#attr_android:visibility">{@code 947 * android:visibility}. 948 */ 949 public static final int INVISIBLE = 0x00000004; 950 951 /** 952 * This view is invisible, and it doesn't take any space for layout 953 * purposes. Use with {@link #setVisibility} and <a href="#attr_android:visibility">{@code 954 * android:visibility}. 955 */ 956 public static final int GONE = 0x00000008; 957 958 /** 959 * Mask for use with setFlags indicating bits used for visibility. 960 * {@hide} 961 */ 962 static final int VISIBILITY_MASK = 0x0000000C; 963 964 private static final int[] VISIBILITY_FLAGS = {VISIBLE, INVISIBLE, GONE}; 965 966 /** 967 * Hint indicating that this view can be autofilled with an email address. 968 * 969 * <p>Can be used with either {@link #setAutofillHints(String[])} or 970 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 971 * value should be <code>{@value #AUTOFILL_HINT_EMAIL_ADDRESS}</code>). 972 * 973 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 974 */ 975 public static final String AUTOFILL_HINT_EMAIL_ADDRESS = "emailAddress"; 976 977 /** 978 * Hint indicating that this view can be autofilled with a user's real name. 979 * 980 * <p>Can be used with either {@link #setAutofillHints(String[])} or 981 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 982 * value should be <code>{@value #AUTOFILL_HINT_NAME}</code>). 983 * 984 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 985 */ 986 public static final String AUTOFILL_HINT_NAME = "name"; 987 988 /** 989 * Hint indicating that this view can be autofilled with a username. 990 * 991 * <p>Can be used with either {@link #setAutofillHints(String[])} or 992 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 993 * value should be <code>{@value #AUTOFILL_HINT_USERNAME}</code>). 994 * 995 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 996 */ 997 public static final String AUTOFILL_HINT_USERNAME = "username"; 998 999 /** 1000 * Hint indicating that this view can be autofilled with a password. 1001 * 1002 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1003 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1004 * value should be <code>{@value #AUTOFILL_HINT_PASSWORD}</code>). 1005 * 1006 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1007 */ 1008 public static final String AUTOFILL_HINT_PASSWORD = "password"; 1009 1010 /** 1011 * Hint indicating that this view can be autofilled with a phone number. 1012 * 1013 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1014 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1015 * value should be <code>{@value #AUTOFILL_HINT_PHONE}</code>). 1016 * 1017 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1018 */ 1019 public static final String AUTOFILL_HINT_PHONE = "phone"; 1020 1021 /** 1022 * Hint indicating that this view can be autofilled with a postal address. 1023 * 1024 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1025 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1026 * value should be <code>{@value #AUTOFILL_HINT_POSTAL_ADDRESS}</code>). 1027 * 1028 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1029 */ 1030 public static final String AUTOFILL_HINT_POSTAL_ADDRESS = "postalAddress"; 1031 1032 /** 1033 * Hint indicating that this view can be autofilled with a postal code. 1034 * 1035 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1036 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1037 * value should be <code>{@value #AUTOFILL_HINT_POSTAL_CODE}</code>). 1038 * 1039 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1040 */ 1041 public static final String AUTOFILL_HINT_POSTAL_CODE = "postalCode"; 1042 1043 /** 1044 * Hint indicating that this view can be autofilled with a credit card number. 1045 * 1046 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1047 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1048 * value should be <code>{@value #AUTOFILL_HINT_CREDIT_CARD_NUMBER}</code>). 1049 * 1050 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1051 */ 1052 public static final String AUTOFILL_HINT_CREDIT_CARD_NUMBER = "creditCardNumber"; 1053 1054 /** 1055 * Hint indicating that this view can be autofilled with a credit card security code. 1056 * 1057 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1058 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1059 * value should be <code>{@value #AUTOFILL_HINT_CREDIT_CARD_SECURITY_CODE}</code>). 1060 * 1061 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1062 */ 1063 public static final String AUTOFILL_HINT_CREDIT_CARD_SECURITY_CODE = "creditCardSecurityCode"; 1064 1065 /** 1066 * Hint indicating that this view can be autofilled with a credit card expiration date. 1067 * 1068 * <p>It should be used when the credit card expiration date is represented by just one view; 1069 * if it is represented by more than one (for example, one view for the month and another view 1070 * for the year), then each of these views should use the hint specific for the unit 1071 * ({@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DAY}, 1072 * {@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH}, 1073 * or {@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR}). 1074 * 1075 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1076 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1077 * value should be <code>{@value #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE}</code>). 1078 * 1079 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1080 */ 1081 public static final String AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE = 1082 "creditCardExpirationDate"; 1083 1084 /** 1085 * Hint indicating that this view can be autofilled with a credit card expiration month. 1086 * 1087 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1088 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1089 * value should be <code>{@value #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH}</code>). 1090 * 1091 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1092 */ 1093 public static final String AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH = 1094 "creditCardExpirationMonth"; 1095 1096 /** 1097 * Hint indicating that this view can be autofilled with a credit card expiration year. 1098 * 1099 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1100 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1101 * value should be <code>{@value #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR}</code>). 1102 * 1103 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1104 */ 1105 public static final String AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR = 1106 "creditCardExpirationYear"; 1107 1108 /** 1109 * Hint indicating that this view can be autofilled with a credit card expiration day. 1110 * 1111 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1112 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1113 * value should be <code>{@value #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DAY}</code>). 1114 * 1115 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1116 */ 1117 public static final String AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DAY = "creditCardExpirationDay"; 1118 1119 /** 1120 * Hints for the autofill services that describes the content of the view. 1121 */ 1122 private @Nullable String[] mAutofillHints; 1123 1124 /** 1125 * Autofill id, lazily created on calls to {@link #getAutofillId()}. 1126 */ 1127 private AutofillId mAutofillId; 1128 1129 /** @hide */ 1130 @IntDef({ 1131 AUTOFILL_TYPE_NONE, 1132 AUTOFILL_TYPE_TEXT, 1133 AUTOFILL_TYPE_TOGGLE, 1134 AUTOFILL_TYPE_LIST, 1135 AUTOFILL_TYPE_DATE 1136 }) 1137 @Retention(RetentionPolicy.SOURCE) 1138 public @interface AutofillType {} 1139 1140 /** 1141 * Autofill type for views that cannot be autofilled. 1142 * 1143 * <p>Typically used when the view is read-only; for example, a text label. 1144 * 1145 * @see #getAutofillType() 1146 */ 1147 public static final int AUTOFILL_TYPE_NONE = 0; 1148 1149 /** 1150 * Autofill type for a text field, which is filled by a {@link CharSequence}. 1151 * 1152 * <p>{@link AutofillValue} instances for autofilling a {@link View} can be obtained through 1153 * {@link AutofillValue#forText(CharSequence)}, and the value passed to autofill a 1154 * {@link View} can be fetched through {@link AutofillValue#getTextValue()}. 1155 * 1156 * @see #getAutofillType() 1157 */ 1158 public static final int AUTOFILL_TYPE_TEXT = 1; 1159 1160 /** 1161 * Autofill type for a togglable field, which is filled by a {@code boolean}. 1162 * 1163 * <p>{@link AutofillValue} instances for autofilling a {@link View} can be obtained through 1164 * {@link AutofillValue#forToggle(boolean)}, and the value passed to autofill a 1165 * {@link View} can be fetched through {@link AutofillValue#getToggleValue()}. 1166 * 1167 * @see #getAutofillType() 1168 */ 1169 public static final int AUTOFILL_TYPE_TOGGLE = 2; 1170 1171 /** 1172 * Autofill type for a selection list field, which is filled by an {@code int} 1173 * representing the element index inside the list (starting at {@code 0}). 1174 * 1175 * <p>{@link AutofillValue} instances for autofilling a {@link View} can be obtained through 1176 * {@link AutofillValue#forList(int)}, and the value passed to autofill a 1177 * {@link View} can be fetched through {@link AutofillValue#getListValue()}. 1178 * 1179 * <p>The available options in the selection list are typically provided by 1180 * {@link android.app.assist.AssistStructure.ViewNode#getAutofillOptions()}. 1181 * 1182 * @see #getAutofillType() 1183 */ 1184 public static final int AUTOFILL_TYPE_LIST = 3; 1185 1186 1187 /** 1188 * Autofill type for a field that contains a date, which is represented by a long representing 1189 * the number of milliseconds since the standard base time known as "the epoch", namely 1190 * January 1, 1970, 00:00:00 GMT (see {@link java.util.Date#getTime()}. 1191 * 1192 * <p>{@link AutofillValue} instances for autofilling a {@link View} can be obtained through 1193 * {@link AutofillValue#forDate(long)}, and the values passed to 1194 * autofill a {@link View} can be fetched through {@link AutofillValue#getDateValue()}. 1195 * 1196 * @see #getAutofillType() 1197 */ 1198 public static final int AUTOFILL_TYPE_DATE = 4; 1199 1200 /** @hide */ 1201 @IntDef({ 1202 IMPORTANT_FOR_AUTOFILL_AUTO, 1203 IMPORTANT_FOR_AUTOFILL_YES, 1204 IMPORTANT_FOR_AUTOFILL_NO, 1205 IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS, 1206 IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS 1207 }) 1208 @Retention(RetentionPolicy.SOURCE) 1209 public @interface AutofillImportance {} 1210 1211 /** 1212 * Automatically determine whether a view is important for autofill. 1213 * 1214 * @see #isImportantForAutofill() 1215 * @see #setImportantForAutofill(int) 1216 */ 1217 public static final int IMPORTANT_FOR_AUTOFILL_AUTO = 0x0; 1218 1219 /** 1220 * The view is important for autofill, and its children (if any) will be traversed. 1221 * 1222 * @see #isImportantForAutofill() 1223 * @see #setImportantForAutofill(int) 1224 */ 1225 public static final int IMPORTANT_FOR_AUTOFILL_YES = 0x1; 1226 1227 /** 1228 * The view is not important for autofill, but its children (if any) will be traversed. 1229 * 1230 * @see #isImportantForAutofill() 1231 * @see #setImportantForAutofill(int) 1232 */ 1233 public static final int IMPORTANT_FOR_AUTOFILL_NO = 0x2; 1234 1235 /** 1236 * The view is important for autofill, but its children (if any) will not be traversed. 1237 * 1238 * @see #isImportantForAutofill() 1239 * @see #setImportantForAutofill(int) 1240 */ 1241 public static final int IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS = 0x4; 1242 1243 /** 1244 * The view is not important for autofill, and its children (if any) will not be traversed. 1245 * 1246 * @see #isImportantForAutofill() 1247 * @see #setImportantForAutofill(int) 1248 */ 1249 public static final int IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS = 0x8; 1250 1251 /** @hide */ 1252 @IntDef( 1253 flag = true, 1254 value = {AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS}) 1255 @Retention(RetentionPolicy.SOURCE) 1256 public @interface AutofillFlags {} 1257 1258 /** 1259 * Flag requesting you to add views that are marked as not important for autofill 1260 * (see {@link #setImportantForAutofill(int)}) to a {@link ViewStructure}. 1261 */ 1262 public static final int AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS = 0x1; 1263 1264 /** 1265 * This view is enabled. Interpretation varies by subclass. 1266 * Use with ENABLED_MASK when calling setFlags. 1267 * {@hide} 1268 */ 1269 static final int ENABLED = 0x00000000; 1270 1271 /** 1272 * This view is disabled. Interpretation varies by subclass. 1273 * Use with ENABLED_MASK when calling setFlags. 1274 * {@hide} 1275 */ 1276 static final int DISABLED = 0x00000020; 1277 1278 /** 1279 * Mask for use with setFlags indicating bits used for indicating whether 1280 * this view is enabled 1281 * {@hide} 1282 */ 1283 static final int ENABLED_MASK = 0x00000020; 1284 1285 /** 1286 * This view won't draw. {@link #onDraw(android.graphics.Canvas)} won't be 1287 * called and further optimizations will be performed. It is okay to have 1288 * this flag set and a background. Use with DRAW_MASK when calling setFlags. 1289 * {@hide} 1290 */ 1291 static final int WILL_NOT_DRAW = 0x00000080; 1292 1293 /** 1294 * Mask for use with setFlags indicating bits used for indicating whether 1295 * this view is will draw 1296 * {@hide} 1297 */ 1298 static final int DRAW_MASK = 0x00000080; 1299 1300 /** 1301 * <p>This view doesn't show scrollbars.</p> 1302 * {@hide} 1303 */ 1304 static final int SCROLLBARS_NONE = 0x00000000; 1305 1306 /** 1307 * <p>This view shows horizontal scrollbars.</p> 1308 * {@hide} 1309 */ 1310 static final int SCROLLBARS_HORIZONTAL = 0x00000100; 1311 1312 /** 1313 * <p>This view shows vertical scrollbars.</p> 1314 * {@hide} 1315 */ 1316 static final int SCROLLBARS_VERTICAL = 0x00000200; 1317 1318 /** 1319 * <p>Mask for use with setFlags indicating bits used for indicating which 1320 * scrollbars are enabled.</p> 1321 * {@hide} 1322 */ 1323 static final int SCROLLBARS_MASK = 0x00000300; 1324 1325 /** 1326 * Indicates that the view should filter touches when its window is obscured. 1327 * Refer to the class comments for more information about this security feature. 1328 * {@hide} 1329 */ 1330 static final int FILTER_TOUCHES_WHEN_OBSCURED = 0x00000400; 1331 1332 /** 1333 * Set for framework elements that use FITS_SYSTEM_WINDOWS, to indicate 1334 * that they are optional and should be skipped if the window has 1335 * requested system UI flags that ignore those insets for layout. 1336 */ 1337 static final int OPTIONAL_FITS_SYSTEM_WINDOWS = 0x00000800; 1338 1339 /** 1340 * <p>This view doesn't show fading edges.</p> 1341 * {@hide} 1342 */ 1343 static final int FADING_EDGE_NONE = 0x00000000; 1344 1345 /** 1346 * <p>This view shows horizontal fading edges.</p> 1347 * {@hide} 1348 */ 1349 static final int FADING_EDGE_HORIZONTAL = 0x00001000; 1350 1351 /** 1352 * <p>This view shows vertical fading edges.</p> 1353 * {@hide} 1354 */ 1355 static final int FADING_EDGE_VERTICAL = 0x00002000; 1356 1357 /** 1358 * <p>Mask for use with setFlags indicating bits used for indicating which 1359 * fading edges are enabled.</p> 1360 * {@hide} 1361 */ 1362 static final int FADING_EDGE_MASK = 0x00003000; 1363 1364 /** 1365 * <p>Indicates this view can be clicked. When clickable, a View reacts 1366 * to clicks by notifying the OnClickListener.<p> 1367 * {@hide} 1368 */ 1369 static final int CLICKABLE = 0x00004000; 1370 1371 /** 1372 * <p>Indicates this view is caching its drawing into a bitmap.</p> 1373 * {@hide} 1374 */ 1375 static final int DRAWING_CACHE_ENABLED = 0x00008000; 1376 1377 /** 1378 * <p>Indicates that no icicle should be saved for this view.<p> 1379 * {@hide} 1380 */ 1381 static final int SAVE_DISABLED = 0x000010000; 1382 1383 /** 1384 * <p>Mask for use with setFlags indicating bits used for the saveEnabled 1385 * property.</p> 1386 * {@hide} 1387 */ 1388 static final int SAVE_DISABLED_MASK = 0x000010000; 1389 1390 /** 1391 * <p>Indicates that no drawing cache should ever be created for this view.<p> 1392 * {@hide} 1393 */ 1394 static final int WILL_NOT_CACHE_DRAWING = 0x000020000; 1395 1396 /** 1397 * <p>Indicates this view can take / keep focus when int touch mode.</p> 1398 * {@hide} 1399 */ 1400 static final int FOCUSABLE_IN_TOUCH_MODE = 0x00040000; 1401 1402 /** @hide */ 1403 @Retention(RetentionPolicy.SOURCE) 1404 @IntDef({DRAWING_CACHE_QUALITY_LOW, DRAWING_CACHE_QUALITY_HIGH, DRAWING_CACHE_QUALITY_AUTO}) 1405 public @interface DrawingCacheQuality {} 1406 1407 /** 1408 * <p>Enables low quality mode for the drawing cache.</p> 1409 */ 1410 public static final int DRAWING_CACHE_QUALITY_LOW = 0x00080000; 1411 1412 /** 1413 * <p>Enables high quality mode for the drawing cache.</p> 1414 */ 1415 public static final int DRAWING_CACHE_QUALITY_HIGH = 0x00100000; 1416 1417 /** 1418 * <p>Enables automatic quality mode for the drawing cache.</p> 1419 */ 1420 public static final int DRAWING_CACHE_QUALITY_AUTO = 0x00000000; 1421 1422 private static final int[] DRAWING_CACHE_QUALITY_FLAGS = { 1423 DRAWING_CACHE_QUALITY_AUTO, DRAWING_CACHE_QUALITY_LOW, DRAWING_CACHE_QUALITY_HIGH 1424 }; 1425 1426 /** 1427 * <p>Mask for use with setFlags indicating bits used for the cache 1428 * quality property.</p> 1429 * {@hide} 1430 */ 1431 static final int DRAWING_CACHE_QUALITY_MASK = 0x00180000; 1432 1433 /** 1434 * <p> 1435 * Indicates this view can be long clicked. When long clickable, a View 1436 * reacts to long clicks by notifying the OnLongClickListener or showing a 1437 * context menu. 1438 * </p> 1439 * {@hide} 1440 */ 1441 static final int LONG_CLICKABLE = 0x00200000; 1442 1443 /** 1444 * <p>Indicates that this view gets its drawable states from its direct parent 1445 * and ignores its original internal states.</p> 1446 * 1447 * @hide 1448 */ 1449 static final int DUPLICATE_PARENT_STATE = 0x00400000; 1450 1451 /** 1452 * <p> 1453 * Indicates this view can be context clicked. When context clickable, a View reacts to a 1454 * context click (e.g. a primary stylus button press or right mouse click) by notifying the 1455 * OnContextClickListener. 1456 * </p> 1457 * {@hide} 1458 */ 1459 static final int CONTEXT_CLICKABLE = 0x00800000; 1460 1461 1462 /** @hide */ 1463 @IntDef({ 1464 SCROLLBARS_INSIDE_OVERLAY, 1465 SCROLLBARS_INSIDE_INSET, 1466 SCROLLBARS_OUTSIDE_OVERLAY, 1467 SCROLLBARS_OUTSIDE_INSET 1468 }) 1469 @Retention(RetentionPolicy.SOURCE) 1470 public @interface ScrollBarStyle {} 1471 1472 /** 1473 * The scrollbar style to display the scrollbars inside the content area, 1474 * without increasing the padding. The scrollbars will be overlaid with 1475 * translucency on the view's content. 1476 */ 1477 public static final int SCROLLBARS_INSIDE_OVERLAY = 0; 1478 1479 /** 1480 * The scrollbar style to display the scrollbars inside the padded area, 1481 * increasing the padding of the view. The scrollbars will not overlap the 1482 * content area of the view. 1483 */ 1484 public static final int SCROLLBARS_INSIDE_INSET = 0x01000000; 1485 1486 /** 1487 * The scrollbar style to display the scrollbars at the edge of the view, 1488 * without increasing the padding. The scrollbars will be overlaid with 1489 * translucency. 1490 */ 1491 public static final int SCROLLBARS_OUTSIDE_OVERLAY = 0x02000000; 1492 1493 /** 1494 * The scrollbar style to display the scrollbars at the edge of the view, 1495 * increasing the padding of the view. The scrollbars will only overlap the 1496 * background, if any. 1497 */ 1498 public static final int SCROLLBARS_OUTSIDE_INSET = 0x03000000; 1499 1500 /** 1501 * Mask to check if the scrollbar style is overlay or inset. 1502 * {@hide} 1503 */ 1504 static final int SCROLLBARS_INSET_MASK = 0x01000000; 1505 1506 /** 1507 * Mask to check if the scrollbar style is inside or outside. 1508 * {@hide} 1509 */ 1510 static final int SCROLLBARS_OUTSIDE_MASK = 0x02000000; 1511 1512 /** 1513 * Mask for scrollbar style. 1514 * {@hide} 1515 */ 1516 static final int SCROLLBARS_STYLE_MASK = 0x03000000; 1517 1518 /** 1519 * View flag indicating that the screen should remain on while the 1520 * window containing this view is visible to the user. This effectively 1521 * takes care of automatically setting the WindowManager's 1522 * {@link WindowManager.LayoutParams#FLAG_KEEP_SCREEN_ON}. 1523 */ 1524 public static final int KEEP_SCREEN_ON = 0x04000000; 1525 1526 /** 1527 * View flag indicating whether this view should have sound effects enabled 1528 * for events such as clicking and touching. 1529 */ 1530 public static final int SOUND_EFFECTS_ENABLED = 0x08000000; 1531 1532 /** 1533 * View flag indicating whether this view should have haptic feedback 1534 * enabled for events such as long presses. 1535 */ 1536 public static final int HAPTIC_FEEDBACK_ENABLED = 0x10000000; 1537 1538 /** 1539 * <p>Indicates that the view hierarchy should stop saving state when 1540 * it reaches this view. If state saving is initiated immediately at 1541 * the view, it will be allowed. 1542 * {@hide} 1543 */ 1544 static final int PARENT_SAVE_DISABLED = 0x20000000; 1545 1546 /** 1547 * <p>Mask for use with setFlags indicating bits used for PARENT_SAVE_DISABLED.</p> 1548 * {@hide} 1549 */ 1550 static final int PARENT_SAVE_DISABLED_MASK = 0x20000000; 1551 1552 private static Paint sDebugPaint; 1553 1554 /** 1555 * <p>Indicates this view can display a tooltip on hover or long press.</p> 1556 * {@hide} 1557 */ 1558 static final int TOOLTIP = 0x40000000; 1559 1560 /** @hide */ 1561 @IntDef(flag = true, 1562 value = { 1563 FOCUSABLES_ALL, 1564 FOCUSABLES_TOUCH_MODE 1565 }) 1566 @Retention(RetentionPolicy.SOURCE) 1567 public @interface FocusableMode {} 1568 1569 /** 1570 * View flag indicating whether {@link #addFocusables(ArrayList, int, int)} 1571 * should add all focusable Views regardless if they are focusable in touch mode. 1572 */ 1573 public static final int FOCUSABLES_ALL = 0x00000000; 1574 1575 /** 1576 * View flag indicating whether {@link #addFocusables(ArrayList, int, int)} 1577 * should add only Views focusable in touch mode. 1578 */ 1579 public static final int FOCUSABLES_TOUCH_MODE = 0x00000001; 1580 1581 /** @hide */ 1582 @IntDef({ 1583 FOCUS_BACKWARD, 1584 FOCUS_FORWARD, 1585 FOCUS_LEFT, 1586 FOCUS_UP, 1587 FOCUS_RIGHT, 1588 FOCUS_DOWN 1589 }) 1590 @Retention(RetentionPolicy.SOURCE) 1591 public @interface FocusDirection {} 1592 1593 /** @hide */ 1594 @IntDef({ 1595 FOCUS_LEFT, 1596 FOCUS_UP, 1597 FOCUS_RIGHT, 1598 FOCUS_DOWN 1599 }) 1600 @Retention(RetentionPolicy.SOURCE) 1601 public @interface FocusRealDirection {} // Like @FocusDirection, but without forward/backward 1602 1603 /** 1604 * Use with {@link #focusSearch(int)}. Move focus to the previous selectable 1605 * item. 1606 */ 1607 public static final int FOCUS_BACKWARD = 0x00000001; 1608 1609 /** 1610 * Use with {@link #focusSearch(int)}. Move focus to the next selectable 1611 * item. 1612 */ 1613 public static final int FOCUS_FORWARD = 0x00000002; 1614 1615 /** 1616 * Use with {@link #focusSearch(int)}. Move focus to the left. 1617 */ 1618 public static final int FOCUS_LEFT = 0x00000011; 1619 1620 /** 1621 * Use with {@link #focusSearch(int)}. Move focus up. 1622 */ 1623 public static final int FOCUS_UP = 0x00000021; 1624 1625 /** 1626 * Use with {@link #focusSearch(int)}. Move focus to the right. 1627 */ 1628 public static final int FOCUS_RIGHT = 0x00000042; 1629 1630 /** 1631 * Use with {@link #focusSearch(int)}. Move focus down. 1632 */ 1633 public static final int FOCUS_DOWN = 0x00000082; 1634 1635 /** 1636 * Bits of {@link #getMeasuredWidthAndState()} and 1637 * {@link #getMeasuredWidthAndState()} that provide the actual measured size. 1638 */ 1639 public static final int MEASURED_SIZE_MASK = 0x00ffffff; 1640 1641 /** 1642 * Bits of {@link #getMeasuredWidthAndState()} and 1643 * {@link #getMeasuredWidthAndState()} that provide the additional state bits. 1644 */ 1645 public static final int MEASURED_STATE_MASK = 0xff000000; 1646 1647 /** 1648 * Bit shift of {@link #MEASURED_STATE_MASK} to get to the height bits 1649 * for functions that combine both width and height into a single int, 1650 * such as {@link #getMeasuredState()} and the childState argument of 1651 * {@link #resolveSizeAndState(int, int, int)}. 1652 */ 1653 public static final int MEASURED_HEIGHT_STATE_SHIFT = 16; 1654 1655 /** 1656 * Bit of {@link #getMeasuredWidthAndState()} and 1657 * {@link #getMeasuredWidthAndState()} that indicates the measured size 1658 * is smaller that the space the view would like to have. 1659 */ 1660 public static final int MEASURED_STATE_TOO_SMALL = 0x01000000; 1661 1662 /** 1663 * Base View state sets 1664 */ 1665 // Singles 1666 /** 1667 * Indicates the view has no states set. States are used with 1668 * {@link android.graphics.drawable.Drawable} to change the drawing of the 1669 * view depending on its state. 1670 * 1671 * @see android.graphics.drawable.Drawable 1672 * @see #getDrawableState() 1673 */ 1674 protected static final int[] EMPTY_STATE_SET; 1675 /** 1676 * Indicates the view is enabled. States are used with 1677 * {@link android.graphics.drawable.Drawable} to change the drawing of the 1678 * view depending on its state. 1679 * 1680 * @see android.graphics.drawable.Drawable 1681 * @see #getDrawableState() 1682 */ 1683 protected static final int[] ENABLED_STATE_SET; 1684 /** 1685 * Indicates the view is focused. States are used with 1686 * {@link android.graphics.drawable.Drawable} to change the drawing of the 1687 * view depending on its state. 1688 * 1689 * @see android.graphics.drawable.Drawable 1690 * @see #getDrawableState() 1691 */ 1692 protected static final int[] FOCUSED_STATE_SET; 1693 /** 1694 * Indicates the view is selected. States are used with 1695 * {@link android.graphics.drawable.Drawable} to change the drawing of the 1696 * view depending on its state. 1697 * 1698 * @see android.graphics.drawable.Drawable 1699 * @see #getDrawableState() 1700 */ 1701 protected static final int[] SELECTED_STATE_SET; 1702 /** 1703 * Indicates the view is pressed. States are used with 1704 * {@link android.graphics.drawable.Drawable} to change the drawing of the 1705 * view depending on its state. 1706 * 1707 * @see android.graphics.drawable.Drawable 1708 * @see #getDrawableState() 1709 */ 1710 protected static final int[] PRESSED_STATE_SET; 1711 /** 1712 * Indicates the view's window has focus. States are used with 1713 * {@link android.graphics.drawable.Drawable} to change the drawing of the 1714 * view depending on its state. 1715 * 1716 * @see android.graphics.drawable.Drawable 1717 * @see #getDrawableState() 1718 */ 1719 protected static final int[] WINDOW_FOCUSED_STATE_SET; 1720 // Doubles 1721 /** 1722 * Indicates the view is enabled and has the focus. 1723 * 1724 * @see #ENABLED_STATE_SET 1725 * @see #FOCUSED_STATE_SET 1726 */ 1727 protected static final int[] ENABLED_FOCUSED_STATE_SET; 1728 /** 1729 * Indicates the view is enabled and selected. 1730 * 1731 * @see #ENABLED_STATE_SET 1732 * @see #SELECTED_STATE_SET 1733 */ 1734 protected static final int[] ENABLED_SELECTED_STATE_SET; 1735 /** 1736 * Indicates the view is enabled and that its window has focus. 1737 * 1738 * @see #ENABLED_STATE_SET 1739 * @see #WINDOW_FOCUSED_STATE_SET 1740 */ 1741 protected static final int[] ENABLED_WINDOW_FOCUSED_STATE_SET; 1742 /** 1743 * Indicates the view is focused and selected. 1744 * 1745 * @see #FOCUSED_STATE_SET 1746 * @see #SELECTED_STATE_SET 1747 */ 1748 protected static final int[] FOCUSED_SELECTED_STATE_SET; 1749 /** 1750 * Indicates the view has the focus and that its window has the focus. 1751 * 1752 * @see #FOCUSED_STATE_SET 1753 * @see #WINDOW_FOCUSED_STATE_SET 1754 */ 1755 protected static final int[] FOCUSED_WINDOW_FOCUSED_STATE_SET; 1756 /** 1757 * Indicates the view is selected and that its window has the focus. 1758 * 1759 * @see #SELECTED_STATE_SET 1760 * @see #WINDOW_FOCUSED_STATE_SET 1761 */ 1762 protected static final int[] SELECTED_WINDOW_FOCUSED_STATE_SET; 1763 // Triples 1764 /** 1765 * Indicates the view is enabled, focused and selected. 1766 * 1767 * @see #ENABLED_STATE_SET 1768 * @see #FOCUSED_STATE_SET 1769 * @see #SELECTED_STATE_SET 1770 */ 1771 protected static final int[] ENABLED_FOCUSED_SELECTED_STATE_SET; 1772 /** 1773 * Indicates the view is enabled, focused and its window has the focus. 1774 * 1775 * @see #ENABLED_STATE_SET 1776 * @see #FOCUSED_STATE_SET 1777 * @see #WINDOW_FOCUSED_STATE_SET 1778 */ 1779 protected static final int[] ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET; 1780 /** 1781 * Indicates the view is enabled, selected and its window has the focus. 1782 * 1783 * @see #ENABLED_STATE_SET 1784 * @see #SELECTED_STATE_SET 1785 * @see #WINDOW_FOCUSED_STATE_SET 1786 */ 1787 protected static final int[] ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET; 1788 /** 1789 * Indicates the view is focused, selected and its window has the focus. 1790 * 1791 * @see #FOCUSED_STATE_SET 1792 * @see #SELECTED_STATE_SET 1793 * @see #WINDOW_FOCUSED_STATE_SET 1794 */ 1795 protected static final int[] FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 1796 /** 1797 * Indicates the view is enabled, focused, selected and its window 1798 * has the focus. 1799 * 1800 * @see #ENABLED_STATE_SET 1801 * @see #FOCUSED_STATE_SET 1802 * @see #SELECTED_STATE_SET 1803 * @see #WINDOW_FOCUSED_STATE_SET 1804 */ 1805 protected static final int[] ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 1806 /** 1807 * Indicates the view is pressed and its window has the focus. 1808 * 1809 * @see #PRESSED_STATE_SET 1810 * @see #WINDOW_FOCUSED_STATE_SET 1811 */ 1812 protected static final int[] PRESSED_WINDOW_FOCUSED_STATE_SET; 1813 /** 1814 * Indicates the view is pressed and selected. 1815 * 1816 * @see #PRESSED_STATE_SET 1817 * @see #SELECTED_STATE_SET 1818 */ 1819 protected static final int[] PRESSED_SELECTED_STATE_SET; 1820 /** 1821 * Indicates the view is pressed, selected and its window has the focus. 1822 * 1823 * @see #PRESSED_STATE_SET 1824 * @see #SELECTED_STATE_SET 1825 * @see #WINDOW_FOCUSED_STATE_SET 1826 */ 1827 protected static final int[] PRESSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 1828 /** 1829 * Indicates the view is pressed and focused. 1830 * 1831 * @see #PRESSED_STATE_SET 1832 * @see #FOCUSED_STATE_SET 1833 */ 1834 protected static final int[] PRESSED_FOCUSED_STATE_SET; 1835 /** 1836 * Indicates the view is pressed, focused and its window has the focus. 1837 * 1838 * @see #PRESSED_STATE_SET 1839 * @see #FOCUSED_STATE_SET 1840 * @see #WINDOW_FOCUSED_STATE_SET 1841 */ 1842 protected static final int[] PRESSED_FOCUSED_WINDOW_FOCUSED_STATE_SET; 1843 /** 1844 * Indicates the view is pressed, focused and selected. 1845 * 1846 * @see #PRESSED_STATE_SET 1847 * @see #SELECTED_STATE_SET 1848 * @see #FOCUSED_STATE_SET 1849 */ 1850 protected static final int[] PRESSED_FOCUSED_SELECTED_STATE_SET; 1851 /** 1852 * Indicates the view is pressed, focused, selected and its window has the focus. 1853 * 1854 * @see #PRESSED_STATE_SET 1855 * @see #FOCUSED_STATE_SET 1856 * @see #SELECTED_STATE_SET 1857 * @see #WINDOW_FOCUSED_STATE_SET 1858 */ 1859 protected static final int[] PRESSED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 1860 /** 1861 * Indicates the view is pressed and enabled. 1862 * 1863 * @see #PRESSED_STATE_SET 1864 * @see #ENABLED_STATE_SET 1865 */ 1866 protected static final int[] PRESSED_ENABLED_STATE_SET; 1867 /** 1868 * Indicates the view is pressed, enabled and its window has the focus. 1869 * 1870 * @see #PRESSED_STATE_SET 1871 * @see #ENABLED_STATE_SET 1872 * @see #WINDOW_FOCUSED_STATE_SET 1873 */ 1874 protected static final int[] PRESSED_ENABLED_WINDOW_FOCUSED_STATE_SET; 1875 /** 1876 * Indicates the view is pressed, enabled and selected. 1877 * 1878 * @see #PRESSED_STATE_SET 1879 * @see #ENABLED_STATE_SET 1880 * @see #SELECTED_STATE_SET 1881 */ 1882 protected static final int[] PRESSED_ENABLED_SELECTED_STATE_SET; 1883 /** 1884 * Indicates the view is pressed, enabled, selected and its window has the 1885 * focus. 1886 * 1887 * @see #PRESSED_STATE_SET 1888 * @see #ENABLED_STATE_SET 1889 * @see #SELECTED_STATE_SET 1890 * @see #WINDOW_FOCUSED_STATE_SET 1891 */ 1892 protected static final int[] PRESSED_ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET; 1893 /** 1894 * Indicates the view is pressed, enabled and focused. 1895 * 1896 * @see #PRESSED_STATE_SET 1897 * @see #ENABLED_STATE_SET 1898 * @see #FOCUSED_STATE_SET 1899 */ 1900 protected static final int[] PRESSED_ENABLED_FOCUSED_STATE_SET; 1901 /** 1902 * Indicates the view is pressed, enabled, focused and its window has the 1903 * focus. 1904 * 1905 * @see #PRESSED_STATE_SET 1906 * @see #ENABLED_STATE_SET 1907 * @see #FOCUSED_STATE_SET 1908 * @see #WINDOW_FOCUSED_STATE_SET 1909 */ 1910 protected static final int[] PRESSED_ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET; 1911 /** 1912 * Indicates the view is pressed, enabled, focused and selected. 1913 * 1914 * @see #PRESSED_STATE_SET 1915 * @see #ENABLED_STATE_SET 1916 * @see #SELECTED_STATE_SET 1917 * @see #FOCUSED_STATE_SET 1918 */ 1919 protected static final int[] PRESSED_ENABLED_FOCUSED_SELECTED_STATE_SET; 1920 /** 1921 * Indicates the view is pressed, enabled, focused, selected and its window 1922 * has the focus. 1923 * 1924 * @see #PRESSED_STATE_SET 1925 * @see #ENABLED_STATE_SET 1926 * @see #SELECTED_STATE_SET 1927 * @see #FOCUSED_STATE_SET 1928 * @see #WINDOW_FOCUSED_STATE_SET 1929 */ 1930 protected static final int[] PRESSED_ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 1931 1932 static { 1933 EMPTY_STATE_SET = StateSet.get(0); 1934 1935 WINDOW_FOCUSED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_WINDOW_FOCUSED); 1936 1937 SELECTED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_SELECTED); 1938 SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1939 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED); 1940 1941 FOCUSED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_FOCUSED); 1942 FOCUSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1943 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_FOCUSED); 1944 FOCUSED_SELECTED_STATE_SET = StateSet.get( 1945 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_FOCUSED); 1946 FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1947 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 1948 | StateSet.VIEW_STATE_FOCUSED); 1949 1950 ENABLED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_ENABLED); 1951 ENABLED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1952 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_ENABLED); 1953 ENABLED_SELECTED_STATE_SET = StateSet.get( 1954 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_ENABLED); 1955 ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1956 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 1957 | StateSet.VIEW_STATE_ENABLED); 1958 ENABLED_FOCUSED_STATE_SET = StateSet.get( 1959 StateSet.VIEW_STATE_FOCUSED | StateSet.VIEW_STATE_ENABLED); 1960 ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1961 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_FOCUSED 1962 | StateSet.VIEW_STATE_ENABLED); 1963 ENABLED_FOCUSED_SELECTED_STATE_SET = StateSet.get( 1964 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_FOCUSED 1965 | StateSet.VIEW_STATE_ENABLED); 1966 ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1967 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 1968 | StateSet.VIEW_STATE_FOCUSED| StateSet.VIEW_STATE_ENABLED); 1969 1970 PRESSED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_PRESSED); 1971 PRESSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1972 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_PRESSED); 1973 PRESSED_SELECTED_STATE_SET = StateSet.get( 1974 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_PRESSED); 1975 PRESSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1976 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 1977 | StateSet.VIEW_STATE_PRESSED); 1978 PRESSED_FOCUSED_STATE_SET = StateSet.get( 1979 StateSet.VIEW_STATE_FOCUSED | StateSet.VIEW_STATE_PRESSED); 1980 PRESSED_FOCUSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1981 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_FOCUSED 1982 | StateSet.VIEW_STATE_PRESSED); 1983 PRESSED_FOCUSED_SELECTED_STATE_SET = StateSet.get( 1984 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_FOCUSED 1985 | StateSet.VIEW_STATE_PRESSED); 1986 PRESSED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1987 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 1988 | StateSet.VIEW_STATE_FOCUSED | StateSet.VIEW_STATE_PRESSED); 1989 PRESSED_ENABLED_STATE_SET = StateSet.get( 1990 StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_PRESSED); 1991 PRESSED_ENABLED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1992 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_ENABLED 1993 | StateSet.VIEW_STATE_PRESSED); 1994 PRESSED_ENABLED_SELECTED_STATE_SET = StateSet.get( 1995 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_ENABLED 1996 | StateSet.VIEW_STATE_PRESSED); 1997 PRESSED_ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1998 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 1999 | StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_PRESSED); 2000 PRESSED_ENABLED_FOCUSED_STATE_SET = StateSet.get( 2001 StateSet.VIEW_STATE_FOCUSED | StateSet.VIEW_STATE_ENABLED 2002 | StateSet.VIEW_STATE_PRESSED); 2003 PRESSED_ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2004 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_FOCUSED 2005 | StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_PRESSED); 2006 PRESSED_ENABLED_FOCUSED_SELECTED_STATE_SET = StateSet.get( 2007 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_FOCUSED 2008 | StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_PRESSED); 2009 PRESSED_ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2010 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 2011 | StateSet.VIEW_STATE_FOCUSED| StateSet.VIEW_STATE_ENABLED 2012 | StateSet.VIEW_STATE_PRESSED); 2013 } 2014 2015 /** 2016 * Accessibility event types that are dispatched for text population. 2017 */ 2018 private static final int POPULATING_ACCESSIBILITY_EVENT_TYPES = 2019 AccessibilityEvent.TYPE_VIEW_CLICKED 2020 | AccessibilityEvent.TYPE_VIEW_LONG_CLICKED 2021 | AccessibilityEvent.TYPE_VIEW_SELECTED 2022 | AccessibilityEvent.TYPE_VIEW_FOCUSED 2023 | AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED 2024 | AccessibilityEvent.TYPE_VIEW_HOVER_ENTER 2025 | AccessibilityEvent.TYPE_VIEW_HOVER_EXIT 2026 | AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED 2027 | AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED 2028 | AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED 2029 | AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY; 2030 2031 static final int DEBUG_CORNERS_COLOR = Color.rgb(63, 127, 255); 2032 2033 static final int DEBUG_CORNERS_SIZE_DIP = 8; 2034 2035 /** 2036 * Temporary Rect currently for use in setBackground(). This will probably 2037 * be extended in the future to hold our own class with more than just 2038 * a Rect. :) 2039 */ 2040 static final ThreadLocal<Rect> sThreadLocal = new ThreadLocal<Rect>(); 2041 2042 /** 2043 * Map used to store views' tags. 2044 */ 2045 private SparseArray<Object> mKeyedTags; 2046 2047 /** 2048 * The next available accessibility id. 2049 */ 2050 private static int sNextAccessibilityViewId; 2051 2052 /** 2053 * The animation currently associated with this view. 2054 * @hide 2055 */ 2056 protected Animation mCurrentAnimation = null; 2057 2058 /** 2059 * Width as measured during measure pass. 2060 * {@hide} 2061 */ 2062 @ViewDebug.ExportedProperty(category = "measurement") 2063 int mMeasuredWidth; 2064 2065 /** 2066 * Height as measured during measure pass. 2067 * {@hide} 2068 */ 2069 @ViewDebug.ExportedProperty(category = "measurement") 2070 int mMeasuredHeight; 2071 2072 /** 2073 * Flag to indicate that this view was marked INVALIDATED, or had its display list 2074 * invalidated, prior to the current drawing iteration. If true, the view must re-draw 2075 * its display list. This flag, used only when hw accelerated, allows us to clear the 2076 * flag while retaining this information until it's needed (at getDisplayList() time and 2077 * in drawChild(), when we decide to draw a view's children's display lists into our own). 2078 * 2079 * {@hide} 2080 */ 2081 boolean mRecreateDisplayList = false; 2082 2083 /** 2084 * The view's identifier. 2085 * {@hide} 2086 * 2087 * @see #setId(int) 2088 * @see #getId() 2089 */ 2090 @IdRes 2091 @ViewDebug.ExportedProperty(resolveId = true) 2092 int mID = NO_ID; 2093 2094 /** The ID of this view for autofill purposes. 2095 * <ul> 2096 * <li>== {@link #NO_ID}: ID has not been assigned yet 2097 * <li>≤ {@link #LAST_APP_AUTOFILL_ID}: View is not part of a activity. The ID is 2098 * unique in the process. This might change 2099 * over activity lifecycle events. 2100 * <li>> {@link #LAST_APP_AUTOFILL_ID}: View is part of a activity. The ID is 2101 * unique in the activity. This stays the same 2102 * over activity lifecycle events. 2103 */ 2104 private int mAutofillViewId = NO_ID; 2105 2106 // ID for accessibility purposes. This ID must be unique for every window 2107 private int mAccessibilityViewId = NO_ID; 2108 2109 private int mAccessibilityCursorPosition = ACCESSIBILITY_CURSOR_POSITION_UNDEFINED; 2110 2111 /** 2112 * The view's tag. 2113 * {@hide} 2114 * 2115 * @see #setTag(Object) 2116 * @see #getTag() 2117 */ 2118 protected Object mTag = null; 2119 2120 // for mPrivateFlags: 2121 /** {@hide} */ 2122 static final int PFLAG_WANTS_FOCUS = 0x00000001; 2123 /** {@hide} */ 2124 static final int PFLAG_FOCUSED = 0x00000002; 2125 /** {@hide} */ 2126 static final int PFLAG_SELECTED = 0x00000004; 2127 /** {@hide} */ 2128 static final int PFLAG_IS_ROOT_NAMESPACE = 0x00000008; 2129 /** {@hide} */ 2130 static final int PFLAG_HAS_BOUNDS = 0x00000010; 2131 /** {@hide} */ 2132 static final int PFLAG_DRAWN = 0x00000020; 2133 /** 2134 * When this flag is set, this view is running an animation on behalf of its 2135 * children and should therefore not cancel invalidate requests, even if they 2136 * lie outside of this view's bounds. 2137 * 2138 * {@hide} 2139 */ 2140 static final int PFLAG_DRAW_ANIMATION = 0x00000040; 2141 /** {@hide} */ 2142 static final int PFLAG_SKIP_DRAW = 0x00000080; 2143 /** {@hide} */ 2144 static final int PFLAG_REQUEST_TRANSPARENT_REGIONS = 0x00000200; 2145 /** {@hide} */ 2146 static final int PFLAG_DRAWABLE_STATE_DIRTY = 0x00000400; 2147 /** {@hide} */ 2148 static final int PFLAG_MEASURED_DIMENSION_SET = 0x00000800; 2149 /** {@hide} */ 2150 static final int PFLAG_FORCE_LAYOUT = 0x00001000; 2151 /** {@hide} */ 2152 static final int PFLAG_LAYOUT_REQUIRED = 0x00002000; 2153 2154 private static final int PFLAG_PRESSED = 0x00004000; 2155 2156 /** {@hide} */ 2157 static final int PFLAG_DRAWING_CACHE_VALID = 0x00008000; 2158 /** 2159 * Flag used to indicate that this view should be drawn once more (and only once 2160 * more) after its animation has completed. 2161 * {@hide} 2162 */ 2163 static final int PFLAG_ANIMATION_STARTED = 0x00010000; 2164 2165 private static final int PFLAG_SAVE_STATE_CALLED = 0x00020000; 2166 2167 /** 2168 * Indicates that the View returned true when onSetAlpha() was called and that 2169 * the alpha must be restored. 2170 * {@hide} 2171 */ 2172 static final int PFLAG_ALPHA_SET = 0x00040000; 2173 2174 /** 2175 * Set by {@link #setScrollContainer(boolean)}. 2176 */ 2177 static final int PFLAG_SCROLL_CONTAINER = 0x00080000; 2178 2179 /** 2180 * Set by {@link #setScrollContainer(boolean)}. 2181 */ 2182 static final int PFLAG_SCROLL_CONTAINER_ADDED = 0x00100000; 2183 2184 /** 2185 * View flag indicating whether this view was invalidated (fully or partially.) 2186 * 2187 * @hide 2188 */ 2189 static final int PFLAG_DIRTY = 0x00200000; 2190 2191 /** 2192 * View flag indicating whether this view was invalidated by an opaque 2193 * invalidate request. 2194 * 2195 * @hide 2196 */ 2197 static final int PFLAG_DIRTY_OPAQUE = 0x00400000; 2198 2199 /** 2200 * Mask for {@link #PFLAG_DIRTY} and {@link #PFLAG_DIRTY_OPAQUE}. 2201 * 2202 * @hide 2203 */ 2204 static final int PFLAG_DIRTY_MASK = 0x00600000; 2205 2206 /** 2207 * Indicates whether the background is opaque. 2208 * 2209 * @hide 2210 */ 2211 static final int PFLAG_OPAQUE_BACKGROUND = 0x00800000; 2212 2213 /** 2214 * Indicates whether the scrollbars are opaque. 2215 * 2216 * @hide 2217 */ 2218 static final int PFLAG_OPAQUE_SCROLLBARS = 0x01000000; 2219 2220 /** 2221 * Indicates whether the view is opaque. 2222 * 2223 * @hide 2224 */ 2225 static final int PFLAG_OPAQUE_MASK = 0x01800000; 2226 2227 /** 2228 * Indicates a prepressed state; 2229 * the short time between ACTION_DOWN and recognizing 2230 * a 'real' press. Prepressed is used to recognize quick taps 2231 * even when they are shorter than ViewConfiguration.getTapTimeout(). 2232 * 2233 * @hide 2234 */ 2235 private static final int PFLAG_PREPRESSED = 0x02000000; 2236 2237 /** 2238 * Indicates whether the view is temporarily detached. 2239 * 2240 * @hide 2241 */ 2242 static final int PFLAG_CANCEL_NEXT_UP_EVENT = 0x04000000; 2243 2244 /** 2245 * Indicates that we should awaken scroll bars once attached 2246 * 2247 * PLEASE NOTE: This flag is now unused as we now send onVisibilityChanged 2248 * during window attachment and it is no longer needed. Feel free to repurpose it. 2249 * 2250 * @hide 2251 */ 2252 private static final int PFLAG_AWAKEN_SCROLL_BARS_ON_ATTACH = 0x08000000; 2253 2254 /** 2255 * Indicates that the view has received HOVER_ENTER. Cleared on HOVER_EXIT. 2256 * @hide 2257 */ 2258 private static final int PFLAG_HOVERED = 0x10000000; 2259 2260 /** 2261 * no longer needed, should be reused 2262 */ 2263 private static final int PFLAG_DOES_NOTHING_REUSE_PLEASE = 0x20000000; 2264 2265 /** {@hide} */ 2266 static final int PFLAG_ACTIVATED = 0x40000000; 2267 2268 /** 2269 * Indicates that this view was specifically invalidated, not just dirtied because some 2270 * child view was invalidated. The flag is used to determine when we need to recreate 2271 * a view's display list (as opposed to just returning a reference to its existing 2272 * display list). 2273 * 2274 * @hide 2275 */ 2276 static final int PFLAG_INVALIDATED = 0x80000000; 2277 2278 /** 2279 * Masks for mPrivateFlags2, as generated by dumpFlags(): 2280 * 2281 * |-------|-------|-------|-------| 2282 * 1 PFLAG2_DRAG_CAN_ACCEPT 2283 * 1 PFLAG2_DRAG_HOVERED 2284 * 11 PFLAG2_LAYOUT_DIRECTION_MASK 2285 * 1 PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL 2286 * 1 PFLAG2_LAYOUT_DIRECTION_RESOLVED 2287 * 11 PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK 2288 * 1 PFLAG2_TEXT_DIRECTION_FLAGS[1] 2289 * 1 PFLAG2_TEXT_DIRECTION_FLAGS[2] 2290 * 11 PFLAG2_TEXT_DIRECTION_FLAGS[3] 2291 * 1 PFLAG2_TEXT_DIRECTION_FLAGS[4] 2292 * 1 1 PFLAG2_TEXT_DIRECTION_FLAGS[5] 2293 * 11 PFLAG2_TEXT_DIRECTION_FLAGS[6] 2294 * 111 PFLAG2_TEXT_DIRECTION_FLAGS[7] 2295 * 111 PFLAG2_TEXT_DIRECTION_MASK 2296 * 1 PFLAG2_TEXT_DIRECTION_RESOLVED 2297 * 1 PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT 2298 * 111 PFLAG2_TEXT_DIRECTION_RESOLVED_MASK 2299 * 1 PFLAG2_TEXT_ALIGNMENT_FLAGS[1] 2300 * 1 PFLAG2_TEXT_ALIGNMENT_FLAGS[2] 2301 * 11 PFLAG2_TEXT_ALIGNMENT_FLAGS[3] 2302 * 1 PFLAG2_TEXT_ALIGNMENT_FLAGS[4] 2303 * 1 1 PFLAG2_TEXT_ALIGNMENT_FLAGS[5] 2304 * 11 PFLAG2_TEXT_ALIGNMENT_FLAGS[6] 2305 * 111 PFLAG2_TEXT_ALIGNMENT_MASK 2306 * 1 PFLAG2_TEXT_ALIGNMENT_RESOLVED 2307 * 1 PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT 2308 * 111 PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK 2309 * 111 PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK 2310 * 11 PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK 2311 * 1 PFLAG2_ACCESSIBILITY_FOCUSED 2312 * 1 PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED 2313 * 1 PFLAG2_VIEW_QUICK_REJECTED 2314 * 1 PFLAG2_PADDING_RESOLVED 2315 * 1 PFLAG2_DRAWABLE_RESOLVED 2316 * 1 PFLAG2_HAS_TRANSIENT_STATE 2317 * |-------|-------|-------|-------| 2318 */ 2319 2320 /** 2321 * Indicates that this view has reported that it can accept the current drag's content. 2322 * Cleared when the drag operation concludes. 2323 * @hide 2324 */ 2325 static final int PFLAG2_DRAG_CAN_ACCEPT = 0x00000001; 2326 2327 /** 2328 * Indicates that this view is currently directly under the drag location in a 2329 * drag-and-drop operation involving content that it can accept. Cleared when 2330 * the drag exits the view, or when the drag operation concludes. 2331 * @hide 2332 */ 2333 static final int PFLAG2_DRAG_HOVERED = 0x00000002; 2334 2335 /** @hide */ 2336 @IntDef({ 2337 LAYOUT_DIRECTION_LTR, 2338 LAYOUT_DIRECTION_RTL, 2339 LAYOUT_DIRECTION_INHERIT, 2340 LAYOUT_DIRECTION_LOCALE 2341 }) 2342 @Retention(RetentionPolicy.SOURCE) 2343 // Not called LayoutDirection to avoid conflict with android.util.LayoutDirection 2344 public @interface LayoutDir {} 2345 2346 /** @hide */ 2347 @IntDef({ 2348 LAYOUT_DIRECTION_LTR, 2349 LAYOUT_DIRECTION_RTL 2350 }) 2351 @Retention(RetentionPolicy.SOURCE) 2352 public @interface ResolvedLayoutDir {} 2353 2354 /** 2355 * A flag to indicate that the layout direction of this view has not been defined yet. 2356 * @hide 2357 */ 2358 public static final int LAYOUT_DIRECTION_UNDEFINED = LayoutDirection.UNDEFINED; 2359 2360 /** 2361 * Horizontal layout direction of this view is from Left to Right. 2362 * Use with {@link #setLayoutDirection}. 2363 */ 2364 public static final int LAYOUT_DIRECTION_LTR = LayoutDirection.LTR; 2365 2366 /** 2367 * Horizontal layout direction of this view is from Right to Left. 2368 * Use with {@link #setLayoutDirection}. 2369 */ 2370 public static final int LAYOUT_DIRECTION_RTL = LayoutDirection.RTL; 2371 2372 /** 2373 * Horizontal layout direction of this view is inherited from its parent. 2374 * Use with {@link #setLayoutDirection}. 2375 */ 2376 public static final int LAYOUT_DIRECTION_INHERIT = LayoutDirection.INHERIT; 2377 2378 /** 2379 * Horizontal layout direction of this view is from deduced from the default language 2380 * script for the locale. Use with {@link #setLayoutDirection}. 2381 */ 2382 public static final int LAYOUT_DIRECTION_LOCALE = LayoutDirection.LOCALE; 2383 2384 /** 2385 * Bit shift to get the horizontal layout direction. (bits after DRAG_HOVERED) 2386 * @hide 2387 */ 2388 static final int PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT = 2; 2389 2390 /** 2391 * Mask for use with private flags indicating bits used for horizontal layout direction. 2392 * @hide 2393 */ 2394 static final int PFLAG2_LAYOUT_DIRECTION_MASK = 0x00000003 << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 2395 2396 /** 2397 * Indicates whether the view horizontal layout direction has been resolved and drawn to the 2398 * right-to-left direction. 2399 * @hide 2400 */ 2401 static final int PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL = 4 << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 2402 2403 /** 2404 * Indicates whether the view horizontal layout direction has been resolved. 2405 * @hide 2406 */ 2407 static final int PFLAG2_LAYOUT_DIRECTION_RESOLVED = 8 << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 2408 2409 /** 2410 * Mask for use with private flags indicating bits used for resolved horizontal layout direction. 2411 * @hide 2412 */ 2413 static final int PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK = 0x0000000C 2414 << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 2415 2416 /* 2417 * Array of horizontal layout direction flags for mapping attribute "layoutDirection" to correct 2418 * flag value. 2419 * @hide 2420 */ 2421 private static final int[] LAYOUT_DIRECTION_FLAGS = { 2422 LAYOUT_DIRECTION_LTR, 2423 LAYOUT_DIRECTION_RTL, 2424 LAYOUT_DIRECTION_INHERIT, 2425 LAYOUT_DIRECTION_LOCALE 2426 }; 2427 2428 /** 2429 * Default horizontal layout direction. 2430 */ 2431 private static final int LAYOUT_DIRECTION_DEFAULT = LAYOUT_DIRECTION_INHERIT; 2432 2433 /** 2434 * Default horizontal layout direction. 2435 * @hide 2436 */ 2437 static final int LAYOUT_DIRECTION_RESOLVED_DEFAULT = LAYOUT_DIRECTION_LTR; 2438 2439 /** 2440 * Text direction is inherited through {@link ViewGroup} 2441 */ 2442 public static final int TEXT_DIRECTION_INHERIT = 0; 2443 2444 /** 2445 * Text direction is using "first strong algorithm". The first strong directional character 2446 * determines the paragraph direction. If there is no strong directional character, the 2447 * paragraph direction is the view's resolved layout direction. 2448 */ 2449 public static final int TEXT_DIRECTION_FIRST_STRONG = 1; 2450 2451 /** 2452 * Text direction is using "any-RTL" algorithm. The paragraph direction is RTL if it contains 2453 * any strong RTL character, otherwise it is LTR if it contains any strong LTR characters. 2454 * If there are neither, the paragraph direction is the view's resolved layout direction. 2455 */ 2456 public static final int TEXT_DIRECTION_ANY_RTL = 2; 2457 2458 /** 2459 * Text direction is forced to LTR. 2460 */ 2461 public static final int TEXT_DIRECTION_LTR = 3; 2462 2463 /** 2464 * Text direction is forced to RTL. 2465 */ 2466 public static final int TEXT_DIRECTION_RTL = 4; 2467 2468 /** 2469 * Text direction is coming from the system Locale. 2470 */ 2471 public static final int TEXT_DIRECTION_LOCALE = 5; 2472 2473 /** 2474 * Text direction is using "first strong algorithm". The first strong directional character 2475 * determines the paragraph direction. If there is no strong directional character, the 2476 * paragraph direction is LTR. 2477 */ 2478 public static final int TEXT_DIRECTION_FIRST_STRONG_LTR = 6; 2479 2480 /** 2481 * Text direction is using "first strong algorithm". The first strong directional character 2482 * determines the paragraph direction. If there is no strong directional character, the 2483 * paragraph direction is RTL. 2484 */ 2485 public static final int TEXT_DIRECTION_FIRST_STRONG_RTL = 7; 2486 2487 /** 2488 * Default text direction is inherited 2489 */ 2490 private static final int TEXT_DIRECTION_DEFAULT = TEXT_DIRECTION_INHERIT; 2491 2492 /** 2493 * Default resolved text direction 2494 * @hide 2495 */ 2496 static final int TEXT_DIRECTION_RESOLVED_DEFAULT = TEXT_DIRECTION_FIRST_STRONG; 2497 2498 /** 2499 * Bit shift to get the horizontal layout direction. (bits after LAYOUT_DIRECTION_RESOLVED) 2500 * @hide 2501 */ 2502 static final int PFLAG2_TEXT_DIRECTION_MASK_SHIFT = 6; 2503 2504 /** 2505 * Mask for use with private flags indicating bits used for text direction. 2506 * @hide 2507 */ 2508 static final int PFLAG2_TEXT_DIRECTION_MASK = 0x00000007 2509 << PFLAG2_TEXT_DIRECTION_MASK_SHIFT; 2510 2511 /** 2512 * Array of text direction flags for mapping attribute "textDirection" to correct 2513 * flag value. 2514 * @hide 2515 */ 2516 private static final int[] PFLAG2_TEXT_DIRECTION_FLAGS = { 2517 TEXT_DIRECTION_INHERIT << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2518 TEXT_DIRECTION_FIRST_STRONG << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2519 TEXT_DIRECTION_ANY_RTL << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2520 TEXT_DIRECTION_LTR << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2521 TEXT_DIRECTION_RTL << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2522 TEXT_DIRECTION_LOCALE << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2523 TEXT_DIRECTION_FIRST_STRONG_LTR << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2524 TEXT_DIRECTION_FIRST_STRONG_RTL << PFLAG2_TEXT_DIRECTION_MASK_SHIFT 2525 }; 2526 2527 /** 2528 * Indicates whether the view text direction has been resolved. 2529 * @hide 2530 */ 2531 static final int PFLAG2_TEXT_DIRECTION_RESOLVED = 0x00000008 2532 << PFLAG2_TEXT_DIRECTION_MASK_SHIFT; 2533 2534 /** 2535 * Bit shift to get the horizontal layout direction. (bits after DRAG_HOVERED) 2536 * @hide 2537 */ 2538 static final int PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT = 10; 2539 2540 /** 2541 * Mask for use with private flags indicating bits used for resolved text direction. 2542 * @hide 2543 */ 2544 static final int PFLAG2_TEXT_DIRECTION_RESOLVED_MASK = 0x00000007 2545 << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT; 2546 2547 /** 2548 * Indicates whether the view text direction has been resolved to the "first strong" heuristic. 2549 * @hide 2550 */ 2551 static final int PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT = 2552 TEXT_DIRECTION_RESOLVED_DEFAULT << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT; 2553 2554 /** @hide */ 2555 @IntDef({ 2556 TEXT_ALIGNMENT_INHERIT, 2557 TEXT_ALIGNMENT_GRAVITY, 2558 TEXT_ALIGNMENT_CENTER, 2559 TEXT_ALIGNMENT_TEXT_START, 2560 TEXT_ALIGNMENT_TEXT_END, 2561 TEXT_ALIGNMENT_VIEW_START, 2562 TEXT_ALIGNMENT_VIEW_END 2563 }) 2564 @Retention(RetentionPolicy.SOURCE) 2565 public @interface TextAlignment {} 2566 2567 /** 2568 * Default text alignment. The text alignment of this View is inherited from its parent. 2569 * Use with {@link #setTextAlignment(int)} 2570 */ 2571 public static final int TEXT_ALIGNMENT_INHERIT = 0; 2572 2573 /** 2574 * Default for the root view. The gravity determines the text alignment, ALIGN_NORMAL, 2575 * ALIGN_CENTER, or ALIGN_OPPOSITE, which are relative to each paragraph’s text direction. 2576 * 2577 * Use with {@link #setTextAlignment(int)} 2578 */ 2579 public static final int TEXT_ALIGNMENT_GRAVITY = 1; 2580 2581 /** 2582 * Align to the start of the paragraph, e.g. ALIGN_NORMAL. 2583 * 2584 * Use with {@link #setTextAlignment(int)} 2585 */ 2586 public static final int TEXT_ALIGNMENT_TEXT_START = 2; 2587 2588 /** 2589 * Align to the end of the paragraph, e.g. ALIGN_OPPOSITE. 2590 * 2591 * Use with {@link #setTextAlignment(int)} 2592 */ 2593 public static final int TEXT_ALIGNMENT_TEXT_END = 3; 2594 2595 /** 2596 * Center the paragraph, e.g. ALIGN_CENTER. 2597 * 2598 * Use with {@link #setTextAlignment(int)} 2599 */ 2600 public static final int TEXT_ALIGNMENT_CENTER = 4; 2601 2602 /** 2603 * Align to the start of the view, which is ALIGN_LEFT if the view’s resolved 2604 * layoutDirection is LTR, and ALIGN_RIGHT otherwise. 2605 * 2606 * Use with {@link #setTextAlignment(int)} 2607 */ 2608 public static final int TEXT_ALIGNMENT_VIEW_START = 5; 2609 2610 /** 2611 * Align to the end of the view, which is ALIGN_RIGHT if the view’s resolved 2612 * layoutDirection is LTR, and ALIGN_LEFT otherwise. 2613 * 2614 * Use with {@link #setTextAlignment(int)} 2615 */ 2616 public static final int TEXT_ALIGNMENT_VIEW_END = 6; 2617 2618 /** 2619 * Default text alignment is inherited 2620 */ 2621 private static final int TEXT_ALIGNMENT_DEFAULT = TEXT_ALIGNMENT_GRAVITY; 2622 2623 /** 2624 * Default resolved text alignment 2625 * @hide 2626 */ 2627 static final int TEXT_ALIGNMENT_RESOLVED_DEFAULT = TEXT_ALIGNMENT_GRAVITY; 2628 2629 /** 2630 * Bit shift to get the horizontal layout direction. (bits after DRAG_HOVERED) 2631 * @hide 2632 */ 2633 static final int PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT = 13; 2634 2635 /** 2636 * Mask for use with private flags indicating bits used for text alignment. 2637 * @hide 2638 */ 2639 static final int PFLAG2_TEXT_ALIGNMENT_MASK = 0x00000007 << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT; 2640 2641 /** 2642 * Array of text direction flags for mapping attribute "textAlignment" to correct 2643 * flag value. 2644 * @hide 2645 */ 2646 private static final int[] PFLAG2_TEXT_ALIGNMENT_FLAGS = { 2647 TEXT_ALIGNMENT_INHERIT << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 2648 TEXT_ALIGNMENT_GRAVITY << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 2649 TEXT_ALIGNMENT_TEXT_START << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 2650 TEXT_ALIGNMENT_TEXT_END << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 2651 TEXT_ALIGNMENT_CENTER << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 2652 TEXT_ALIGNMENT_VIEW_START << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 2653 TEXT_ALIGNMENT_VIEW_END << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT 2654 }; 2655 2656 /** 2657 * Indicates whether the view text alignment has been resolved. 2658 * @hide 2659 */ 2660 static final int PFLAG2_TEXT_ALIGNMENT_RESOLVED = 0x00000008 << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT; 2661 2662 /** 2663 * Bit shift to get the resolved text alignment. 2664 * @hide 2665 */ 2666 static final int PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT = 17; 2667 2668 /** 2669 * Mask for use with private flags indicating bits used for text alignment. 2670 * @hide 2671 */ 2672 static final int PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK = 0x00000007 2673 << PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT; 2674 2675 /** 2676 * Indicates whether if the view text alignment has been resolved to gravity 2677 */ 2678 private static final int PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT = 2679 TEXT_ALIGNMENT_RESOLVED_DEFAULT << PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT; 2680 2681 // Accessiblity constants for mPrivateFlags2 2682 2683 /** 2684 * Shift for the bits in {@link #mPrivateFlags2} related to the 2685 * "importantForAccessibility" attribute. 2686 */ 2687 static final int PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT = 20; 2688 2689 /** 2690 * Automatically determine whether a view is important for accessibility. 2691 */ 2692 public static final int IMPORTANT_FOR_ACCESSIBILITY_AUTO = 0x00000000; 2693 2694 /** 2695 * The view is important for accessibility. 2696 */ 2697 public static final int IMPORTANT_FOR_ACCESSIBILITY_YES = 0x00000001; 2698 2699 /** 2700 * The view is not important for accessibility. 2701 */ 2702 public static final int IMPORTANT_FOR_ACCESSIBILITY_NO = 0x00000002; 2703 2704 /** 2705 * The view is not important for accessibility, nor are any of its 2706 * descendant views. 2707 */ 2708 public static final int IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS = 0x00000004; 2709 2710 /** 2711 * The default whether the view is important for accessibility. 2712 */ 2713 static final int IMPORTANT_FOR_ACCESSIBILITY_DEFAULT = IMPORTANT_FOR_ACCESSIBILITY_AUTO; 2714 2715 /** 2716 * Mask for obtaining the bits which specify how to determine 2717 * whether a view is important for accessibility. 2718 */ 2719 static final int PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK = (IMPORTANT_FOR_ACCESSIBILITY_AUTO 2720 | IMPORTANT_FOR_ACCESSIBILITY_YES | IMPORTANT_FOR_ACCESSIBILITY_NO 2721 | IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS) 2722 << PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT; 2723 2724 /** 2725 * Shift for the bits in {@link #mPrivateFlags2} related to the 2726 * "accessibilityLiveRegion" attribute. 2727 */ 2728 static final int PFLAG2_ACCESSIBILITY_LIVE_REGION_SHIFT = 23; 2729 2730 /** 2731 * Live region mode specifying that accessibility services should not 2732 * automatically announce changes to this view. This is the default live 2733 * region mode for most views. 2734 * <p> 2735 * Use with {@link #setAccessibilityLiveRegion(int)}. 2736 */ 2737 public static final int ACCESSIBILITY_LIVE_REGION_NONE = 0x00000000; 2738 2739 /** 2740 * Live region mode specifying that accessibility services should announce 2741 * changes to this view. 2742 * <p> 2743 * Use with {@link #setAccessibilityLiveRegion(int)}. 2744 */ 2745 public static final int ACCESSIBILITY_LIVE_REGION_POLITE = 0x00000001; 2746 2747 /** 2748 * Live region mode specifying that accessibility services should interrupt 2749 * ongoing speech to immediately announce changes to this view. 2750 * <p> 2751 * Use with {@link #setAccessibilityLiveRegion(int)}. 2752 */ 2753 public static final int ACCESSIBILITY_LIVE_REGION_ASSERTIVE = 0x00000002; 2754 2755 /** 2756 * The default whether the view is important for accessibility. 2757 */ 2758 static final int ACCESSIBILITY_LIVE_REGION_DEFAULT = ACCESSIBILITY_LIVE_REGION_NONE; 2759 2760 /** 2761 * Mask for obtaining the bits which specify a view's accessibility live 2762 * region mode. 2763 */ 2764 static final int PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK = (ACCESSIBILITY_LIVE_REGION_NONE 2765 | ACCESSIBILITY_LIVE_REGION_POLITE | ACCESSIBILITY_LIVE_REGION_ASSERTIVE) 2766 << PFLAG2_ACCESSIBILITY_LIVE_REGION_SHIFT; 2767 2768 /** 2769 * Flag indicating whether a view has accessibility focus. 2770 */ 2771 static final int PFLAG2_ACCESSIBILITY_FOCUSED = 0x04000000; 2772 2773 /** 2774 * Flag whether the accessibility state of the subtree rooted at this view changed. 2775 */ 2776 static final int PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED = 0x08000000; 2777 2778 /** 2779 * Flag indicating whether a view failed the quickReject() check in draw(). This condition 2780 * is used to check whether later changes to the view's transform should invalidate the 2781 * view to force the quickReject test to run again. 2782 */ 2783 static final int PFLAG2_VIEW_QUICK_REJECTED = 0x10000000; 2784 2785 /** 2786 * Flag indicating that start/end padding has been resolved into left/right padding 2787 * for use in measurement, layout, drawing, etc. This is set by {@link #resolvePadding()} 2788 * and checked by {@link #measure(int, int)} to determine if padding needs to be resolved 2789 * during measurement. In some special cases this is required such as when an adapter-based 2790 * view measures prospective children without attaching them to a window. 2791 */ 2792 static final int PFLAG2_PADDING_RESOLVED = 0x20000000; 2793 2794 /** 2795 * Flag indicating that the start/end drawables has been resolved into left/right ones. 2796 */ 2797 static final int PFLAG2_DRAWABLE_RESOLVED = 0x40000000; 2798 2799 /** 2800 * Indicates that the view is tracking some sort of transient state 2801 * that the app should not need to be aware of, but that the framework 2802 * should take special care to preserve. 2803 */ 2804 static final int PFLAG2_HAS_TRANSIENT_STATE = 0x80000000; 2805 2806 /** 2807 * Group of bits indicating that RTL properties resolution is done. 2808 */ 2809 static final int ALL_RTL_PROPERTIES_RESOLVED = PFLAG2_LAYOUT_DIRECTION_RESOLVED | 2810 PFLAG2_TEXT_DIRECTION_RESOLVED | 2811 PFLAG2_TEXT_ALIGNMENT_RESOLVED | 2812 PFLAG2_PADDING_RESOLVED | 2813 PFLAG2_DRAWABLE_RESOLVED; 2814 2815 // There are a couple of flags left in mPrivateFlags2 2816 2817 /* End of masks for mPrivateFlags2 */ 2818 2819 /** 2820 * Masks for mPrivateFlags3, as generated by dumpFlags(): 2821 * 2822 * |-------|-------|-------|-------| 2823 * 1 PFLAG3_VIEW_IS_ANIMATING_TRANSFORM 2824 * 1 PFLAG3_VIEW_IS_ANIMATING_ALPHA 2825 * 1 PFLAG3_IS_LAID_OUT 2826 * 1 PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT 2827 * 1 PFLAG3_CALLED_SUPER 2828 * 1 PFLAG3_APPLYING_INSETS 2829 * 1 PFLAG3_FITTING_SYSTEM_WINDOWS 2830 * 1 PFLAG3_NESTED_SCROLLING_ENABLED 2831 * 1 PFLAG3_SCROLL_INDICATOR_TOP 2832 * 1 PFLAG3_SCROLL_INDICATOR_BOTTOM 2833 * 1 PFLAG3_SCROLL_INDICATOR_LEFT 2834 * 1 PFLAG3_SCROLL_INDICATOR_RIGHT 2835 * 1 PFLAG3_SCROLL_INDICATOR_START 2836 * 1 PFLAG3_SCROLL_INDICATOR_END 2837 * 1 PFLAG3_ASSIST_BLOCKED 2838 * 1 PFLAG3_CLUSTER 2839 * 1 PFLAG3_IS_AUTOFILLED 2840 * 1 PFLAG3_FINGER_DOWN 2841 * 1 PFLAG3_FOCUSED_BY_DEFAULT 2842 * 1111 PFLAG3_IMPORTANT_FOR_AUTOFILL 2843 * 1 PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE 2844 * 1 PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED 2845 * 1 PFLAG3_TEMPORARY_DETACH 2846 * 1 PFLAG3_NO_REVEAL_ON_FOCUS 2847 * 1 PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT 2848 * |-------|-------|-------|-------| 2849 */ 2850 2851 /** 2852 * Flag indicating that view has a transform animation set on it. This is used to track whether 2853 * an animation is cleared between successive frames, in order to tell the associated 2854 * DisplayList to clear its animation matrix. 2855 */ 2856 static final int PFLAG3_VIEW_IS_ANIMATING_TRANSFORM = 0x1; 2857 2858 /** 2859 * Flag indicating that view has an alpha animation set on it. This is used to track whether an 2860 * animation is cleared between successive frames, in order to tell the associated 2861 * DisplayList to restore its alpha value. 2862 */ 2863 static final int PFLAG3_VIEW_IS_ANIMATING_ALPHA = 0x2; 2864 2865 /** 2866 * Flag indicating that the view has been through at least one layout since it 2867 * was last attached to a window. 2868 */ 2869 static final int PFLAG3_IS_LAID_OUT = 0x4; 2870 2871 /** 2872 * Flag indicating that a call to measure() was skipped and should be done 2873 * instead when layout() is invoked. 2874 */ 2875 static final int PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT = 0x8; 2876 2877 /** 2878 * Flag indicating that an overridden method correctly called down to 2879 * the superclass implementation as required by the API spec. 2880 */ 2881 static final int PFLAG3_CALLED_SUPER = 0x10; 2882 2883 /** 2884 * Flag indicating that we're in the process of applying window insets. 2885 */ 2886 static final int PFLAG3_APPLYING_INSETS = 0x20; 2887 2888 /** 2889 * Flag indicating that we're in the process of fitting system windows using the old method. 2890 */ 2891 static final int PFLAG3_FITTING_SYSTEM_WINDOWS = 0x40; 2892 2893 /** 2894 * Flag indicating that nested scrolling is enabled for this view. 2895 * The view will optionally cooperate with views up its parent chain to allow for 2896 * integrated nested scrolling along the same axis. 2897 */ 2898 static final int PFLAG3_NESTED_SCROLLING_ENABLED = 0x80; 2899 2900 /** 2901 * Flag indicating that the bottom scroll indicator should be displayed 2902 * when this view can scroll up. 2903 */ 2904 static final int PFLAG3_SCROLL_INDICATOR_TOP = 0x0100; 2905 2906 /** 2907 * Flag indicating that the bottom scroll indicator should be displayed 2908 * when this view can scroll down. 2909 */ 2910 static final int PFLAG3_SCROLL_INDICATOR_BOTTOM = 0x0200; 2911 2912 /** 2913 * Flag indicating that the left scroll indicator should be displayed 2914 * when this view can scroll left. 2915 */ 2916 static final int PFLAG3_SCROLL_INDICATOR_LEFT = 0x0400; 2917 2918 /** 2919 * Flag indicating that the right scroll indicator should be displayed 2920 * when this view can scroll right. 2921 */ 2922 static final int PFLAG3_SCROLL_INDICATOR_RIGHT = 0x0800; 2923 2924 /** 2925 * Flag indicating that the start scroll indicator should be displayed 2926 * when this view can scroll in the start direction. 2927 */ 2928 static final int PFLAG3_SCROLL_INDICATOR_START = 0x1000; 2929 2930 /** 2931 * Flag indicating that the end scroll indicator should be displayed 2932 * when this view can scroll in the end direction. 2933 */ 2934 static final int PFLAG3_SCROLL_INDICATOR_END = 0x2000; 2935 2936 static final int DRAG_MASK = PFLAG2_DRAG_CAN_ACCEPT | PFLAG2_DRAG_HOVERED; 2937 2938 static final int SCROLL_INDICATORS_NONE = 0x0000; 2939 2940 /** 2941 * Mask for use with setFlags indicating bits used for indicating which 2942 * scroll indicators are enabled. 2943 */ 2944 static final int SCROLL_INDICATORS_PFLAG3_MASK = PFLAG3_SCROLL_INDICATOR_TOP 2945 | PFLAG3_SCROLL_INDICATOR_BOTTOM | PFLAG3_SCROLL_INDICATOR_LEFT 2946 | PFLAG3_SCROLL_INDICATOR_RIGHT | PFLAG3_SCROLL_INDICATOR_START 2947 | PFLAG3_SCROLL_INDICATOR_END; 2948 2949 /** 2950 * Left-shift required to translate between public scroll indicator flags 2951 * and internal PFLAGS3 flags. When used as a right-shift, translates 2952 * PFLAGS3 flags to public flags. 2953 */ 2954 static final int SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT = 8; 2955 2956 /** @hide */ 2957 @Retention(RetentionPolicy.SOURCE) 2958 @IntDef(flag = true, 2959 value = { 2960 SCROLL_INDICATOR_TOP, 2961 SCROLL_INDICATOR_BOTTOM, 2962 SCROLL_INDICATOR_LEFT, 2963 SCROLL_INDICATOR_RIGHT, 2964 SCROLL_INDICATOR_START, 2965 SCROLL_INDICATOR_END, 2966 }) 2967 public @interface ScrollIndicators {} 2968 2969 /** 2970 * Scroll indicator direction for the top edge of the view. 2971 * 2972 * @see #setScrollIndicators(int) 2973 * @see #setScrollIndicators(int, int) 2974 * @see #getScrollIndicators() 2975 */ 2976 public static final int SCROLL_INDICATOR_TOP = 2977 PFLAG3_SCROLL_INDICATOR_TOP >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 2978 2979 /** 2980 * Scroll indicator direction for the bottom edge of the view. 2981 * 2982 * @see #setScrollIndicators(int) 2983 * @see #setScrollIndicators(int, int) 2984 * @see #getScrollIndicators() 2985 */ 2986 public static final int SCROLL_INDICATOR_BOTTOM = 2987 PFLAG3_SCROLL_INDICATOR_BOTTOM >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 2988 2989 /** 2990 * Scroll indicator direction for the left edge of the view. 2991 * 2992 * @see #setScrollIndicators(int) 2993 * @see #setScrollIndicators(int, int) 2994 * @see #getScrollIndicators() 2995 */ 2996 public static final int SCROLL_INDICATOR_LEFT = 2997 PFLAG3_SCROLL_INDICATOR_LEFT >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 2998 2999 /** 3000 * Scroll indicator direction for the right edge of the view. 3001 * 3002 * @see #setScrollIndicators(int) 3003 * @see #setScrollIndicators(int, int) 3004 * @see #getScrollIndicators() 3005 */ 3006 public static final int SCROLL_INDICATOR_RIGHT = 3007 PFLAG3_SCROLL_INDICATOR_RIGHT >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 3008 3009 /** 3010 * Scroll indicator direction for the starting edge of the view. 3011 * <p> 3012 * Resolved according to the view's layout direction, see 3013 * {@link #getLayoutDirection()} for more information. 3014 * 3015 * @see #setScrollIndicators(int) 3016 * @see #setScrollIndicators(int, int) 3017 * @see #getScrollIndicators() 3018 */ 3019 public static final int SCROLL_INDICATOR_START = 3020 PFLAG3_SCROLL_INDICATOR_START >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 3021 3022 /** 3023 * Scroll indicator direction for the ending edge of the view. 3024 * <p> 3025 * Resolved according to the view's layout direction, see 3026 * {@link #getLayoutDirection()} for more information. 3027 * 3028 * @see #setScrollIndicators(int) 3029 * @see #setScrollIndicators(int, int) 3030 * @see #getScrollIndicators() 3031 */ 3032 public static final int SCROLL_INDICATOR_END = 3033 PFLAG3_SCROLL_INDICATOR_END >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 3034 3035 /** 3036 * <p>Indicates that we are allowing {@link ViewStructure} to traverse 3037 * into this view.<p> 3038 */ 3039 static final int PFLAG3_ASSIST_BLOCKED = 0x4000; 3040 3041 /** 3042 * Flag indicating that the view is a root of a keyboard navigation cluster. 3043 * 3044 * @see #isKeyboardNavigationCluster() 3045 * @see #setKeyboardNavigationCluster(boolean) 3046 */ 3047 private static final int PFLAG3_CLUSTER = 0x8000; 3048 3049 /** 3050 * Flag indicating that the view is autofilled 3051 * 3052 * @see #isAutofilled() 3053 * @see #setAutofilled(boolean) 3054 */ 3055 private static final int PFLAG3_IS_AUTOFILLED = 0x10000; 3056 3057 /** 3058 * Indicates that the user is currently touching the screen. 3059 * Currently used for the tooltip positioning only. 3060 */ 3061 private static final int PFLAG3_FINGER_DOWN = 0x20000; 3062 3063 /** 3064 * Flag indicating that this view is the default-focus view. 3065 * 3066 * @see #isFocusedByDefault() 3067 * @see #setFocusedByDefault(boolean) 3068 */ 3069 private static final int PFLAG3_FOCUSED_BY_DEFAULT = 0x40000; 3070 3071 /** 3072 * Shift for the bits in {@link #mPrivateFlags3} related to the 3073 * "importantForAutofill" attribute. 3074 */ 3075 static final int PFLAG3_IMPORTANT_FOR_AUTOFILL_SHIFT = 19; 3076 3077 /** 3078 * Mask for obtaining the bits which specify how to determine 3079 * whether a view is important for autofill. 3080 */ 3081 static final int PFLAG3_IMPORTANT_FOR_AUTOFILL_MASK = (IMPORTANT_FOR_AUTOFILL_AUTO 3082 | IMPORTANT_FOR_AUTOFILL_YES | IMPORTANT_FOR_AUTOFILL_NO 3083 | IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS 3084 | IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS) 3085 << PFLAG3_IMPORTANT_FOR_AUTOFILL_SHIFT; 3086 3087 /** 3088 * Whether this view has rendered elements that overlap (see {@link 3089 * #hasOverlappingRendering()}, {@link #forceHasOverlappingRendering(boolean)}, and 3090 * {@link #getHasOverlappingRendering()} ). The value in this bit is only valid when 3091 * PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED has been set. Otherwise, the value is 3092 * determined by whatever {@link #hasOverlappingRendering()} returns. 3093 */ 3094 private static final int PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE = 0x800000; 3095 3096 /** 3097 * Whether {@link #forceHasOverlappingRendering(boolean)} has been called. When true, value 3098 * in PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE is valid. 3099 */ 3100 private static final int PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED = 0x1000000; 3101 3102 /** 3103 * Flag indicating that the view is temporarily detached from the parent view. 3104 * 3105 * @see #onStartTemporaryDetach() 3106 * @see #onFinishTemporaryDetach() 3107 */ 3108 static final int PFLAG3_TEMPORARY_DETACH = 0x2000000; 3109 3110 /** 3111 * Flag indicating that the view does not wish to be revealed within its parent 3112 * hierarchy when it gains focus. Expressed in the negative since the historical 3113 * default behavior is to reveal on focus; this flag suppresses that behavior. 3114 * 3115 * @see #setRevealOnFocusHint(boolean) 3116 * @see #getRevealOnFocusHint() 3117 */ 3118 private static final int PFLAG3_NO_REVEAL_ON_FOCUS = 0x4000000; 3119 3120 /** 3121 * Flag indicating that when layout is completed we should notify 3122 * that the view was entered for autofill purposes. To minimize 3123 * showing autofill for views not visible to the user we evaluate 3124 * user visibility which cannot be done until the view is laid out. 3125 */ 3126 static final int PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT = 0x8000000; 3127 3128 /* End of masks for mPrivateFlags3 */ 3129 3130 /** 3131 * Always allow a user to over-scroll this view, provided it is a 3132 * view that can scroll. 3133 * 3134 * @see #getOverScrollMode() 3135 * @see #setOverScrollMode(int) 3136 */ 3137 public static final int OVER_SCROLL_ALWAYS = 0; 3138 3139 /** 3140 * Allow a user to over-scroll this view only if the content is large 3141 * enough to meaningfully scroll, provided it is a view that can scroll. 3142 * 3143 * @see #getOverScrollMode() 3144 * @see #setOverScrollMode(int) 3145 */ 3146 public static final int OVER_SCROLL_IF_CONTENT_SCROLLS = 1; 3147 3148 /** 3149 * Never allow a user to over-scroll this view. 3150 * 3151 * @see #getOverScrollMode() 3152 * @see #setOverScrollMode(int) 3153 */ 3154 public static final int OVER_SCROLL_NEVER = 2; 3155 3156 /** 3157 * Special constant for {@link #setSystemUiVisibility(int)}: View has 3158 * requested the system UI (status bar) to be visible (the default). 3159 * 3160 * @see #setSystemUiVisibility(int) 3161 */ 3162 public static final int SYSTEM_UI_FLAG_VISIBLE = 0; 3163 3164 /** 3165 * Flag for {@link #setSystemUiVisibility(int)}: View has requested the 3166 * system UI to enter an unobtrusive "low profile" mode. 3167 * 3168 * <p>This is for use in games, book readers, video players, or any other 3169 * "immersive" application where the usual system chrome is deemed too distracting. 3170 * 3171 * <p>In low profile mode, the status bar and/or navigation icons may dim. 3172 * 3173 * @see #setSystemUiVisibility(int) 3174 */ 3175 public static final int SYSTEM_UI_FLAG_LOW_PROFILE = 0x00000001; 3176 3177 /** 3178 * Flag for {@link #setSystemUiVisibility(int)}: View has requested that the 3179 * system navigation be temporarily hidden. 3180 * 3181 * <p>This is an even less obtrusive state than that called for by 3182 * {@link #SYSTEM_UI_FLAG_LOW_PROFILE}; on devices that draw essential navigation controls 3183 * (Home, Back, and the like) on screen, <code>SYSTEM_UI_FLAG_HIDE_NAVIGATION</code> will cause 3184 * those to disappear. This is useful (in conjunction with the 3185 * {@link android.view.WindowManager.LayoutParams#FLAG_FULLSCREEN FLAG_FULLSCREEN} and 3186 * {@link android.view.WindowManager.LayoutParams#FLAG_LAYOUT_IN_SCREEN FLAG_LAYOUT_IN_SCREEN} 3187 * window flags) for displaying content using every last pixel on the display. 3188 * 3189 * <p>There is a limitation: because navigation controls are so important, the least user 3190 * interaction will cause them to reappear immediately. When this happens, both 3191 * this flag and {@link #SYSTEM_UI_FLAG_FULLSCREEN} will be cleared automatically, 3192 * so that both elements reappear at the same time. 3193 * 3194 * @see #setSystemUiVisibility(int) 3195 */ 3196 public static final int SYSTEM_UI_FLAG_HIDE_NAVIGATION = 0x00000002; 3197 3198 /** 3199 * Flag for {@link #setSystemUiVisibility(int)}: View has requested to go 3200 * into the normal fullscreen mode so that its content can take over the screen 3201 * while still allowing the user to interact with the application. 3202 * 3203 * <p>This has the same visual effect as 3204 * {@link android.view.WindowManager.LayoutParams#FLAG_FULLSCREEN 3205 * WindowManager.LayoutParams.FLAG_FULLSCREEN}, 3206 * meaning that non-critical screen decorations (such as the status bar) will be 3207 * hidden while the user is in the View's window, focusing the experience on 3208 * that content. Unlike the window flag, if you are using ActionBar in 3209 * overlay mode with {@link Window#FEATURE_ACTION_BAR_OVERLAY 3210 * Window.FEATURE_ACTION_BAR_OVERLAY}, then enabling this flag will also 3211 * hide the action bar. 3212 * 3213 * <p>This approach to going fullscreen is best used over the window flag when 3214 * it is a transient state -- that is, the application does this at certain 3215 * points in its user interaction where it wants to allow the user to focus 3216 * on content, but not as a continuous state. For situations where the application 3217 * would like to simply stay full screen the entire time (such as a game that 3218 * wants to take over the screen), the 3219 * {@link android.view.WindowManager.LayoutParams#FLAG_FULLSCREEN window flag} 3220 * is usually a better approach. The state set here will be removed by the system 3221 * in various situations (such as the user moving to another application) like 3222 * the other system UI states. 3223 * 3224 * <p>When using this flag, the application should provide some easy facility 3225 * for the user to go out of it. A common example would be in an e-book 3226 * reader, where tapping on the screen brings back whatever screen and UI 3227 * decorations that had been hidden while the user was immersed in reading 3228 * the book. 3229 * 3230 * @see #setSystemUiVisibility(int) 3231 */ 3232 public static final int SYSTEM_UI_FLAG_FULLSCREEN = 0x00000004; 3233 3234 /** 3235 * Flag for {@link #setSystemUiVisibility(int)}: When using other layout 3236 * flags, we would like a stable view of the content insets given to 3237 * {@link #fitSystemWindows(Rect)}. This means that the insets seen there 3238 * will always represent the worst case that the application can expect 3239 * as a continuous state. In the stock Android UI this is the space for 3240 * the system bar, nav bar, and status bar, but not more transient elements 3241 * such as an input method. 3242 * 3243 * The stable layout your UI sees is based on the system UI modes you can 3244 * switch to. That is, if you specify {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN} 3245 * then you will get a stable layout for changes of the 3246 * {@link #SYSTEM_UI_FLAG_FULLSCREEN} mode; if you specify 3247 * {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN} and 3248 * {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION}, then you can transition 3249 * to {@link #SYSTEM_UI_FLAG_FULLSCREEN} and {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION} 3250 * with a stable layout. (Note that you should avoid using 3251 * {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION} by itself.) 3252 * 3253 * If you have set the window flag {@link WindowManager.LayoutParams#FLAG_FULLSCREEN} 3254 * to hide the status bar (instead of using {@link #SYSTEM_UI_FLAG_FULLSCREEN}), 3255 * then a hidden status bar will be considered a "stable" state for purposes 3256 * here. This allows your UI to continually hide the status bar, while still 3257 * using the system UI flags to hide the action bar while still retaining 3258 * a stable layout. Note that changing the window fullscreen flag will never 3259 * provide a stable layout for a clean transition. 3260 * 3261 * <p>If you are using ActionBar in 3262 * overlay mode with {@link Window#FEATURE_ACTION_BAR_OVERLAY 3263 * Window.FEATURE_ACTION_BAR_OVERLAY}, this flag will also impact the 3264 * insets it adds to those given to the application. 3265 */ 3266 public static final int SYSTEM_UI_FLAG_LAYOUT_STABLE = 0x00000100; 3267 3268 /** 3269 * Flag for {@link #setSystemUiVisibility(int)}: View would like its window 3270 * to be laid out as if it has requested 3271 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, even if it currently hasn't. This 3272 * allows it to avoid artifacts when switching in and out of that mode, at 3273 * the expense that some of its user interface may be covered by screen 3274 * decorations when they are shown. You can perform layout of your inner 3275 * UI elements to account for the navigation system UI through the 3276 * {@link #fitSystemWindows(Rect)} method. 3277 */ 3278 public static final int SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION = 0x00000200; 3279 3280 /** 3281 * Flag for {@link #setSystemUiVisibility(int)}: View would like its window 3282 * to be laid out as if it has requested 3283 * {@link #SYSTEM_UI_FLAG_FULLSCREEN}, even if it currently hasn't. This 3284 * allows it to avoid artifacts when switching in and out of that mode, at 3285 * the expense that some of its user interface may be covered by screen 3286 * decorations when they are shown. You can perform layout of your inner 3287 * UI elements to account for non-fullscreen system UI through the 3288 * {@link #fitSystemWindows(Rect)} method. 3289 */ 3290 public static final int SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN = 0x00000400; 3291 3292 /** 3293 * Flag for {@link #setSystemUiVisibility(int)}: View would like to remain interactive when 3294 * hiding the navigation bar with {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}. If this flag is 3295 * not set, {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION} will be force cleared by the system on any 3296 * user interaction. 3297 * <p>Since this flag is a modifier for {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, it only 3298 * has an effect when used in combination with that flag.</p> 3299 */ 3300 public static final int SYSTEM_UI_FLAG_IMMERSIVE = 0x00000800; 3301 3302 /** 3303 * Flag for {@link #setSystemUiVisibility(int)}: View would like to remain interactive when 3304 * hiding the status bar with {@link #SYSTEM_UI_FLAG_FULLSCREEN} and/or hiding the navigation 3305 * bar with {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}. Use this flag to create an immersive 3306 * experience while also hiding the system bars. If this flag is not set, 3307 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION} will be force cleared by the system on any user 3308 * interaction, and {@link #SYSTEM_UI_FLAG_FULLSCREEN} will be force-cleared by the system 3309 * if the user swipes from the top of the screen. 3310 * <p>When system bars are hidden in immersive mode, they can be revealed temporarily with 3311 * system gestures, such as swiping from the top of the screen. These transient system bars 3312 * will overlay app’s content, may have some degree of transparency, and will automatically 3313 * hide after a short timeout. 3314 * </p><p>Since this flag is a modifier for {@link #SYSTEM_UI_FLAG_FULLSCREEN} and 3315 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, it only has an effect when used in combination 3316 * with one or both of those flags.</p> 3317 */ 3318 public static final int SYSTEM_UI_FLAG_IMMERSIVE_STICKY = 0x00001000; 3319 3320 /** 3321 * Flag for {@link #setSystemUiVisibility(int)}: Requests the status bar to draw in a mode that 3322 * is compatible with light status bar backgrounds. 3323 * 3324 * <p>For this to take effect, the window must request 3325 * {@link android.view.WindowManager.LayoutParams#FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS 3326 * FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS} but not 3327 * {@link android.view.WindowManager.LayoutParams#FLAG_TRANSLUCENT_STATUS 3328 * FLAG_TRANSLUCENT_STATUS}. 3329 * 3330 * @see android.R.attr#windowLightStatusBar 3331 */ 3332 public static final int SYSTEM_UI_FLAG_LIGHT_STATUS_BAR = 0x00002000; 3333 3334 /** 3335 * This flag was previously used for a private API. DO NOT reuse it for a public API as it might 3336 * trigger undefined behavior on older platforms with apps compiled against a new SDK. 3337 */ 3338 private static final int SYSTEM_UI_RESERVED_LEGACY1 = 0x00004000; 3339 3340 /** 3341 * This flag was previously used for a private API. DO NOT reuse it for a public API as it might 3342 * trigger undefined behavior on older platforms with apps compiled against a new SDK. 3343 */ 3344 private static final int SYSTEM_UI_RESERVED_LEGACY2 = 0x00010000; 3345 3346 /** 3347 * Flag for {@link #setSystemUiVisibility(int)}: Requests the navigation bar to draw in a mode 3348 * that is compatible with light navigation bar backgrounds. 3349 * 3350 * <p>For this to take effect, the window must request 3351 * {@link android.view.WindowManager.LayoutParams#FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS 3352 * FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS} but not 3353 * {@link android.view.WindowManager.LayoutParams#FLAG_TRANSLUCENT_NAVIGATION 3354 * FLAG_TRANSLUCENT_NAVIGATION}. 3355 */ 3356 public static final int SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR = 0x00000010; 3357 3358 /** 3359 * @deprecated Use {@link #SYSTEM_UI_FLAG_LOW_PROFILE} instead. 3360 */ 3361 @Deprecated 3362 public static final int STATUS_BAR_HIDDEN = SYSTEM_UI_FLAG_LOW_PROFILE; 3363 3364 /** 3365 * @deprecated Use {@link #SYSTEM_UI_FLAG_VISIBLE} instead. 3366 */ 3367 @Deprecated 3368 public static final int STATUS_BAR_VISIBLE = SYSTEM_UI_FLAG_VISIBLE; 3369 3370 /** 3371 * @hide 3372 * 3373 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3374 * out of the public fields to keep the undefined bits out of the developer's way. 3375 * 3376 * Flag to make the status bar not expandable. Unless you also 3377 * set {@link #STATUS_BAR_DISABLE_NOTIFICATION_ICONS}, new notifications will continue to show. 3378 */ 3379 public static final int STATUS_BAR_DISABLE_EXPAND = 0x00010000; 3380 3381 /** 3382 * @hide 3383 * 3384 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3385 * out of the public fields to keep the undefined bits out of the developer's way. 3386 * 3387 * Flag to hide notification icons and scrolling ticker text. 3388 */ 3389 public static final int STATUS_BAR_DISABLE_NOTIFICATION_ICONS = 0x00020000; 3390 3391 /** 3392 * @hide 3393 * 3394 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3395 * out of the public fields to keep the undefined bits out of the developer's way. 3396 * 3397 * Flag to disable incoming notification alerts. This will not block 3398 * icons, but it will block sound, vibrating and other visual or aural notifications. 3399 */ 3400 public static final int STATUS_BAR_DISABLE_NOTIFICATION_ALERTS = 0x00040000; 3401 3402 /** 3403 * @hide 3404 * 3405 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3406 * out of the public fields to keep the undefined bits out of the developer's way. 3407 * 3408 * Flag to hide only the scrolling ticker. Note that 3409 * {@link #STATUS_BAR_DISABLE_NOTIFICATION_ICONS} implies 3410 * {@link #STATUS_BAR_DISABLE_NOTIFICATION_TICKER}. 3411 */ 3412 public static final int STATUS_BAR_DISABLE_NOTIFICATION_TICKER = 0x00080000; 3413 3414 /** 3415 * @hide 3416 * 3417 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3418 * out of the public fields to keep the undefined bits out of the developer's way. 3419 * 3420 * Flag to hide the center system info area. 3421 */ 3422 public static final int STATUS_BAR_DISABLE_SYSTEM_INFO = 0x00100000; 3423 3424 /** 3425 * @hide 3426 * 3427 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3428 * out of the public fields to keep the undefined bits out of the developer's way. 3429 * 3430 * Flag to hide only the home button. Don't use this 3431 * unless you're a special part of the system UI (i.e., setup wizard, keyguard). 3432 */ 3433 public static final int STATUS_BAR_DISABLE_HOME = 0x00200000; 3434 3435 /** 3436 * @hide 3437 * 3438 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3439 * out of the public fields to keep the undefined bits out of the developer's way. 3440 * 3441 * Flag to hide only the back button. Don't use this 3442 * unless you're a special part of the system UI (i.e., setup wizard, keyguard). 3443 */ 3444 public static final int STATUS_BAR_DISABLE_BACK = 0x00400000; 3445 3446 /** 3447 * @hide 3448 * 3449 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3450 * out of the public fields to keep the undefined bits out of the developer's way. 3451 * 3452 * Flag to hide only the clock. You might use this if your activity has 3453 * its own clock making the status bar's clock redundant. 3454 */ 3455 public static final int STATUS_BAR_DISABLE_CLOCK = 0x00800000; 3456 3457 /** 3458 * @hide 3459 * 3460 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3461 * out of the public fields to keep the undefined bits out of the developer's way. 3462 * 3463 * Flag to hide only the recent apps button. Don't use this 3464 * unless you're a special part of the system UI (i.e., setup wizard, keyguard). 3465 */ 3466 public static final int STATUS_BAR_DISABLE_RECENT = 0x01000000; 3467 3468 /** 3469 * @hide 3470 * 3471 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3472 * out of the public fields to keep the undefined bits out of the developer's way. 3473 * 3474 * Flag to disable the global search gesture. Don't use this 3475 * unless you're a special part of the system UI (i.e., setup wizard, keyguard). 3476 */ 3477 public static final int STATUS_BAR_DISABLE_SEARCH = 0x02000000; 3478 3479 /** 3480 * @hide 3481 * 3482 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3483 * out of the public fields to keep the undefined bits out of the developer's way. 3484 * 3485 * Flag to specify that the status bar is displayed in transient mode. 3486 */ 3487 public static final int STATUS_BAR_TRANSIENT = 0x04000000; 3488 3489 /** 3490 * @hide 3491 * 3492 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3493 * out of the public fields to keep the undefined bits out of the developer's way. 3494 * 3495 * Flag to specify that the navigation bar is displayed in transient mode. 3496 */ 3497 public static final int NAVIGATION_BAR_TRANSIENT = 0x08000000; 3498 3499 /** 3500 * @hide 3501 * 3502 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3503 * out of the public fields to keep the undefined bits out of the developer's way. 3504 * 3505 * Flag to specify that the hidden status bar would like to be shown. 3506 */ 3507 public static final int STATUS_BAR_UNHIDE = 0x10000000; 3508 3509 /** 3510 * @hide 3511 * 3512 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3513 * out of the public fields to keep the undefined bits out of the developer's way. 3514 * 3515 * Flag to specify that the hidden navigation bar would like to be shown. 3516 */ 3517 public static final int NAVIGATION_BAR_UNHIDE = 0x20000000; 3518 3519 /** 3520 * @hide 3521 * 3522 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3523 * out of the public fields to keep the undefined bits out of the developer's way. 3524 * 3525 * Flag to specify that the status bar is displayed in translucent mode. 3526 */ 3527 public static final int STATUS_BAR_TRANSLUCENT = 0x40000000; 3528 3529 /** 3530 * @hide 3531 * 3532 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3533 * out of the public fields to keep the undefined bits out of the developer's way. 3534 * 3535 * Flag to specify that the navigation bar is displayed in translucent mode. 3536 */ 3537 public static final int NAVIGATION_BAR_TRANSLUCENT = 0x80000000; 3538 3539 /** 3540 * @hide 3541 * 3542 * Makes navigation bar transparent (but not the status bar). 3543 */ 3544 public static final int NAVIGATION_BAR_TRANSPARENT = 0x00008000; 3545 3546 /** 3547 * @hide 3548 * 3549 * Makes status bar transparent (but not the navigation bar). 3550 */ 3551 public static final int STATUS_BAR_TRANSPARENT = 0x00000008; 3552 3553 /** 3554 * @hide 3555 * 3556 * Makes both status bar and navigation bar transparent. 3557 */ 3558 public static final int SYSTEM_UI_TRANSPARENT = NAVIGATION_BAR_TRANSPARENT 3559 | STATUS_BAR_TRANSPARENT; 3560 3561 /** 3562 * @hide 3563 */ 3564 public static final int PUBLIC_STATUS_BAR_VISIBILITY_MASK = 0x00003FF7; 3565 3566 /** 3567 * These are the system UI flags that can be cleared by events outside 3568 * of an application. Currently this is just the ability to tap on the 3569 * screen while hiding the navigation bar to have it return. 3570 * @hide 3571 */ 3572 public static final int SYSTEM_UI_CLEARABLE_FLAGS = 3573 SYSTEM_UI_FLAG_LOW_PROFILE | SYSTEM_UI_FLAG_HIDE_NAVIGATION 3574 | SYSTEM_UI_FLAG_FULLSCREEN; 3575 3576 /** 3577 * Flags that can impact the layout in relation to system UI. 3578 */ 3579 public static final int SYSTEM_UI_LAYOUT_FLAGS = 3580 SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION 3581 | SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN; 3582 3583 /** @hide */ 3584 @IntDef(flag = true, 3585 value = { FIND_VIEWS_WITH_TEXT, FIND_VIEWS_WITH_CONTENT_DESCRIPTION }) 3586 @Retention(RetentionPolicy.SOURCE) 3587 public @interface FindViewFlags {} 3588 3589 /** 3590 * Find views that render the specified text. 3591 * 3592 * @see #findViewsWithText(ArrayList, CharSequence, int) 3593 */ 3594 public static final int FIND_VIEWS_WITH_TEXT = 0x00000001; 3595 3596 /** 3597 * Find find views that contain the specified content description. 3598 * 3599 * @see #findViewsWithText(ArrayList, CharSequence, int) 3600 */ 3601 public static final int FIND_VIEWS_WITH_CONTENT_DESCRIPTION = 0x00000002; 3602 3603 /** 3604 * Find views that contain {@link AccessibilityNodeProvider}. Such 3605 * a View is a root of virtual view hierarchy and may contain the searched 3606 * text. If this flag is set Views with providers are automatically 3607 * added and it is a responsibility of the client to call the APIs of 3608 * the provider to determine whether the virtual tree rooted at this View 3609 * contains the text, i.e. getting the list of {@link AccessibilityNodeInfo}s 3610 * representing the virtual views with this text. 3611 * 3612 * @see #findViewsWithText(ArrayList, CharSequence, int) 3613 * 3614 * @hide 3615 */ 3616 public static final int FIND_VIEWS_WITH_ACCESSIBILITY_NODE_PROVIDERS = 0x00000004; 3617 3618 /** 3619 * The undefined cursor position. 3620 * 3621 * @hide 3622 */ 3623 public static final int ACCESSIBILITY_CURSOR_POSITION_UNDEFINED = -1; 3624 3625 /** 3626 * Indicates that the screen has changed state and is now off. 3627 * 3628 * @see #onScreenStateChanged(int) 3629 */ 3630 public static final int SCREEN_STATE_OFF = 0x0; 3631 3632 /** 3633 * Indicates that the screen has changed state and is now on. 3634 * 3635 * @see #onScreenStateChanged(int) 3636 */ 3637 public static final int SCREEN_STATE_ON = 0x1; 3638 3639 /** 3640 * Indicates no axis of view scrolling. 3641 */ 3642 public static final int SCROLL_AXIS_NONE = 0; 3643 3644 /** 3645 * Indicates scrolling along the horizontal axis. 3646 */ 3647 public static final int SCROLL_AXIS_HORIZONTAL = 1 << 0; 3648 3649 /** 3650 * Indicates scrolling along the vertical axis. 3651 */ 3652 public static final int SCROLL_AXIS_VERTICAL = 1 << 1; 3653 3654 /** 3655 * Controls the over-scroll mode for this view. 3656 * See {@link #overScrollBy(int, int, int, int, int, int, int, int, boolean)}, 3657 * {@link #OVER_SCROLL_ALWAYS}, {@link #OVER_SCROLL_IF_CONTENT_SCROLLS}, 3658 * and {@link #OVER_SCROLL_NEVER}. 3659 */ 3660 private int mOverScrollMode; 3661 3662 /** 3663 * The parent this view is attached to. 3664 * {@hide} 3665 * 3666 * @see #getParent() 3667 */ 3668 protected ViewParent mParent; 3669 3670 /** 3671 * {@hide} 3672 */ 3673 AttachInfo mAttachInfo; 3674 3675 /** 3676 * {@hide} 3677 */ 3678 @ViewDebug.ExportedProperty(flagMapping = { 3679 @ViewDebug.FlagToString(mask = PFLAG_FORCE_LAYOUT, equals = PFLAG_FORCE_LAYOUT, 3680 name = "FORCE_LAYOUT"), 3681 @ViewDebug.FlagToString(mask = PFLAG_LAYOUT_REQUIRED, equals = PFLAG_LAYOUT_REQUIRED, 3682 name = "LAYOUT_REQUIRED"), 3683 @ViewDebug.FlagToString(mask = PFLAG_DRAWING_CACHE_VALID, equals = PFLAG_DRAWING_CACHE_VALID, 3684 name = "DRAWING_CACHE_INVALID", outputIf = false), 3685 @ViewDebug.FlagToString(mask = PFLAG_DRAWN, equals = PFLAG_DRAWN, name = "DRAWN", outputIf = true), 3686 @ViewDebug.FlagToString(mask = PFLAG_DRAWN, equals = PFLAG_DRAWN, name = "NOT_DRAWN", outputIf = false), 3687 @ViewDebug.FlagToString(mask = PFLAG_DIRTY_MASK, equals = PFLAG_DIRTY_OPAQUE, name = "DIRTY_OPAQUE"), 3688 @ViewDebug.FlagToString(mask = PFLAG_DIRTY_MASK, equals = PFLAG_DIRTY, name = "DIRTY") 3689 }, formatToHexString = true) 3690 3691 /* @hide */ 3692 public int mPrivateFlags; 3693 int mPrivateFlags2; 3694 int mPrivateFlags3; 3695 3696 /** 3697 * This view's request for the visibility of the status bar. 3698 * @hide 3699 */ 3700 @ViewDebug.ExportedProperty(flagMapping = { 3701 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_LOW_PROFILE, 3702 equals = SYSTEM_UI_FLAG_LOW_PROFILE, 3703 name = "SYSTEM_UI_FLAG_LOW_PROFILE", outputIf = true), 3704 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_HIDE_NAVIGATION, 3705 equals = SYSTEM_UI_FLAG_HIDE_NAVIGATION, 3706 name = "SYSTEM_UI_FLAG_HIDE_NAVIGATION", outputIf = true), 3707 @ViewDebug.FlagToString(mask = PUBLIC_STATUS_BAR_VISIBILITY_MASK, 3708 equals = SYSTEM_UI_FLAG_VISIBLE, 3709 name = "SYSTEM_UI_FLAG_VISIBLE", outputIf = true) 3710 }, formatToHexString = true) 3711 int mSystemUiVisibility; 3712 3713 /** 3714 * Reference count for transient state. 3715 * @see #setHasTransientState(boolean) 3716 */ 3717 int mTransientStateCount = 0; 3718 3719 /** 3720 * Count of how many windows this view has been attached to. 3721 */ 3722 int mWindowAttachCount; 3723 3724 /** 3725 * The layout parameters associated with this view and used by the parent 3726 * {@link android.view.ViewGroup} to determine how this view should be 3727 * laid out. 3728 * {@hide} 3729 */ 3730 protected ViewGroup.LayoutParams mLayoutParams; 3731 3732 /** 3733 * The view flags hold various views states. 3734 * {@hide} 3735 */ 3736 @ViewDebug.ExportedProperty(formatToHexString = true) 3737 int mViewFlags; 3738 3739 static class TransformationInfo { 3740 /** 3741 * The transform matrix for the View. This transform is calculated internally 3742 * based on the translation, rotation, and scale properties. 3743 * 3744 * Do *not* use this variable directly; instead call getMatrix(), which will 3745 * load the value from the View's RenderNode. 3746 */ 3747 private final Matrix mMatrix = new Matrix(); 3748 3749 /** 3750 * The inverse transform matrix for the View. This transform is calculated 3751 * internally based on the translation, rotation, and scale properties. 3752 * 3753 * Do *not* use this variable directly; instead call getInverseMatrix(), 3754 * which will load the value from the View's RenderNode. 3755 */ 3756 private Matrix mInverseMatrix; 3757 3758 /** 3759 * The opacity of the View. This is a value from 0 to 1, where 0 means 3760 * completely transparent and 1 means completely opaque. 3761 */ 3762 @ViewDebug.ExportedProperty 3763 float mAlpha = 1f; 3764 3765 /** 3766 * The opacity of the view as manipulated by the Fade transition. This is a hidden 3767 * property only used by transitions, which is composited with the other alpha 3768 * values to calculate the final visual alpha value. 3769 */ 3770 float mTransitionAlpha = 1f; 3771 } 3772 3773 /** @hide */ 3774 public TransformationInfo mTransformationInfo; 3775 3776 /** 3777 * Current clip bounds. to which all drawing of this view are constrained. 3778 */ 3779 Rect mClipBounds = null; 3780 3781 private boolean mLastIsOpaque; 3782 3783 /** 3784 * The distance in pixels from the left edge of this view's parent 3785 * to the left edge of this view. 3786 * {@hide} 3787 */ 3788 @ViewDebug.ExportedProperty(category = "layout") 3789 protected int mLeft; 3790 /** 3791 * The distance in pixels from the left edge of this view's parent 3792 * to the right edge of this view. 3793 * {@hide} 3794 */ 3795 @ViewDebug.ExportedProperty(category = "layout") 3796 protected int mRight; 3797 /** 3798 * The distance in pixels from the top edge of this view's parent 3799 * to the top edge of this view. 3800 * {@hide} 3801 */ 3802 @ViewDebug.ExportedProperty(category = "layout") 3803 protected int mTop; 3804 /** 3805 * The distance in pixels from the top edge of this view's parent 3806 * to the bottom edge of this view. 3807 * {@hide} 3808 */ 3809 @ViewDebug.ExportedProperty(category = "layout") 3810 protected int mBottom; 3811 3812 /** 3813 * The offset, in pixels, by which the content of this view is scrolled 3814 * horizontally. 3815 * {@hide} 3816 */ 3817 @ViewDebug.ExportedProperty(category = "scrolling") 3818 protected int mScrollX; 3819 /** 3820 * The offset, in pixels, by which the content of this view is scrolled 3821 * vertically. 3822 * {@hide} 3823 */ 3824 @ViewDebug.ExportedProperty(category = "scrolling") 3825 protected int mScrollY; 3826 3827 /** 3828 * The left padding in pixels, that is the distance in pixels between the 3829 * left edge of this view and the left edge of its content. 3830 * {@hide} 3831 */ 3832 @ViewDebug.ExportedProperty(category = "padding") 3833 protected int mPaddingLeft = 0; 3834 /** 3835 * The right padding in pixels, that is the distance in pixels between the 3836 * right edge of this view and the right edge of its content. 3837 * {@hide} 3838 */ 3839 @ViewDebug.ExportedProperty(category = "padding") 3840 protected int mPaddingRight = 0; 3841 /** 3842 * The top padding in pixels, that is the distance in pixels between the 3843 * top edge of this view and the top edge of its content. 3844 * {@hide} 3845 */ 3846 @ViewDebug.ExportedProperty(category = "padding") 3847 protected int mPaddingTop; 3848 /** 3849 * The bottom padding in pixels, that is the distance in pixels between the 3850 * bottom edge of this view and the bottom edge of its content. 3851 * {@hide} 3852 */ 3853 @ViewDebug.ExportedProperty(category = "padding") 3854 protected int mPaddingBottom; 3855 3856 /** 3857 * The layout insets in pixels, that is the distance in pixels between the 3858 * visible edges of this view its bounds. 3859 */ 3860 private Insets mLayoutInsets; 3861 3862 /** 3863 * Briefly describes the view and is primarily used for accessibility support. 3864 */ 3865 private CharSequence mContentDescription; 3866 3867 /** 3868 * Specifies the id of a view for which this view serves as a label for 3869 * accessibility purposes. 3870 */ 3871 private int mLabelForId = View.NO_ID; 3872 3873 /** 3874 * Predicate for matching labeled view id with its label for 3875 * accessibility purposes. 3876 */ 3877 private MatchLabelForPredicate mMatchLabelForPredicate; 3878 3879 /** 3880 * Specifies a view before which this one is visited in accessibility traversal. 3881 */ 3882 private int mAccessibilityTraversalBeforeId = NO_ID; 3883 3884 /** 3885 * Specifies a view after which this one is visited in accessibility traversal. 3886 */ 3887 private int mAccessibilityTraversalAfterId = NO_ID; 3888 3889 /** 3890 * Predicate for matching a view by its id. 3891 */ 3892 private MatchIdPredicate mMatchIdPredicate; 3893 3894 /** 3895 * Cache the paddingRight set by the user to append to the scrollbar's size. 3896 * 3897 * @hide 3898 */ 3899 @ViewDebug.ExportedProperty(category = "padding") 3900 protected int mUserPaddingRight; 3901 3902 /** 3903 * Cache the paddingBottom set by the user to append to the scrollbar's size. 3904 * 3905 * @hide 3906 */ 3907 @ViewDebug.ExportedProperty(category = "padding") 3908 protected int mUserPaddingBottom; 3909 3910 /** 3911 * Cache the paddingLeft set by the user to append to the scrollbar's size. 3912 * 3913 * @hide 3914 */ 3915 @ViewDebug.ExportedProperty(category = "padding") 3916 protected int mUserPaddingLeft; 3917 3918 /** 3919 * Cache the paddingStart set by the user to append to the scrollbar's size. 3920 * 3921 */ 3922 @ViewDebug.ExportedProperty(category = "padding") 3923 int mUserPaddingStart; 3924 3925 /** 3926 * Cache the paddingEnd set by the user to append to the scrollbar's size. 3927 * 3928 */ 3929 @ViewDebug.ExportedProperty(category = "padding") 3930 int mUserPaddingEnd; 3931 3932 /** 3933 * Cache initial left padding. 3934 * 3935 * @hide 3936 */ 3937 int mUserPaddingLeftInitial; 3938 3939 /** 3940 * Cache initial right padding. 3941 * 3942 * @hide 3943 */ 3944 int mUserPaddingRightInitial; 3945 3946 /** 3947 * Default undefined padding 3948 */ 3949 private static final int UNDEFINED_PADDING = Integer.MIN_VALUE; 3950 3951 /** 3952 * Cache if a left padding has been defined 3953 */ 3954 private boolean mLeftPaddingDefined = false; 3955 3956 /** 3957 * Cache if a right padding has been defined 3958 */ 3959 private boolean mRightPaddingDefined = false; 3960 3961 /** 3962 * @hide 3963 */ 3964 int mOldWidthMeasureSpec = Integer.MIN_VALUE; 3965 /** 3966 * @hide 3967 */ 3968 int mOldHeightMeasureSpec = Integer.MIN_VALUE; 3969 3970 private LongSparseLongArray mMeasureCache; 3971 3972 @ViewDebug.ExportedProperty(deepExport = true, prefix = "bg_") 3973 private Drawable mBackground; 3974 private TintInfo mBackgroundTint; 3975 3976 @ViewDebug.ExportedProperty(deepExport = true, prefix = "fg_") 3977 private ForegroundInfo mForegroundInfo; 3978 3979 private Drawable mScrollIndicatorDrawable; 3980 3981 /** 3982 * RenderNode used for backgrounds. 3983 * <p> 3984 * When non-null and valid, this is expected to contain an up-to-date copy 3985 * of the background drawable. It is cleared on temporary detach, and reset 3986 * on cleanup. 3987 */ 3988 private RenderNode mBackgroundRenderNode; 3989 3990 private int mBackgroundResource; 3991 private boolean mBackgroundSizeChanged; 3992 3993 /** The default focus highlight. 3994 * @see #mDefaultFocusHighlightEnabled 3995 * @see Drawable#hasFocusStateSpecified() 3996 */ 3997 private Drawable mDefaultFocusHighlight; 3998 private Drawable mDefaultFocusHighlightCache; 3999 private boolean mDefaultFocusHighlightSizeChanged; 4000 /** 4001 * True if the default focus highlight is needed on the target device. 4002 */ 4003 private static boolean sUseDefaultFocusHighlight; 4004 4005 private String mTransitionName; 4006 4007 static class TintInfo { 4008 ColorStateList mTintList; 4009 PorterDuff.Mode mTintMode; 4010 boolean mHasTintMode; 4011 boolean mHasTintList; 4012 } 4013 4014 private static class ForegroundInfo { 4015 private Drawable mDrawable; 4016 private TintInfo mTintInfo; 4017 private int mGravity = Gravity.FILL; 4018 private boolean mInsidePadding = true; 4019 private boolean mBoundsChanged = true; 4020 private final Rect mSelfBounds = new Rect(); 4021 private final Rect mOverlayBounds = new Rect(); 4022 } 4023 4024 static class ListenerInfo { 4025 /** 4026 * Listener used to dispatch focus change events. 4027 * This field should be made private, so it is hidden from the SDK. 4028 * {@hide} 4029 */ 4030 protected OnFocusChangeListener mOnFocusChangeListener; 4031 4032 /** 4033 * Listeners for layout change events. 4034 */ 4035 private ArrayList<OnLayoutChangeListener> mOnLayoutChangeListeners; 4036 4037 protected OnScrollChangeListener mOnScrollChangeListener; 4038 4039 /** 4040 * Listeners for attach events. 4041 */ 4042 private CopyOnWriteArrayList<OnAttachStateChangeListener> mOnAttachStateChangeListeners; 4043 4044 /** 4045 * Listener used to dispatch click events. 4046 * This field should be made private, so it is hidden from the SDK. 4047 * {@hide} 4048 */ 4049 public OnClickListener mOnClickListener; 4050 4051 /** 4052 * Listener used to dispatch long click events. 4053 * This field should be made private, so it is hidden from the SDK. 4054 * {@hide} 4055 */ 4056 protected OnLongClickListener mOnLongClickListener; 4057 4058 /** 4059 * Listener used to dispatch context click events. This field should be made private, so it 4060 * is hidden from the SDK. 4061 * {@hide} 4062 */ 4063 protected OnContextClickListener mOnContextClickListener; 4064 4065 /** 4066 * Listener used to build the context menu. 4067 * This field should be made private, so it is hidden from the SDK. 4068 * {@hide} 4069 */ 4070 protected OnCreateContextMenuListener mOnCreateContextMenuListener; 4071 4072 private OnKeyListener mOnKeyListener; 4073 4074 private OnTouchListener mOnTouchListener; 4075 4076 private OnHoverListener mOnHoverListener; 4077 4078 private OnGenericMotionListener mOnGenericMotionListener; 4079 4080 private OnDragListener mOnDragListener; 4081 4082 private OnSystemUiVisibilityChangeListener mOnSystemUiVisibilityChangeListener; 4083 4084 OnApplyWindowInsetsListener mOnApplyWindowInsetsListener; 4085 4086 OnCapturedPointerListener mOnCapturedPointerListener; 4087 } 4088 4089 ListenerInfo mListenerInfo; 4090 4091 private static class TooltipInfo { 4092 /** 4093 * Text to be displayed in a tooltip popup. 4094 */ 4095 @Nullable 4096 CharSequence mTooltipText; 4097 4098 /** 4099 * View-relative position of the tooltip anchor point. 4100 */ 4101 int mAnchorX; 4102 int mAnchorY; 4103 4104 /** 4105 * The tooltip popup. 4106 */ 4107 @Nullable 4108 TooltipPopup mTooltipPopup; 4109 4110 /** 4111 * Set to true if the tooltip was shown as a result of a long click. 4112 */ 4113 boolean mTooltipFromLongClick; 4114 4115 /** 4116 * Keep these Runnables so that they can be used to reschedule. 4117 */ 4118 Runnable mShowTooltipRunnable; 4119 Runnable mHideTooltipRunnable; 4120 } 4121 4122 TooltipInfo mTooltipInfo; 4123 4124 // Temporary values used to hold (x,y) coordinates when delegating from the 4125 // two-arg performLongClick() method to the legacy no-arg version. 4126 private float mLongClickX = Float.NaN; 4127 private float mLongClickY = Float.NaN; 4128 4129 /** 4130 * The application environment this view lives in. 4131 * This field should be made private, so it is hidden from the SDK. 4132 * {@hide} 4133 */ 4134 @ViewDebug.ExportedProperty(deepExport = true) 4135 protected Context mContext; 4136 4137 private final Resources mResources; 4138 4139 private ScrollabilityCache mScrollCache; 4140 4141 private int[] mDrawableState = null; 4142 4143 ViewOutlineProvider mOutlineProvider = ViewOutlineProvider.BACKGROUND; 4144 4145 /** 4146 * Animator that automatically runs based on state changes. 4147 */ 4148 private StateListAnimator mStateListAnimator; 4149 4150 /** 4151 * When this view has focus and the next focus is {@link #FOCUS_LEFT}, 4152 * the user may specify which view to go to next. 4153 */ 4154 private int mNextFocusLeftId = View.NO_ID; 4155 4156 /** 4157 * When this view has focus and the next focus is {@link #FOCUS_RIGHT}, 4158 * the user may specify which view to go to next. 4159 */ 4160 private int mNextFocusRightId = View.NO_ID; 4161 4162 /** 4163 * When this view has focus and the next focus is {@link #FOCUS_UP}, 4164 * the user may specify which view to go to next. 4165 */ 4166 private int mNextFocusUpId = View.NO_ID; 4167 4168 /** 4169 * When this view has focus and the next focus is {@link #FOCUS_DOWN}, 4170 * the user may specify which view to go to next. 4171 */ 4172 private int mNextFocusDownId = View.NO_ID; 4173 4174 /** 4175 * When this view has focus and the next focus is {@link #FOCUS_FORWARD}, 4176 * the user may specify which view to go to next. 4177 */ 4178 int mNextFocusForwardId = View.NO_ID; 4179 4180 /** 4181 * User-specified next keyboard navigation cluster in the {@link #FOCUS_FORWARD} direction. 4182 * 4183 * @see #findUserSetNextKeyboardNavigationCluster(View, int) 4184 */ 4185 int mNextClusterForwardId = View.NO_ID; 4186 4187 /** 4188 * Whether this View should use a default focus highlight when it gets focused but doesn't 4189 * have {@link android.R.attr#state_focused} defined in its background. 4190 */ 4191 boolean mDefaultFocusHighlightEnabled = true; 4192 4193 private CheckForLongPress mPendingCheckForLongPress; 4194 private CheckForTap mPendingCheckForTap = null; 4195 private PerformClick mPerformClick; 4196 private SendViewScrolledAccessibilityEvent mSendViewScrolledAccessibilityEvent; 4197 4198 private UnsetPressedState mUnsetPressedState; 4199 4200 /** 4201 * Whether the long press's action has been invoked. The tap's action is invoked on the 4202 * up event while a long press is invoked as soon as the long press duration is reached, so 4203 * a long press could be performed before the tap is checked, in which case the tap's action 4204 * should not be invoked. 4205 */ 4206 private boolean mHasPerformedLongPress; 4207 4208 /** 4209 * Whether a context click button is currently pressed down. This is true when the stylus is 4210 * touching the screen and the primary button has been pressed, or if a mouse's right button is 4211 * pressed. This is false once the button is released or if the stylus has been lifted. 4212 */ 4213 private boolean mInContextButtonPress; 4214 4215 /** 4216 * Whether the next up event should be ignored for the purposes of gesture recognition. This is 4217 * true after a stylus button press has occured, when the next up event should not be recognized 4218 * as a tap. 4219 */ 4220 private boolean mIgnoreNextUpEvent; 4221 4222 /** 4223 * The minimum height of the view. We'll try our best to have the height 4224 * of this view to at least this amount. 4225 */ 4226 @ViewDebug.ExportedProperty(category = "measurement") 4227 private int mMinHeight; 4228 4229 /** 4230 * The minimum width of the view. We'll try our best to have the width 4231 * of this view to at least this amount. 4232 */ 4233 @ViewDebug.ExportedProperty(category = "measurement") 4234 private int mMinWidth; 4235 4236 /** 4237 * The delegate to handle touch events that are physically in this view 4238 * but should be handled by another view. 4239 */ 4240 private TouchDelegate mTouchDelegate = null; 4241 4242 /** 4243 * Solid color to use as a background when creating the drawing cache. Enables 4244 * the cache to use 16 bit bitmaps instead of 32 bit. 4245 */ 4246 private int mDrawingCacheBackgroundColor = 0; 4247 4248 /** 4249 * Special tree observer used when mAttachInfo is null. 4250 */ 4251 private ViewTreeObserver mFloatingTreeObserver; 4252 4253 /** 4254 * Cache the touch slop from the context that created the view. 4255 */ 4256 private int mTouchSlop; 4257 4258 /** 4259 * Object that handles automatic animation of view properties. 4260 */ 4261 private ViewPropertyAnimator mAnimator = null; 4262 4263 /** 4264 * List of registered FrameMetricsObservers. 4265 */ 4266 private ArrayList<FrameMetricsObserver> mFrameMetricsObservers; 4267 4268 /** 4269 * Flag indicating that a drag can cross window boundaries. When 4270 * {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, int)} is called 4271 * with this flag set, all visible applications with targetSdkVersion >= 4272 * {@link android.os.Build.VERSION_CODES#N API 24} will be able to participate 4273 * in the drag operation and receive the dragged content. 4274 * 4275 * <p>If this is the only flag set, then the drag recipient will only have access to text data 4276 * and intents contained in the {@link ClipData} object. Access to URIs contained in the 4277 * {@link ClipData} is determined by other DRAG_FLAG_GLOBAL_* flags</p> 4278 */ 4279 public static final int DRAG_FLAG_GLOBAL = 1 << 8; // 256 4280 4281 /** 4282 * When this flag is used with {@link #DRAG_FLAG_GLOBAL}, the drag recipient will be able to 4283 * request read access to the content URI(s) contained in the {@link ClipData} object. 4284 * @see android.content.Intent#FLAG_GRANT_READ_URI_PERMISSION 4285 */ 4286 public static final int DRAG_FLAG_GLOBAL_URI_READ = Intent.FLAG_GRANT_READ_URI_PERMISSION; 4287 4288 /** 4289 * When this flag is used with {@link #DRAG_FLAG_GLOBAL}, the drag recipient will be able to 4290 * request write access to the content URI(s) contained in the {@link ClipData} object. 4291 * @see android.content.Intent#FLAG_GRANT_WRITE_URI_PERMISSION 4292 */ 4293 public static final int DRAG_FLAG_GLOBAL_URI_WRITE = Intent.FLAG_GRANT_WRITE_URI_PERMISSION; 4294 4295 /** 4296 * When this flag is used with {@link #DRAG_FLAG_GLOBAL_URI_READ} and/or {@link 4297 * #DRAG_FLAG_GLOBAL_URI_WRITE}, the URI permission grant can be persisted across device 4298 * reboots until explicitly revoked with 4299 * {@link android.content.Context#revokeUriPermission(Uri, int)} Context.revokeUriPermission}. 4300 * @see android.content.Intent#FLAG_GRANT_PERSISTABLE_URI_PERMISSION 4301 */ 4302 public static final int DRAG_FLAG_GLOBAL_PERSISTABLE_URI_PERMISSION = 4303 Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION; 4304 4305 /** 4306 * When this flag is used with {@link #DRAG_FLAG_GLOBAL_URI_READ} and/or {@link 4307 * #DRAG_FLAG_GLOBAL_URI_WRITE}, the URI permission grant applies to any URI that is a prefix 4308 * match against the original granted URI. 4309 * @see android.content.Intent#FLAG_GRANT_PREFIX_URI_PERMISSION 4310 */ 4311 public static final int DRAG_FLAG_GLOBAL_PREFIX_URI_PERMISSION = 4312 Intent.FLAG_GRANT_PREFIX_URI_PERMISSION; 4313 4314 /** 4315 * Flag indicating that the drag shadow will be opaque. When 4316 * {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, int)} is called 4317 * with this flag set, the drag shadow will be opaque, otherwise, it will be semitransparent. 4318 */ 4319 public static final int DRAG_FLAG_OPAQUE = 1 << 9; 4320 4321 /** 4322 * Vertical scroll factor cached by {@link #getVerticalScrollFactor}. 4323 */ 4324 private float mVerticalScrollFactor; 4325 4326 /** 4327 * Position of the vertical scroll bar. 4328 */ 4329 private int mVerticalScrollbarPosition; 4330 4331 /** 4332 * Position the scroll bar at the default position as determined by the system. 4333 */ 4334 public static final int SCROLLBAR_POSITION_DEFAULT = 0; 4335 4336 /** 4337 * Position the scroll bar along the left edge. 4338 */ 4339 public static final int SCROLLBAR_POSITION_LEFT = 1; 4340 4341 /** 4342 * Position the scroll bar along the right edge. 4343 */ 4344 public static final int SCROLLBAR_POSITION_RIGHT = 2; 4345 4346 /** 4347 * Indicates that the view does not have a layer. 4348 * 4349 * @see #getLayerType() 4350 * @see #setLayerType(int, android.graphics.Paint) 4351 * @see #LAYER_TYPE_SOFTWARE 4352 * @see #LAYER_TYPE_HARDWARE 4353 */ 4354 public static final int LAYER_TYPE_NONE = 0; 4355 4356 /** 4357 * <p>Indicates that the view has a software layer. A software layer is backed 4358 * by a bitmap and causes the view to be rendered using Android's software 4359 * rendering pipeline, even if hardware acceleration is enabled.</p> 4360 * 4361 * <p>Software layers have various usages:</p> 4362 * <p>When the application is not using hardware acceleration, a software layer 4363 * is useful to apply a specific color filter and/or blending mode and/or 4364 * translucency to a view and all its children.</p> 4365 * <p>When the application is using hardware acceleration, a software layer 4366 * is useful to render drawing primitives not supported by the hardware 4367 * accelerated pipeline. It can also be used to cache a complex view tree 4368 * into a texture and reduce the complexity of drawing operations. For instance, 4369 * when animating a complex view tree with a translation, a software layer can 4370 * be used to render the view tree only once.</p> 4371 * <p>Software layers should be avoided when the affected view tree updates 4372 * often. Every update will require to re-render the software layer, which can 4373 * potentially be slow (particularly when hardware acceleration is turned on 4374 * since the layer will have to be uploaded into a hardware texture after every 4375 * update.)</p> 4376 * 4377 * @see #getLayerType() 4378 * @see #setLayerType(int, android.graphics.Paint) 4379 * @see #LAYER_TYPE_NONE 4380 * @see #LAYER_TYPE_HARDWARE 4381 */ 4382 public static final int LAYER_TYPE_SOFTWARE = 1; 4383 4384 /** 4385 * <p>Indicates that the view has a hardware layer. A hardware layer is backed 4386 * by a hardware specific texture (generally Frame Buffer Objects or FBO on 4387 * OpenGL hardware) and causes the view to be rendered using Android's hardware 4388 * rendering pipeline, but only if hardware acceleration is turned on for the 4389 * view hierarchy. When hardware acceleration is turned off, hardware layers 4390 * behave exactly as {@link #LAYER_TYPE_SOFTWARE software layers}.</p> 4391 * 4392 * <p>A hardware layer is useful to apply a specific color filter and/or 4393 * blending mode and/or translucency to a view and all its children.</p> 4394 * <p>A hardware layer can be used to cache a complex view tree into a 4395 * texture and reduce the complexity of drawing operations. For instance, 4396 * when animating a complex view tree with a translation, a hardware layer can 4397 * be used to render the view tree only once.</p> 4398 * <p>A hardware layer can also be used to increase the rendering quality when 4399 * rotation transformations are applied on a view. It can also be used to 4400 * prevent potential clipping issues when applying 3D transforms on a view.</p> 4401 * 4402 * @see #getLayerType() 4403 * @see #setLayerType(int, android.graphics.Paint) 4404 * @see #LAYER_TYPE_NONE 4405 * @see #LAYER_TYPE_SOFTWARE 4406 */ 4407 public static final int LAYER_TYPE_HARDWARE = 2; 4408 4409 @ViewDebug.ExportedProperty(category = "drawing", mapping = { 4410 @ViewDebug.IntToString(from = LAYER_TYPE_NONE, to = "NONE"), 4411 @ViewDebug.IntToString(from = LAYER_TYPE_SOFTWARE, to = "SOFTWARE"), 4412 @ViewDebug.IntToString(from = LAYER_TYPE_HARDWARE, to = "HARDWARE") 4413 }) 4414 int mLayerType = LAYER_TYPE_NONE; 4415 Paint mLayerPaint; 4416 4417 /** 4418 * Set to true when drawing cache is enabled and cannot be created. 4419 * 4420 * @hide 4421 */ 4422 public boolean mCachingFailed; 4423 private Bitmap mDrawingCache; 4424 private Bitmap mUnscaledDrawingCache; 4425 4426 /** 4427 * RenderNode holding View properties, potentially holding a DisplayList of View content. 4428 * <p> 4429 * When non-null and valid, this is expected to contain an up-to-date copy 4430 * of the View content. Its DisplayList content is cleared on temporary detach and reset on 4431 * cleanup. 4432 */ 4433 final RenderNode mRenderNode; 4434 4435 /** 4436 * Set to true when the view is sending hover accessibility events because it 4437 * is the innermost hovered view. 4438 */ 4439 private boolean mSendingHoverAccessibilityEvents; 4440 4441 /** 4442 * Delegate for injecting accessibility functionality. 4443 */ 4444 AccessibilityDelegate mAccessibilityDelegate; 4445 4446 /** 4447 * The view's overlay layer. Developers get a reference to the overlay via getOverlay() 4448 * and add/remove objects to/from the overlay directly through the Overlay methods. 4449 */ 4450 ViewOverlay mOverlay; 4451 4452 /** 4453 * The currently active parent view for receiving delegated nested scrolling events. 4454 * This is set by {@link #startNestedScroll(int)} during a touch interaction and cleared 4455 * by {@link #stopNestedScroll()} at the same point where we clear 4456 * requestDisallowInterceptTouchEvent. 4457 */ 4458 private ViewParent mNestedScrollingParent; 4459 4460 /** 4461 * Consistency verifier for debugging purposes. 4462 * @hide 4463 */ 4464 protected final InputEventConsistencyVerifier mInputEventConsistencyVerifier = 4465 InputEventConsistencyVerifier.isInstrumentationEnabled() ? 4466 new InputEventConsistencyVerifier(this, 0) : null; 4467 4468 private static final AtomicInteger sNextGeneratedId = new AtomicInteger(1); 4469 4470 private int[] mTempNestedScrollConsumed; 4471 4472 /** 4473 * An overlay is going to draw this View instead of being drawn as part of this 4474 * View's parent. mGhostView is the View in the Overlay that must be invalidated 4475 * when this view is invalidated. 4476 */ 4477 GhostView mGhostView; 4478 4479 /** 4480 * Holds pairs of adjacent attribute data: attribute name followed by its value. 4481 * @hide 4482 */ 4483 @ViewDebug.ExportedProperty(category = "attributes", hasAdjacentMapping = true) 4484 public String[] mAttributes; 4485 4486 /** 4487 * Maps a Resource id to its name. 4488 */ 4489 private static SparseArray<String> mAttributeMap; 4490 4491 /** 4492 * Queue of pending runnables. Used to postpone calls to post() until this 4493 * view is attached and has a handler. 4494 */ 4495 private HandlerActionQueue mRunQueue; 4496 4497 /** 4498 * The pointer icon when the mouse hovers on this view. The default is null. 4499 */ 4500 private PointerIcon mPointerIcon; 4501 4502 /** 4503 * @hide 4504 */ 4505 String mStartActivityRequestWho; 4506 4507 @Nullable 4508 private RoundScrollbarRenderer mRoundScrollbarRenderer; 4509 4510 /** Used to delay visibility updates sent to the autofill manager */ 4511 private Handler mVisibilityChangeForAutofillHandler; 4512 4513 /** 4514 * Simple constructor to use when creating a view from code. 4515 * 4516 * @param context The Context the view is running in, through which it can 4517 * access the current theme, resources, etc. 4518 */ 4519 public View(Context context) { 4520 mContext = context; 4521 mResources = context != null ? context.getResources() : null; 4522 mViewFlags = SOUND_EFFECTS_ENABLED | HAPTIC_FEEDBACK_ENABLED | FOCUSABLE_AUTO; 4523 // Set some flags defaults 4524 mPrivateFlags2 = 4525 (LAYOUT_DIRECTION_DEFAULT << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT) | 4526 (TEXT_DIRECTION_DEFAULT << PFLAG2_TEXT_DIRECTION_MASK_SHIFT) | 4527 (PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT) | 4528 (TEXT_ALIGNMENT_DEFAULT << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT) | 4529 (PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT) | 4530 (IMPORTANT_FOR_ACCESSIBILITY_DEFAULT << PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT); 4531 mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); 4532 setOverScrollMode(OVER_SCROLL_IF_CONTENT_SCROLLS); 4533 mUserPaddingStart = UNDEFINED_PADDING; 4534 mUserPaddingEnd = UNDEFINED_PADDING; 4535 mRenderNode = RenderNode.create(getClass().getName(), this); 4536 4537 if (!sCompatibilityDone && context != null) { 4538 final int targetSdkVersion = context.getApplicationInfo().targetSdkVersion; 4539 4540 // Older apps may need this compatibility hack for measurement. 4541 sUseBrokenMakeMeasureSpec = targetSdkVersion <= Build.VERSION_CODES.JELLY_BEAN_MR1; 4542 4543 // Older apps expect onMeasure() to always be called on a layout pass, regardless 4544 // of whether a layout was requested on that View. 4545 sIgnoreMeasureCache = targetSdkVersion < Build.VERSION_CODES.KITKAT; 4546 4547 Canvas.sCompatibilityRestore = targetSdkVersion < Build.VERSION_CODES.M; 4548 Canvas.sCompatibilitySetBitmap = targetSdkVersion < Build.VERSION_CODES.O; 4549 4550 // In M and newer, our widgets can pass a "hint" value in the size 4551 // for UNSPECIFIED MeasureSpecs. This lets child views of scrolling containers 4552 // know what the expected parent size is going to be, so e.g. list items can size 4553 // themselves at 1/3 the size of their container. It breaks older apps though, 4554 // specifically apps that use some popular open source libraries. 4555 sUseZeroUnspecifiedMeasureSpec = targetSdkVersion < Build.VERSION_CODES.M; 4556 4557 // Old versions of the platform would give different results from 4558 // LinearLayout measurement passes using EXACTLY and non-EXACTLY 4559 // modes, so we always need to run an additional EXACTLY pass. 4560 sAlwaysRemeasureExactly = targetSdkVersion <= Build.VERSION_CODES.M; 4561 4562 // Prior to N, layout params could change without requiring a 4563 // subsequent call to setLayoutParams() and they would usually 4564 // work. Partial layout breaks this assumption. 4565 sLayoutParamsAlwaysChanged = targetSdkVersion <= Build.VERSION_CODES.M; 4566 4567 // Prior to N, TextureView would silently ignore calls to setBackground/setForeground. 4568 // On N+, we throw, but that breaks compatibility with apps that use these methods. 4569 sTextureViewIgnoresDrawableSetters = targetSdkVersion <= Build.VERSION_CODES.M; 4570 4571 // Prior to N, we would drop margins in LayoutParam conversions. The fix triggers bugs 4572 // in apps so we target check it to avoid breaking existing apps. 4573 sPreserveMarginParamsInLayoutParamConversion = 4574 targetSdkVersion >= Build.VERSION_CODES.N; 4575 4576 sCascadedDragDrop = targetSdkVersion < Build.VERSION_CODES.N; 4577 4578 sHasFocusableExcludeAutoFocusable = targetSdkVersion < Build.VERSION_CODES.O; 4579 4580 sAutoFocusableOffUIThreadWontNotifyParents = targetSdkVersion < Build.VERSION_CODES.O; 4581 4582 sUseDefaultFocusHighlight = context.getResources().getBoolean( 4583 com.android.internal.R.bool.config_useDefaultFocusHighlight); 4584 4585 sCompatibilityDone = true; 4586 } 4587 } 4588 4589 /** 4590 * Constructor that is called when inflating a view from XML. This is called 4591 * when a view is being constructed from an XML file, supplying attributes 4592 * that were specified in the XML file. This version uses a default style of 4593 * 0, so the only attribute values applied are those in the Context's Theme 4594 * and the given AttributeSet. 4595 * 4596 * <p> 4597 * The method onFinishInflate() will be called after all children have been 4598 * added. 4599 * 4600 * @param context The Context the view is running in, through which it can 4601 * access the current theme, resources, etc. 4602 * @param attrs The attributes of the XML tag that is inflating the view. 4603 * @see #View(Context, AttributeSet, int) 4604 */ 4605 public View(Context context, @Nullable AttributeSet attrs) { 4606 this(context, attrs, 0); 4607 } 4608 4609 /** 4610 * Perform inflation from XML and apply a class-specific base style from a 4611 * theme attribute. This constructor of View allows subclasses to use their 4612 * own base style when they are inflating. For example, a Button class's 4613 * constructor would call this version of the super class constructor and 4614 * supply <code>R.attr.buttonStyle</code> for <var>defStyleAttr</var>; this 4615 * allows the theme's button style to modify all of the base view attributes 4616 * (in particular its background) as well as the Button class's attributes. 4617 * 4618 * @param context The Context the view is running in, through which it can 4619 * access the current theme, resources, etc. 4620 * @param attrs The attributes of the XML tag that is inflating the view. 4621 * @param defStyleAttr An attribute in the current theme that contains a 4622 * reference to a style resource that supplies default values for 4623 * the view. Can be 0 to not look for defaults. 4624 * @see #View(Context, AttributeSet) 4625 */ 4626 public View(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { 4627 this(context, attrs, defStyleAttr, 0); 4628 } 4629 4630 /** 4631 * Perform inflation from XML and apply a class-specific base style from a 4632 * theme attribute or style resource. This constructor of View allows 4633 * subclasses to use their own base style when they are inflating. 4634 * <p> 4635 * When determining the final value of a particular attribute, there are 4636 * four inputs that come into play: 4637 * <ol> 4638 * <li>Any attribute values in the given AttributeSet. 4639 * <li>The style resource specified in the AttributeSet (named "style"). 4640 * <li>The default style specified by <var>defStyleAttr</var>. 4641 * <li>The default style specified by <var>defStyleRes</var>. 4642 * <li>The base values in this theme. 4643 * </ol> 4644 * <p> 4645 * Each of these inputs is considered in-order, with the first listed taking 4646 * precedence over the following ones. In other words, if in the 4647 * AttributeSet you have supplied <code><Button * textColor="#ff000000"></code> 4648 * , then the button's text will <em>always</em> be black, regardless of 4649 * what is specified in any of the styles. 4650 * 4651 * @param context The Context the view is running in, through which it can 4652 * access the current theme, resources, etc. 4653 * @param attrs The attributes of the XML tag that is inflating the view. 4654 * @param defStyleAttr An attribute in the current theme that contains a 4655 * reference to a style resource that supplies default values for 4656 * the view. Can be 0 to not look for defaults. 4657 * @param defStyleRes A resource identifier of a style resource that 4658 * supplies default values for the view, used only if 4659 * defStyleAttr is 0 or can not be found in the theme. Can be 0 4660 * to not look for defaults. 4661 * @see #View(Context, AttributeSet, int) 4662 */ 4663 public View(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) { 4664 this(context); 4665 4666 final TypedArray a = context.obtainStyledAttributes( 4667 attrs, com.android.internal.R.styleable.View, defStyleAttr, defStyleRes); 4668 4669 if (mDebugViewAttributes) { 4670 saveAttributeData(attrs, a); 4671 } 4672 4673 Drawable background = null; 4674 4675 int leftPadding = -1; 4676 int topPadding = -1; 4677 int rightPadding = -1; 4678 int bottomPadding = -1; 4679 int startPadding = UNDEFINED_PADDING; 4680 int endPadding = UNDEFINED_PADDING; 4681 4682 int padding = -1; 4683 int paddingHorizontal = -1; 4684 int paddingVertical = -1; 4685 4686 int viewFlagValues = 0; 4687 int viewFlagMasks = 0; 4688 4689 boolean setScrollContainer = false; 4690 4691 int x = 0; 4692 int y = 0; 4693 4694 float tx = 0; 4695 float ty = 0; 4696 float tz = 0; 4697 float elevation = 0; 4698 float rotation = 0; 4699 float rotationX = 0; 4700 float rotationY = 0; 4701 float sx = 1f; 4702 float sy = 1f; 4703 boolean transformSet = false; 4704 4705 int scrollbarStyle = SCROLLBARS_INSIDE_OVERLAY; 4706 int overScrollMode = mOverScrollMode; 4707 boolean initializeScrollbars = false; 4708 boolean initializeScrollIndicators = false; 4709 4710 boolean startPaddingDefined = false; 4711 boolean endPaddingDefined = false; 4712 boolean leftPaddingDefined = false; 4713 boolean rightPaddingDefined = false; 4714 4715 final int targetSdkVersion = context.getApplicationInfo().targetSdkVersion; 4716 4717 // Set default values. 4718 viewFlagValues |= FOCUSABLE_AUTO; 4719 viewFlagMasks |= FOCUSABLE_AUTO; 4720 4721 final int N = a.getIndexCount(); 4722 for (int i = 0; i < N; i++) { 4723 int attr = a.getIndex(i); 4724 switch (attr) { 4725 case com.android.internal.R.styleable.View_background: 4726 background = a.getDrawable(attr); 4727 break; 4728 case com.android.internal.R.styleable.View_padding: 4729 padding = a.getDimensionPixelSize(attr, -1); 4730 mUserPaddingLeftInitial = padding; 4731 mUserPaddingRightInitial = padding; 4732 leftPaddingDefined = true; 4733 rightPaddingDefined = true; 4734 break; 4735 case com.android.internal.R.styleable.View_paddingHorizontal: 4736 paddingHorizontal = a.getDimensionPixelSize(attr, -1); 4737 mUserPaddingLeftInitial = paddingHorizontal; 4738 mUserPaddingRightInitial = paddingHorizontal; 4739 leftPaddingDefined = true; 4740 rightPaddingDefined = true; 4741 break; 4742 case com.android.internal.R.styleable.View_paddingVertical: 4743 paddingVertical = a.getDimensionPixelSize(attr, -1); 4744 break; 4745 case com.android.internal.R.styleable.View_paddingLeft: 4746 leftPadding = a.getDimensionPixelSize(attr, -1); 4747 mUserPaddingLeftInitial = leftPadding; 4748 leftPaddingDefined = true; 4749 break; 4750 case com.android.internal.R.styleable.View_paddingTop: 4751 topPadding = a.getDimensionPixelSize(attr, -1); 4752 break; 4753 case com.android.internal.R.styleable.View_paddingRight: 4754 rightPadding = a.getDimensionPixelSize(attr, -1); 4755 mUserPaddingRightInitial = rightPadding; 4756 rightPaddingDefined = true; 4757 break; 4758 case com.android.internal.R.styleable.View_paddingBottom: 4759 bottomPadding = a.getDimensionPixelSize(attr, -1); 4760 break; 4761 case com.android.internal.R.styleable.View_paddingStart: 4762 startPadding = a.getDimensionPixelSize(attr, UNDEFINED_PADDING); 4763 startPaddingDefined = (startPadding != UNDEFINED_PADDING); 4764 break; 4765 case com.android.internal.R.styleable.View_paddingEnd: 4766 endPadding = a.getDimensionPixelSize(attr, UNDEFINED_PADDING); 4767 endPaddingDefined = (endPadding != UNDEFINED_PADDING); 4768 break; 4769 case com.android.internal.R.styleable.View_scrollX: 4770 x = a.getDimensionPixelOffset(attr, 0); 4771 break; 4772 case com.android.internal.R.styleable.View_scrollY: 4773 y = a.getDimensionPixelOffset(attr, 0); 4774 break; 4775 case com.android.internal.R.styleable.View_alpha: 4776 setAlpha(a.getFloat(attr, 1f)); 4777 break; 4778 case com.android.internal.R.styleable.View_transformPivotX: 4779 setPivotX(a.getDimension(attr, 0)); 4780 break; 4781 case com.android.internal.R.styleable.View_transformPivotY: 4782 setPivotY(a.getDimension(attr, 0)); 4783 break; 4784 case com.android.internal.R.styleable.View_translationX: 4785 tx = a.getDimension(attr, 0); 4786 transformSet = true; 4787 break; 4788 case com.android.internal.R.styleable.View_translationY: 4789 ty = a.getDimension(attr, 0); 4790 transformSet = true; 4791 break; 4792 case com.android.internal.R.styleable.View_translationZ: 4793 tz = a.getDimension(attr, 0); 4794 transformSet = true; 4795 break; 4796 case com.android.internal.R.styleable.View_elevation: 4797 elevation = a.getDimension(attr, 0); 4798 transformSet = true; 4799 break; 4800 case com.android.internal.R.styleable.View_rotation: 4801 rotation = a.getFloat(attr, 0); 4802 transformSet = true; 4803 break; 4804 case com.android.internal.R.styleable.View_rotationX: 4805 rotationX = a.getFloat(attr, 0); 4806 transformSet = true; 4807 break; 4808 case com.android.internal.R.styleable.View_rotationY: 4809 rotationY = a.getFloat(attr, 0); 4810 transformSet = true; 4811 break; 4812 case com.android.internal.R.styleable.View_scaleX: 4813 sx = a.getFloat(attr, 1f); 4814 transformSet = true; 4815 break; 4816 case com.android.internal.R.styleable.View_scaleY: 4817 sy = a.getFloat(attr, 1f); 4818 transformSet = true; 4819 break; 4820 case com.android.internal.R.styleable.View_id: 4821 mID = a.getResourceId(attr, NO_ID); 4822 break; 4823 case com.android.internal.R.styleable.View_tag: 4824 mTag = a.getText(attr); 4825 break; 4826 case com.android.internal.R.styleable.View_fitsSystemWindows: 4827 if (a.getBoolean(attr, false)) { 4828 viewFlagValues |= FITS_SYSTEM_WINDOWS; 4829 viewFlagMasks |= FITS_SYSTEM_WINDOWS; 4830 } 4831 break; 4832 case com.android.internal.R.styleable.View_focusable: 4833 viewFlagValues = (viewFlagValues & ~FOCUSABLE_MASK) | getFocusableAttribute(a); 4834 if ((viewFlagValues & FOCUSABLE_AUTO) == 0) { 4835 viewFlagMasks |= FOCUSABLE_MASK; 4836 } 4837 break; 4838 case com.android.internal.R.styleable.View_focusableInTouchMode: 4839 if (a.getBoolean(attr, false)) { 4840 // unset auto focus since focusableInTouchMode implies explicit focusable 4841 viewFlagValues &= ~FOCUSABLE_AUTO; 4842 viewFlagValues |= FOCUSABLE_IN_TOUCH_MODE | FOCUSABLE; 4843 viewFlagMasks |= FOCUSABLE_IN_TOUCH_MODE | FOCUSABLE_MASK; 4844 } 4845 break; 4846 case com.android.internal.R.styleable.View_clickable: 4847 if (a.getBoolean(attr, false)) { 4848 viewFlagValues |= CLICKABLE; 4849 viewFlagMasks |= CLICKABLE; 4850 } 4851 break; 4852 case com.android.internal.R.styleable.View_longClickable: 4853 if (a.getBoolean(attr, false)) { 4854 viewFlagValues |= LONG_CLICKABLE; 4855 viewFlagMasks |= LONG_CLICKABLE; 4856 } 4857 break; 4858 case com.android.internal.R.styleable.View_contextClickable: 4859 if (a.getBoolean(attr, false)) { 4860 viewFlagValues |= CONTEXT_CLICKABLE; 4861 viewFlagMasks |= CONTEXT_CLICKABLE; 4862 } 4863 break; 4864 case com.android.internal.R.styleable.View_saveEnabled: 4865 if (!a.getBoolean(attr, true)) { 4866 viewFlagValues |= SAVE_DISABLED; 4867 viewFlagMasks |= SAVE_DISABLED_MASK; 4868 } 4869 break; 4870 case com.android.internal.R.styleable.View_duplicateParentState: 4871 if (a.getBoolean(attr, false)) { 4872 viewFlagValues |= DUPLICATE_PARENT_STATE; 4873 viewFlagMasks |= DUPLICATE_PARENT_STATE; 4874 } 4875 break; 4876 case com.android.internal.R.styleable.View_visibility: 4877 final int visibility = a.getInt(attr, 0); 4878 if (visibility != 0) { 4879 viewFlagValues |= VISIBILITY_FLAGS[visibility]; 4880 viewFlagMasks |= VISIBILITY_MASK; 4881 } 4882 break; 4883 case com.android.internal.R.styleable.View_layoutDirection: 4884 // Clear any layout direction flags (included resolved bits) already set 4885 mPrivateFlags2 &= 4886 ~(PFLAG2_LAYOUT_DIRECTION_MASK | PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK); 4887 // Set the layout direction flags depending on the value of the attribute 4888 final int layoutDirection = a.getInt(attr, -1); 4889 final int value = (layoutDirection != -1) ? 4890 LAYOUT_DIRECTION_FLAGS[layoutDirection] : LAYOUT_DIRECTION_DEFAULT; 4891 mPrivateFlags2 |= (value << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT); 4892 break; 4893 case com.android.internal.R.styleable.View_drawingCacheQuality: 4894 final int cacheQuality = a.getInt(attr, 0); 4895 if (cacheQuality != 0) { 4896 viewFlagValues |= DRAWING_CACHE_QUALITY_FLAGS[cacheQuality]; 4897 viewFlagMasks |= DRAWING_CACHE_QUALITY_MASK; 4898 } 4899 break; 4900 case com.android.internal.R.styleable.View_contentDescription: 4901 setContentDescription(a.getString(attr)); 4902 break; 4903 case com.android.internal.R.styleable.View_accessibilityTraversalBefore: 4904 setAccessibilityTraversalBefore(a.getResourceId(attr, NO_ID)); 4905 break; 4906 case com.android.internal.R.styleable.View_accessibilityTraversalAfter: 4907 setAccessibilityTraversalAfter(a.getResourceId(attr, NO_ID)); 4908 break; 4909 case com.android.internal.R.styleable.View_labelFor: 4910 setLabelFor(a.getResourceId(attr, NO_ID)); 4911 break; 4912 case com.android.internal.R.styleable.View_soundEffectsEnabled: 4913 if (!a.getBoolean(attr, true)) { 4914 viewFlagValues &= ~SOUND_EFFECTS_ENABLED; 4915 viewFlagMasks |= SOUND_EFFECTS_ENABLED; 4916 } 4917 break; 4918 case com.android.internal.R.styleable.View_hapticFeedbackEnabled: 4919 if (!a.getBoolean(attr, true)) { 4920 viewFlagValues &= ~HAPTIC_FEEDBACK_ENABLED; 4921 viewFlagMasks |= HAPTIC_FEEDBACK_ENABLED; 4922 } 4923 break; 4924 case R.styleable.View_scrollbars: 4925 final int scrollbars = a.getInt(attr, SCROLLBARS_NONE); 4926 if (scrollbars != SCROLLBARS_NONE) { 4927 viewFlagValues |= scrollbars; 4928 viewFlagMasks |= SCROLLBARS_MASK; 4929 initializeScrollbars = true; 4930 } 4931 break; 4932 //noinspection deprecation 4933 case R.styleable.View_fadingEdge: 4934 if (targetSdkVersion >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { 4935 // Ignore the attribute starting with ICS 4936 break; 4937 } 4938 // With builds < ICS, fall through and apply fading edges 4939 case R.styleable.View_requiresFadingEdge: 4940 final int fadingEdge = a.getInt(attr, FADING_EDGE_NONE); 4941 if (fadingEdge != FADING_EDGE_NONE) { 4942 viewFlagValues |= fadingEdge; 4943 viewFlagMasks |= FADING_EDGE_MASK; 4944 initializeFadingEdgeInternal(a); 4945 } 4946 break; 4947 case R.styleable.View_scrollbarStyle: 4948 scrollbarStyle = a.getInt(attr, SCROLLBARS_INSIDE_OVERLAY); 4949 if (scrollbarStyle != SCROLLBARS_INSIDE_OVERLAY) { 4950 viewFlagValues |= scrollbarStyle & SCROLLBARS_STYLE_MASK; 4951 viewFlagMasks |= SCROLLBARS_STYLE_MASK; 4952 } 4953 break; 4954 case R.styleable.View_isScrollContainer: 4955 setScrollContainer = true; 4956 if (a.getBoolean(attr, false)) { 4957 setScrollContainer(true); 4958 } 4959 break; 4960 case com.android.internal.R.styleable.View_keepScreenOn: 4961 if (a.getBoolean(attr, false)) { 4962 viewFlagValues |= KEEP_SCREEN_ON; 4963 viewFlagMasks |= KEEP_SCREEN_ON; 4964 } 4965 break; 4966 case R.styleable.View_filterTouchesWhenObscured: 4967 if (a.getBoolean(attr, false)) { 4968 viewFlagValues |= FILTER_TOUCHES_WHEN_OBSCURED; 4969 viewFlagMasks |= FILTER_TOUCHES_WHEN_OBSCURED; 4970 } 4971 break; 4972 case R.styleable.View_nextFocusLeft: 4973 mNextFocusLeftId = a.getResourceId(attr, View.NO_ID); 4974 break; 4975 case R.styleable.View_nextFocusRight: 4976 mNextFocusRightId = a.getResourceId(attr, View.NO_ID); 4977 break; 4978 case R.styleable.View_nextFocusUp: 4979 mNextFocusUpId = a.getResourceId(attr, View.NO_ID); 4980 break; 4981 case R.styleable.View_nextFocusDown: 4982 mNextFocusDownId = a.getResourceId(attr, View.NO_ID); 4983 break; 4984 case R.styleable.View_nextFocusForward: 4985 mNextFocusForwardId = a.getResourceId(attr, View.NO_ID); 4986 break; 4987 case R.styleable.View_nextClusterForward: 4988 mNextClusterForwardId = a.getResourceId(attr, View.NO_ID); 4989 break; 4990 case R.styleable.View_minWidth: 4991 mMinWidth = a.getDimensionPixelSize(attr, 0); 4992 break; 4993 case R.styleable.View_minHeight: 4994 mMinHeight = a.getDimensionPixelSize(attr, 0); 4995 break; 4996 case R.styleable.View_onClick: 4997 if (context.isRestricted()) { 4998 throw new IllegalStateException("The android:onClick attribute cannot " 4999 + "be used within a restricted context"); 5000 } 5001 5002 final String handlerName = a.getString(attr); 5003 if (handlerName != null) { 5004 setOnClickListener(new DeclaredOnClickListener(this, handlerName)); 5005 } 5006 break; 5007 case R.styleable.View_overScrollMode: 5008 overScrollMode = a.getInt(attr, OVER_SCROLL_IF_CONTENT_SCROLLS); 5009 break; 5010 case R.styleable.View_verticalScrollbarPosition: 5011 mVerticalScrollbarPosition = a.getInt(attr, SCROLLBAR_POSITION_DEFAULT); 5012 break; 5013 case R.styleable.View_layerType: 5014 setLayerType(a.getInt(attr, LAYER_TYPE_NONE), null); 5015 break; 5016 case R.styleable.View_textDirection: 5017 // Clear any text direction flag already set 5018 mPrivateFlags2 &= ~PFLAG2_TEXT_DIRECTION_MASK; 5019 // Set the text direction flags depending on the value of the attribute 5020 final int textDirection = a.getInt(attr, -1); 5021 if (textDirection != -1) { 5022 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_FLAGS[textDirection]; 5023 } 5024 break; 5025 case R.styleable.View_textAlignment: 5026 // Clear any text alignment flag already set 5027 mPrivateFlags2 &= ~PFLAG2_TEXT_ALIGNMENT_MASK; 5028 // Set the text alignment flag depending on the value of the attribute 5029 final int textAlignment = a.getInt(attr, TEXT_ALIGNMENT_DEFAULT); 5030 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_FLAGS[textAlignment]; 5031 break; 5032 case R.styleable.View_importantForAccessibility: 5033 setImportantForAccessibility(a.getInt(attr, 5034 IMPORTANT_FOR_ACCESSIBILITY_DEFAULT)); 5035 break; 5036 case R.styleable.View_accessibilityLiveRegion: 5037 setAccessibilityLiveRegion(a.getInt(attr, ACCESSIBILITY_LIVE_REGION_DEFAULT)); 5038 break; 5039 case R.styleable.View_transitionName: 5040 setTransitionName(a.getString(attr)); 5041 break; 5042 case R.styleable.View_nestedScrollingEnabled: 5043 setNestedScrollingEnabled(a.getBoolean(attr, false)); 5044 break; 5045 case R.styleable.View_stateListAnimator: 5046 setStateListAnimator(AnimatorInflater.loadStateListAnimator(context, 5047 a.getResourceId(attr, 0))); 5048 break; 5049 case R.styleable.View_backgroundTint: 5050 // This will get applied later during setBackground(). 5051 if (mBackgroundTint == null) { 5052 mBackgroundTint = new TintInfo(); 5053 } 5054 mBackgroundTint.mTintList = a.getColorStateList( 5055 R.styleable.View_backgroundTint); 5056 mBackgroundTint.mHasTintList = true; 5057 break; 5058 case R.styleable.View_backgroundTintMode: 5059 // This will get applied later during setBackground(). 5060 if (mBackgroundTint == null) { 5061 mBackgroundTint = new TintInfo(); 5062 } 5063 mBackgroundTint.mTintMode = Drawable.parseTintMode(a.getInt( 5064 R.styleable.View_backgroundTintMode, -1), null); 5065 mBackgroundTint.mHasTintMode = true; 5066 break; 5067 case R.styleable.View_outlineProvider: 5068 setOutlineProviderFromAttribute(a.getInt(R.styleable.View_outlineProvider, 5069 PROVIDER_BACKGROUND)); 5070 break; 5071 case R.styleable.View_foreground: 5072 if (targetSdkVersion >= Build.VERSION_CODES.M || this instanceof FrameLayout) { 5073 setForeground(a.getDrawable(attr)); 5074 } 5075 break; 5076 case R.styleable.View_foregroundGravity: 5077 if (targetSdkVersion >= Build.VERSION_CODES.M || this instanceof FrameLayout) { 5078 setForegroundGravity(a.getInt(attr, Gravity.NO_GRAVITY)); 5079 } 5080 break; 5081 case R.styleable.View_foregroundTintMode: 5082 if (targetSdkVersion >= Build.VERSION_CODES.M || this instanceof FrameLayout) { 5083 setForegroundTintMode(Drawable.parseTintMode(a.getInt(attr, -1), null)); 5084 } 5085 break; 5086 case R.styleable.View_foregroundTint: 5087 if (targetSdkVersion >= Build.VERSION_CODES.M || this instanceof FrameLayout) { 5088 setForegroundTintList(a.getColorStateList(attr)); 5089 } 5090 break; 5091 case R.styleable.View_foregroundInsidePadding: 5092 if (targetSdkVersion >= Build.VERSION_CODES.M || this instanceof FrameLayout) { 5093 if (mForegroundInfo == null) { 5094 mForegroundInfo = new ForegroundInfo(); 5095 } 5096 mForegroundInfo.mInsidePadding = a.getBoolean(attr, 5097 mForegroundInfo.mInsidePadding); 5098 } 5099 break; 5100 case R.styleable.View_scrollIndicators: 5101 final int scrollIndicators = 5102 (a.getInt(attr, 0) << SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT) 5103 & SCROLL_INDICATORS_PFLAG3_MASK; 5104 if (scrollIndicators != 0) { 5105 mPrivateFlags3 |= scrollIndicators; 5106 initializeScrollIndicators = true; 5107 } 5108 break; 5109 case R.styleable.View_pointerIcon: 5110 final int resourceId = a.getResourceId(attr, 0); 5111 if (resourceId != 0) { 5112 setPointerIcon(PointerIcon.load( 5113 context.getResources(), resourceId)); 5114 } else { 5115 final int pointerType = a.getInt(attr, PointerIcon.TYPE_NOT_SPECIFIED); 5116 if (pointerType != PointerIcon.TYPE_NOT_SPECIFIED) { 5117 setPointerIcon(PointerIcon.getSystemIcon(context, pointerType)); 5118 } 5119 } 5120 break; 5121 case R.styleable.View_forceHasOverlappingRendering: 5122 if (a.peekValue(attr) != null) { 5123 forceHasOverlappingRendering(a.getBoolean(attr, true)); 5124 } 5125 break; 5126 case R.styleable.View_tooltipText: 5127 setTooltipText(a.getText(attr)); 5128 break; 5129 case R.styleable.View_keyboardNavigationCluster: 5130 if (a.peekValue(attr) != null) { 5131 setKeyboardNavigationCluster(a.getBoolean(attr, true)); 5132 } 5133 break; 5134 case R.styleable.View_focusedByDefault: 5135 if (a.peekValue(attr) != null) { 5136 setFocusedByDefault(a.getBoolean(attr, true)); 5137 } 5138 break; 5139 case R.styleable.View_autofillHints: 5140 if (a.peekValue(attr) != null) { 5141 CharSequence[] rawHints = null; 5142 String rawString = null; 5143 5144 if (a.getType(attr) == TypedValue.TYPE_REFERENCE) { 5145 int resId = a.getResourceId(attr, 0); 5146 5147 try { 5148 rawHints = a.getTextArray(attr); 5149 } catch (Resources.NotFoundException e) { 5150 rawString = getResources().getString(resId); 5151 } 5152 } else { 5153 rawString = a.getString(attr); 5154 } 5155 5156 if (rawHints == null) { 5157 if (rawString == null) { 5158 throw new IllegalArgumentException( 5159 "Could not resolve autofillHints"); 5160 } else { 5161 rawHints = rawString.split(","); 5162 } 5163 } 5164 5165 String[] hints = new String[rawHints.length]; 5166 5167 int numHints = rawHints.length; 5168 for (int rawHintNum = 0; rawHintNum < numHints; rawHintNum++) { 5169 hints[rawHintNum] = rawHints[rawHintNum].toString().trim(); 5170 } 5171 setAutofillHints(hints); 5172 } 5173 break; 5174 case R.styleable.View_importantForAutofill: 5175 if (a.peekValue(attr) != null) { 5176 setImportantForAutofill(a.getInt(attr, IMPORTANT_FOR_AUTOFILL_AUTO)); 5177 } 5178 break; 5179 case R.styleable.View_defaultFocusHighlightEnabled: 5180 if (a.peekValue(attr) != null) { 5181 setDefaultFocusHighlightEnabled(a.getBoolean(attr, true)); 5182 } 5183 break; 5184 } 5185 } 5186 5187 setOverScrollMode(overScrollMode); 5188 5189 // Cache start/end user padding as we cannot fully resolve padding here (we dont have yet 5190 // the resolved layout direction). Those cached values will be used later during padding 5191 // resolution. 5192 mUserPaddingStart = startPadding; 5193 mUserPaddingEnd = endPadding; 5194 5195 if (background != null) { 5196 setBackground(background); 5197 } 5198 5199 // setBackground above will record that padding is currently provided by the background. 5200 // If we have padding specified via xml, record that here instead and use it. 5201 mLeftPaddingDefined = leftPaddingDefined; 5202 mRightPaddingDefined = rightPaddingDefined; 5203 5204 if (padding >= 0) { 5205 leftPadding = padding; 5206 topPadding = padding; 5207 rightPadding = padding; 5208 bottomPadding = padding; 5209 mUserPaddingLeftInitial = padding; 5210 mUserPaddingRightInitial = padding; 5211 } else { 5212 if (paddingHorizontal >= 0) { 5213 leftPadding = paddingHorizontal; 5214 rightPadding = paddingHorizontal; 5215 mUserPaddingLeftInitial = paddingHorizontal; 5216 mUserPaddingRightInitial = paddingHorizontal; 5217 } 5218 if (paddingVertical >= 0) { 5219 topPadding = paddingVertical; 5220 bottomPadding = paddingVertical; 5221 } 5222 } 5223 5224 if (isRtlCompatibilityMode()) { 5225 // RTL compatibility mode: pre Jelly Bean MR1 case OR no RTL support case. 5226 // left / right padding are used if defined (meaning here nothing to do). If they are not 5227 // defined and start / end padding are defined (e.g. in Frameworks resources), then we use 5228 // start / end and resolve them as left / right (layout direction is not taken into account). 5229 // Padding from the background drawable is stored at this point in mUserPaddingLeftInitial 5230 // and mUserPaddingRightInitial) so drawable padding will be used as ultimate default if 5231 // defined. 5232 if (!mLeftPaddingDefined && startPaddingDefined) { 5233 leftPadding = startPadding; 5234 } 5235 mUserPaddingLeftInitial = (leftPadding >= 0) ? leftPadding : mUserPaddingLeftInitial; 5236 if (!mRightPaddingDefined && endPaddingDefined) { 5237 rightPadding = endPadding; 5238 } 5239 mUserPaddingRightInitial = (rightPadding >= 0) ? rightPadding : mUserPaddingRightInitial; 5240 } else { 5241 // Jelly Bean MR1 and after case: if start/end defined, they will override any left/right 5242 // values defined. Otherwise, left /right values are used. 5243 // Padding from the background drawable is stored at this point in mUserPaddingLeftInitial 5244 // and mUserPaddingRightInitial) so drawable padding will be used as ultimate default if 5245 // defined. 5246 final boolean hasRelativePadding = startPaddingDefined || endPaddingDefined; 5247 5248 if (mLeftPaddingDefined && !hasRelativePadding) { 5249 mUserPaddingLeftInitial = leftPadding; 5250 } 5251 if (mRightPaddingDefined && !hasRelativePadding) { 5252 mUserPaddingRightInitial = rightPadding; 5253 } 5254 } 5255 5256 internalSetPadding( 5257 mUserPaddingLeftInitial, 5258 topPadding >= 0 ? topPadding : mPaddingTop, 5259 mUserPaddingRightInitial, 5260 bottomPadding >= 0 ? bottomPadding : mPaddingBottom); 5261 5262 if (viewFlagMasks != 0) { 5263 setFlags(viewFlagValues, viewFlagMasks); 5264 } 5265 5266 if (initializeScrollbars) { 5267 initializeScrollbarsInternal(a); 5268 } 5269 5270 if (initializeScrollIndicators) { 5271 initializeScrollIndicatorsInternal(); 5272 } 5273 5274 a.recycle(); 5275 5276 // Needs to be called after mViewFlags is set 5277 if (scrollbarStyle != SCROLLBARS_INSIDE_OVERLAY) { 5278 recomputePadding(); 5279 } 5280 5281 if (x != 0 || y != 0) { 5282 scrollTo(x, y); 5283 } 5284 5285 if (transformSet) { 5286 setTranslationX(tx); 5287 setTranslationY(ty); 5288 setTranslationZ(tz); 5289 setElevation(elevation); 5290 setRotation(rotation); 5291 setRotationX(rotationX); 5292 setRotationY(rotationY); 5293 setScaleX(sx); 5294 setScaleY(sy); 5295 } 5296 5297 if (!setScrollContainer && (viewFlagValues&SCROLLBARS_VERTICAL) != 0) { 5298 setScrollContainer(true); 5299 } 5300 5301 computeOpaqueFlags(); 5302 } 5303 5304 /** 5305 * An implementation of OnClickListener that attempts to lazily load a 5306 * named click handling method from a parent or ancestor context. 5307 */ 5308 private static class DeclaredOnClickListener implements OnClickListener { 5309 private final View mHostView; 5310 private final String mMethodName; 5311 5312 private Method mResolvedMethod; 5313 private Context mResolvedContext; 5314 5315 public DeclaredOnClickListener(@NonNull View hostView, @NonNull String methodName) { 5316 mHostView = hostView; 5317 mMethodName = methodName; 5318 } 5319 5320 @Override 5321 public void onClick(@NonNull View v) { 5322 if (mResolvedMethod == null) { 5323 resolveMethod(mHostView.getContext(), mMethodName); 5324 } 5325 5326 try { 5327 mResolvedMethod.invoke(mResolvedContext, v); 5328 } catch (IllegalAccessException e) { 5329 throw new IllegalStateException( 5330 "Could not execute non-public method for android:onClick", e); 5331 } catch (InvocationTargetException e) { 5332 throw new IllegalStateException( 5333 "Could not execute method for android:onClick", e); 5334 } 5335 } 5336 5337 @NonNull 5338 private void resolveMethod(@Nullable Context context, @NonNull String name) { 5339 while (context != null) { 5340 try { 5341 if (!context.isRestricted()) { 5342 final Method method = context.getClass().getMethod(mMethodName, View.class); 5343 if (method != null) { 5344 mResolvedMethod = method; 5345 mResolvedContext = context; 5346 return; 5347 } 5348 } 5349 } catch (NoSuchMethodException e) { 5350 // Failed to find method, keep searching up the hierarchy. 5351 } 5352 5353 if (context instanceof ContextWrapper) { 5354 context = ((ContextWrapper) context).getBaseContext(); 5355 } else { 5356 // Can't search up the hierarchy, null out and fail. 5357 context = null; 5358 } 5359 } 5360 5361 final int id = mHostView.getId(); 5362 final String idText = id == NO_ID ? "" : " with id '" 5363 + mHostView.getContext().getResources().getResourceEntryName(id) + "'"; 5364 throw new IllegalStateException("Could not find method " + mMethodName 5365 + "(View) in a parent or ancestor Context for android:onClick " 5366 + "attribute defined on view " + mHostView.getClass() + idText); 5367 } 5368 } 5369 5370 /** 5371 * Non-public constructor for use in testing 5372 */ 5373 View() { 5374 mResources = null; 5375 mRenderNode = RenderNode.create(getClass().getName(), this); 5376 } 5377 5378 final boolean debugDraw() { 5379 return DEBUG_DRAW || mAttachInfo != null && mAttachInfo.mDebugLayout; 5380 } 5381 5382 private static SparseArray<String> getAttributeMap() { 5383 if (mAttributeMap == null) { 5384 mAttributeMap = new SparseArray<>(); 5385 } 5386 return mAttributeMap; 5387 } 5388 5389 private void saveAttributeData(@Nullable AttributeSet attrs, @NonNull TypedArray t) { 5390 final int attrsCount = attrs == null ? 0 : attrs.getAttributeCount(); 5391 final int indexCount = t.getIndexCount(); 5392 final String[] attributes = new String[(attrsCount + indexCount) * 2]; 5393 5394 int i = 0; 5395 5396 // Store raw XML attributes. 5397 for (int j = 0; j < attrsCount; ++j) { 5398 attributes[i] = attrs.getAttributeName(j); 5399 attributes[i + 1] = attrs.getAttributeValue(j); 5400 i += 2; 5401 } 5402 5403 // Store resolved styleable attributes. 5404 final Resources res = t.getResources(); 5405 final SparseArray<String> attributeMap = getAttributeMap(); 5406 for (int j = 0; j < indexCount; ++j) { 5407 final int index = t.getIndex(j); 5408 if (!t.hasValueOrEmpty(index)) { 5409 // Value is undefined. Skip it. 5410 continue; 5411 } 5412 5413 final int resourceId = t.getResourceId(index, 0); 5414 if (resourceId == 0) { 5415 // Value is not a reference. Skip it. 5416 continue; 5417 } 5418 5419 String resourceName = attributeMap.get(resourceId); 5420 if (resourceName == null) { 5421 try { 5422 resourceName = res.getResourceName(resourceId); 5423 } catch (Resources.NotFoundException e) { 5424 resourceName = "0x" + Integer.toHexString(resourceId); 5425 } 5426 attributeMap.put(resourceId, resourceName); 5427 } 5428 5429 attributes[i] = resourceName; 5430 attributes[i + 1] = t.getString(index); 5431 i += 2; 5432 } 5433 5434 // Trim to fit contents. 5435 final String[] trimmed = new String[i]; 5436 System.arraycopy(attributes, 0, trimmed, 0, i); 5437 mAttributes = trimmed; 5438 } 5439 5440 public String toString() { 5441 StringBuilder out = new StringBuilder(128); 5442 out.append(getClass().getName()); 5443 out.append('{'); 5444 out.append(Integer.toHexString(System.identityHashCode(this))); 5445 out.append(' '); 5446 switch (mViewFlags&VISIBILITY_MASK) { 5447 case VISIBLE: out.append('V'); break; 5448 case INVISIBLE: out.append('I'); break; 5449 case GONE: out.append('G'); break; 5450 default: out.append('.'); break; 5451 } 5452 out.append((mViewFlags & FOCUSABLE) == FOCUSABLE ? 'F' : '.'); 5453 out.append((mViewFlags&ENABLED_MASK) == ENABLED ? 'E' : '.'); 5454 out.append((mViewFlags&DRAW_MASK) == WILL_NOT_DRAW ? '.' : 'D'); 5455 out.append((mViewFlags&SCROLLBARS_HORIZONTAL) != 0 ? 'H' : '.'); 5456 out.append((mViewFlags&SCROLLBARS_VERTICAL) != 0 ? 'V' : '.'); 5457 out.append((mViewFlags&CLICKABLE) != 0 ? 'C' : '.'); 5458 out.append((mViewFlags&LONG_CLICKABLE) != 0 ? 'L' : '.'); 5459 out.append((mViewFlags&CONTEXT_CLICKABLE) != 0 ? 'X' : '.'); 5460 out.append(' '); 5461 out.append((mPrivateFlags&PFLAG_IS_ROOT_NAMESPACE) != 0 ? 'R' : '.'); 5462 out.append((mPrivateFlags&PFLAG_FOCUSED) != 0 ? 'F' : '.'); 5463 out.append((mPrivateFlags&PFLAG_SELECTED) != 0 ? 'S' : '.'); 5464 if ((mPrivateFlags&PFLAG_PREPRESSED) != 0) { 5465 out.append('p'); 5466 } else { 5467 out.append((mPrivateFlags&PFLAG_PRESSED) != 0 ? 'P' : '.'); 5468 } 5469 out.append((mPrivateFlags&PFLAG_HOVERED) != 0 ? 'H' : '.'); 5470 out.append((mPrivateFlags&PFLAG_ACTIVATED) != 0 ? 'A' : '.'); 5471 out.append((mPrivateFlags&PFLAG_INVALIDATED) != 0 ? 'I' : '.'); 5472 out.append((mPrivateFlags&PFLAG_DIRTY_MASK) != 0 ? 'D' : '.'); 5473 out.append(' '); 5474 out.append(mLeft); 5475 out.append(','); 5476 out.append(mTop); 5477 out.append('-'); 5478 out.append(mRight); 5479 out.append(','); 5480 out.append(mBottom); 5481 final int id = getId(); 5482 if (id != NO_ID) { 5483 out.append(" #"); 5484 out.append(Integer.toHexString(id)); 5485 final Resources r = mResources; 5486 if (id > 0 && Resources.resourceHasPackage(id) && r != null) { 5487 try { 5488 String pkgname; 5489 switch (id&0xff000000) { 5490 case 0x7f000000: 5491 pkgname="app"; 5492 break; 5493 case 0x01000000: 5494 pkgname="android"; 5495 break; 5496 default: 5497 pkgname = r.getResourcePackageName(id); 5498 break; 5499 } 5500 String typename = r.getResourceTypeName(id); 5501 String entryname = r.getResourceEntryName(id); 5502 out.append(" "); 5503 out.append(pkgname); 5504 out.append(":"); 5505 out.append(typename); 5506 out.append("/"); 5507 out.append(entryname); 5508 } catch (Resources.NotFoundException e) { 5509 } 5510 } 5511 } 5512 out.append("}"); 5513 return out.toString(); 5514 } 5515 5516 /** 5517 * <p> 5518 * Initializes the fading edges from a given set of styled attributes. This 5519 * method should be called by subclasses that need fading edges and when an 5520 * instance of these subclasses is created programmatically rather than 5521 * being inflated from XML. This method is automatically called when the XML 5522 * is inflated. 5523 * </p> 5524 * 5525 * @param a the styled attributes set to initialize the fading edges from 5526 * 5527 * @removed 5528 */ 5529 protected void initializeFadingEdge(TypedArray a) { 5530 // This method probably shouldn't have been included in the SDK to begin with. 5531 // It relies on 'a' having been initialized using an attribute filter array that is 5532 // not publicly available to the SDK. The old method has been renamed 5533 // to initializeFadingEdgeInternal and hidden for framework use only; 5534 // this one initializes using defaults to make it safe to call for apps. 5535 5536 TypedArray arr = mContext.obtainStyledAttributes(com.android.internal.R.styleable.View); 5537 5538 initializeFadingEdgeInternal(arr); 5539 5540 arr.recycle(); 5541 } 5542 5543 /** 5544 * <p> 5545 * Initializes the fading edges from a given set of styled attributes. This 5546 * method should be called by subclasses that need fading edges and when an 5547 * instance of these subclasses is created programmatically rather than 5548 * being inflated from XML. This method is automatically called when the XML 5549 * is inflated. 5550 * </p> 5551 * 5552 * @param a the styled attributes set to initialize the fading edges from 5553 * @hide This is the real method; the public one is shimmed to be safe to call from apps. 5554 */ 5555 protected void initializeFadingEdgeInternal(TypedArray a) { 5556 initScrollCache(); 5557 5558 mScrollCache.fadingEdgeLength = a.getDimensionPixelSize( 5559 R.styleable.View_fadingEdgeLength, 5560 ViewConfiguration.get(mContext).getScaledFadingEdgeLength()); 5561 } 5562 5563 /** 5564 * Returns the size of the vertical faded edges used to indicate that more 5565 * content in this view is visible. 5566 * 5567 * @return The size in pixels of the vertical faded edge or 0 if vertical 5568 * faded edges are not enabled for this view. 5569 * @attr ref android.R.styleable#View_fadingEdgeLength 5570 */ 5571 public int getVerticalFadingEdgeLength() { 5572 if (isVerticalFadingEdgeEnabled()) { 5573 ScrollabilityCache cache = mScrollCache; 5574 if (cache != null) { 5575 return cache.fadingEdgeLength; 5576 } 5577 } 5578 return 0; 5579 } 5580 5581 /** 5582 * Set the size of the faded edge used to indicate that more content in this 5583 * view is available. Will not change whether the fading edge is enabled; use 5584 * {@link #setVerticalFadingEdgeEnabled(boolean)} or 5585 * {@link #setHorizontalFadingEdgeEnabled(boolean)} to enable the fading edge 5586 * for the vertical or horizontal fading edges. 5587 * 5588 * @param length The size in pixels of the faded edge used to indicate that more 5589 * content in this view is visible. 5590 */ 5591 public void setFadingEdgeLength(int length) { 5592 initScrollCache(); 5593 mScrollCache.fadingEdgeLength = length; 5594 } 5595 5596 /** 5597 * Returns the size of the horizontal faded edges used to indicate that more 5598 * content in this view is visible. 5599 * 5600 * @return The size in pixels of the horizontal faded edge or 0 if horizontal 5601 * faded edges are not enabled for this view. 5602 * @attr ref android.R.styleable#View_fadingEdgeLength 5603 */ 5604 public int getHorizontalFadingEdgeLength() { 5605 if (isHorizontalFadingEdgeEnabled()) { 5606 ScrollabilityCache cache = mScrollCache; 5607 if (cache != null) { 5608 return cache.fadingEdgeLength; 5609 } 5610 } 5611 return 0; 5612 } 5613 5614 /** 5615 * Returns the width of the vertical scrollbar. 5616 * 5617 * @return The width in pixels of the vertical scrollbar or 0 if there 5618 * is no vertical scrollbar. 5619 */ 5620 public int getVerticalScrollbarWidth() { 5621 ScrollabilityCache cache = mScrollCache; 5622 if (cache != null) { 5623 ScrollBarDrawable scrollBar = cache.scrollBar; 5624 if (scrollBar != null) { 5625 int size = scrollBar.getSize(true); 5626 if (size <= 0) { 5627 size = cache.scrollBarSize; 5628 } 5629 return size; 5630 } 5631 return 0; 5632 } 5633 return 0; 5634 } 5635 5636 /** 5637 * Returns the height of the horizontal scrollbar. 5638 * 5639 * @return The height in pixels of the horizontal scrollbar or 0 if 5640 * there is no horizontal scrollbar. 5641 */ 5642 protected int getHorizontalScrollbarHeight() { 5643 ScrollabilityCache cache = mScrollCache; 5644 if (cache != null) { 5645 ScrollBarDrawable scrollBar = cache.scrollBar; 5646 if (scrollBar != null) { 5647 int size = scrollBar.getSize(false); 5648 if (size <= 0) { 5649 size = cache.scrollBarSize; 5650 } 5651 return size; 5652 } 5653 return 0; 5654 } 5655 return 0; 5656 } 5657 5658 /** 5659 * <p> 5660 * Initializes the scrollbars from a given set of styled attributes. This 5661 * method should be called by subclasses that need scrollbars and when an 5662 * instance of these subclasses is created programmatically rather than 5663 * being inflated from XML. This method is automatically called when the XML 5664 * is inflated. 5665 * </p> 5666 * 5667 * @param a the styled attributes set to initialize the scrollbars from 5668 * 5669 * @removed 5670 */ 5671 protected void initializeScrollbars(TypedArray a) { 5672 // It's not safe to use this method from apps. The parameter 'a' must have been obtained 5673 // using the View filter array which is not available to the SDK. As such, internal 5674 // framework usage now uses initializeScrollbarsInternal and we grab a default 5675 // TypedArray with the right filter instead here. 5676 TypedArray arr = mContext.obtainStyledAttributes(com.android.internal.R.styleable.View); 5677 5678 initializeScrollbarsInternal(arr); 5679 5680 // We ignored the method parameter. Recycle the one we actually did use. 5681 arr.recycle(); 5682 } 5683 5684 /** 5685 * <p> 5686 * Initializes the scrollbars from a given set of styled attributes. This 5687 * method should be called by subclasses that need scrollbars and when an 5688 * instance of these subclasses is created programmatically rather than 5689 * being inflated from XML. This method is automatically called when the XML 5690 * is inflated. 5691 * </p> 5692 * 5693 * @param a the styled attributes set to initialize the scrollbars from 5694 * @hide 5695 */ 5696 protected void initializeScrollbarsInternal(TypedArray a) { 5697 initScrollCache(); 5698 5699 final ScrollabilityCache scrollabilityCache = mScrollCache; 5700 5701 if (scrollabilityCache.scrollBar == null) { 5702 scrollabilityCache.scrollBar = new ScrollBarDrawable(); 5703 scrollabilityCache.scrollBar.setState(getDrawableState()); 5704 scrollabilityCache.scrollBar.setCallback(this); 5705 } 5706 5707 final boolean fadeScrollbars = a.getBoolean(R.styleable.View_fadeScrollbars, true); 5708 5709 if (!fadeScrollbars) { 5710 scrollabilityCache.state = ScrollabilityCache.ON; 5711 } 5712 scrollabilityCache.fadeScrollBars = fadeScrollbars; 5713 5714 5715 scrollabilityCache.scrollBarFadeDuration = a.getInt( 5716 R.styleable.View_scrollbarFadeDuration, ViewConfiguration 5717 .getScrollBarFadeDuration()); 5718 scrollabilityCache.scrollBarDefaultDelayBeforeFade = a.getInt( 5719 R.styleable.View_scrollbarDefaultDelayBeforeFade, 5720 ViewConfiguration.getScrollDefaultDelay()); 5721 5722 5723 scrollabilityCache.scrollBarSize = a.getDimensionPixelSize( 5724 com.android.internal.R.styleable.View_scrollbarSize, 5725 ViewConfiguration.get(mContext).getScaledScrollBarSize()); 5726 5727 Drawable track = a.getDrawable(R.styleable.View_scrollbarTrackHorizontal); 5728 scrollabilityCache.scrollBar.setHorizontalTrackDrawable(track); 5729 5730 Drawable thumb = a.getDrawable(R.styleable.View_scrollbarThumbHorizontal); 5731 if (thumb != null) { 5732 scrollabilityCache.scrollBar.setHorizontalThumbDrawable(thumb); 5733 } 5734 5735 boolean alwaysDraw = a.getBoolean(R.styleable.View_scrollbarAlwaysDrawHorizontalTrack, 5736 false); 5737 if (alwaysDraw) { 5738 scrollabilityCache.scrollBar.setAlwaysDrawHorizontalTrack(true); 5739 } 5740 5741 track = a.getDrawable(R.styleable.View_scrollbarTrackVertical); 5742 scrollabilityCache.scrollBar.setVerticalTrackDrawable(track); 5743 5744 thumb = a.getDrawable(R.styleable.View_scrollbarThumbVertical); 5745 if (thumb != null) { 5746 scrollabilityCache.scrollBar.setVerticalThumbDrawable(thumb); 5747 } 5748 5749 alwaysDraw = a.getBoolean(R.styleable.View_scrollbarAlwaysDrawVerticalTrack, 5750 false); 5751 if (alwaysDraw) { 5752 scrollabilityCache.scrollBar.setAlwaysDrawVerticalTrack(true); 5753 } 5754 5755 // Apply layout direction to the new Drawables if needed 5756 final int layoutDirection = getLayoutDirection(); 5757 if (track != null) { 5758 track.setLayoutDirection(layoutDirection); 5759 } 5760 if (thumb != null) { 5761 thumb.setLayoutDirection(layoutDirection); 5762 } 5763 5764 // Re-apply user/background padding so that scrollbar(s) get added 5765 resolvePadding(); 5766 } 5767 5768 private void initializeScrollIndicatorsInternal() { 5769 // Some day maybe we'll break this into top/left/start/etc. and let the 5770 // client control it. Until then, you can have any scroll indicator you 5771 // want as long as it's a 1dp foreground-colored rectangle. 5772 if (mScrollIndicatorDrawable == null) { 5773 mScrollIndicatorDrawable = mContext.getDrawable(R.drawable.scroll_indicator_material); 5774 } 5775 } 5776 5777 /** 5778 * <p> 5779 * Initalizes the scrollability cache if necessary. 5780 * </p> 5781 */ 5782 private void initScrollCache() { 5783 if (mScrollCache == null) { 5784 mScrollCache = new ScrollabilityCache(ViewConfiguration.get(mContext), this); 5785 } 5786 } 5787 5788 private ScrollabilityCache getScrollCache() { 5789 initScrollCache(); 5790 return mScrollCache; 5791 } 5792 5793 /** 5794 * Set the position of the vertical scroll bar. Should be one of 5795 * {@link #SCROLLBAR_POSITION_DEFAULT}, {@link #SCROLLBAR_POSITION_LEFT} or 5796 * {@link #SCROLLBAR_POSITION_RIGHT}. 5797 * 5798 * @param position Where the vertical scroll bar should be positioned. 5799 */ 5800 public void setVerticalScrollbarPosition(int position) { 5801 if (mVerticalScrollbarPosition != position) { 5802 mVerticalScrollbarPosition = position; 5803 computeOpaqueFlags(); 5804 resolvePadding(); 5805 } 5806 } 5807 5808 /** 5809 * @return The position where the vertical scroll bar will show, if applicable. 5810 * @see #setVerticalScrollbarPosition(int) 5811 */ 5812 public int getVerticalScrollbarPosition() { 5813 return mVerticalScrollbarPosition; 5814 } 5815 5816 boolean isOnScrollbar(float x, float y) { 5817 if (mScrollCache == null) { 5818 return false; 5819 } 5820 x += getScrollX(); 5821 y += getScrollY(); 5822 if (isVerticalScrollBarEnabled() && !isVerticalScrollBarHidden()) { 5823 final Rect touchBounds = mScrollCache.mScrollBarTouchBounds; 5824 getVerticalScrollBarBounds(null, touchBounds); 5825 if (touchBounds.contains((int) x, (int) y)) { 5826 return true; 5827 } 5828 } 5829 if (isHorizontalScrollBarEnabled()) { 5830 final Rect touchBounds = mScrollCache.mScrollBarTouchBounds; 5831 getHorizontalScrollBarBounds(null, touchBounds); 5832 if (touchBounds.contains((int) x, (int) y)) { 5833 return true; 5834 } 5835 } 5836 return false; 5837 } 5838 5839 boolean isOnScrollbarThumb(float x, float y) { 5840 return isOnVerticalScrollbarThumb(x, y) || isOnHorizontalScrollbarThumb(x, y); 5841 } 5842 5843 private boolean isOnVerticalScrollbarThumb(float x, float y) { 5844 if (mScrollCache == null) { 5845 return false; 5846 } 5847 if (isVerticalScrollBarEnabled() && !isVerticalScrollBarHidden()) { 5848 x += getScrollX(); 5849 y += getScrollY(); 5850 final Rect bounds = mScrollCache.mScrollBarBounds; 5851 final Rect touchBounds = mScrollCache.mScrollBarTouchBounds; 5852 getVerticalScrollBarBounds(bounds, touchBounds); 5853 final int range = computeVerticalScrollRange(); 5854 final int offset = computeVerticalScrollOffset(); 5855 final int extent = computeVerticalScrollExtent(); 5856 final int thumbLength = ScrollBarUtils.getThumbLength(bounds.height(), bounds.width(), 5857 extent, range); 5858 final int thumbOffset = ScrollBarUtils.getThumbOffset(bounds.height(), thumbLength, 5859 extent, range, offset); 5860 final int thumbTop = bounds.top + thumbOffset; 5861 final int adjust = Math.max(mScrollCache.scrollBarMinTouchTarget - thumbLength, 0) / 2; 5862 if (x >= touchBounds.left && x <= touchBounds.right 5863 && y >= thumbTop - adjust && y <= thumbTop + thumbLength + adjust) { 5864 return true; 5865 } 5866 } 5867 return false; 5868 } 5869 5870 private boolean isOnHorizontalScrollbarThumb(float x, float y) { 5871 if (mScrollCache == null) { 5872 return false; 5873 } 5874 if (isHorizontalScrollBarEnabled()) { 5875 x += getScrollX(); 5876 y += getScrollY(); 5877 final Rect bounds = mScrollCache.mScrollBarBounds; 5878 final Rect touchBounds = mScrollCache.mScrollBarTouchBounds; 5879 getHorizontalScrollBarBounds(bounds, touchBounds); 5880 final int range = computeHorizontalScrollRange(); 5881 final int offset = computeHorizontalScrollOffset(); 5882 final int extent = computeHorizontalScrollExtent(); 5883 final int thumbLength = ScrollBarUtils.getThumbLength(bounds.width(), bounds.height(), 5884 extent, range); 5885 final int thumbOffset = ScrollBarUtils.getThumbOffset(bounds.width(), thumbLength, 5886 extent, range, offset); 5887 final int thumbLeft = bounds.left + thumbOffset; 5888 final int adjust = Math.max(mScrollCache.scrollBarMinTouchTarget - thumbLength, 0) / 2; 5889 if (x >= thumbLeft - adjust && x <= thumbLeft + thumbLength + adjust 5890 && y >= touchBounds.top && y <= touchBounds.bottom) { 5891 return true; 5892 } 5893 } 5894 return false; 5895 } 5896 5897 boolean isDraggingScrollBar() { 5898 return mScrollCache != null 5899 && mScrollCache.mScrollBarDraggingState != ScrollabilityCache.NOT_DRAGGING; 5900 } 5901 5902 /** 5903 * Sets the state of all scroll indicators. 5904 * <p> 5905 * See {@link #setScrollIndicators(int, int)} for usage information. 5906 * 5907 * @param indicators a bitmask of indicators that should be enabled, or 5908 * {@code 0} to disable all indicators 5909 * @see #setScrollIndicators(int, int) 5910 * @see #getScrollIndicators() 5911 * @attr ref android.R.styleable#View_scrollIndicators 5912 */ 5913 public void setScrollIndicators(@ScrollIndicators int indicators) { 5914 setScrollIndicators(indicators, 5915 SCROLL_INDICATORS_PFLAG3_MASK >>> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT); 5916 } 5917 5918 /** 5919 * Sets the state of the scroll indicators specified by the mask. To change 5920 * all scroll indicators at once, see {@link #setScrollIndicators(int)}. 5921 * <p> 5922 * When a scroll indicator is enabled, it will be displayed if the view 5923 * can scroll in the direction of the indicator. 5924 * <p> 5925 * Multiple indicator types may be enabled or disabled by passing the 5926 * logical OR of the desired types. If multiple types are specified, they 5927 * will all be set to the same enabled state. 5928 * <p> 5929 * For example, to enable the top scroll indicatorExample: {@code setScrollIndicators 5930 * 5931 * @param indicators the indicator direction, or the logical OR of multiple 5932 * indicator directions. One or more of: 5933 * <ul> 5934 * <li>{@link #SCROLL_INDICATOR_TOP}</li> 5935 * <li>{@link #SCROLL_INDICATOR_BOTTOM}</li> 5936 * <li>{@link #SCROLL_INDICATOR_LEFT}</li> 5937 * <li>{@link #SCROLL_INDICATOR_RIGHT}</li> 5938 * <li>{@link #SCROLL_INDICATOR_START}</li> 5939 * <li>{@link #SCROLL_INDICATOR_END}</li> 5940 * </ul> 5941 * @see #setScrollIndicators(int) 5942 * @see #getScrollIndicators() 5943 * @attr ref android.R.styleable#View_scrollIndicators 5944 */ 5945 public void setScrollIndicators(@ScrollIndicators int indicators, @ScrollIndicators int mask) { 5946 // Shift and sanitize mask. 5947 mask <<= SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 5948 mask &= SCROLL_INDICATORS_PFLAG3_MASK; 5949 5950 // Shift and mask indicators. 5951 indicators <<= SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 5952 indicators &= mask; 5953 5954 // Merge with non-masked flags. 5955 final int updatedFlags = indicators | (mPrivateFlags3 & ~mask); 5956 5957 if (mPrivateFlags3 != updatedFlags) { 5958 mPrivateFlags3 = updatedFlags; 5959 5960 if (indicators != 0) { 5961 initializeScrollIndicatorsInternal(); 5962 } 5963 invalidate(); 5964 } 5965 } 5966 5967 /** 5968 * Returns a bitmask representing the enabled scroll indicators. 5969 * <p> 5970 * For example, if the top and left scroll indicators are enabled and all 5971 * other indicators are disabled, the return value will be 5972 * {@code View.SCROLL_INDICATOR_TOP | View.SCROLL_INDICATOR_LEFT}. 5973 * <p> 5974 * To check whether the bottom scroll indicator is enabled, use the value 5975 * of {@code (getScrollIndicators() & View.SCROLL_INDICATOR_BOTTOM) != 0}. 5976 * 5977 * @return a bitmask representing the enabled scroll indicators 5978 */ 5979 @ScrollIndicators 5980 public int getScrollIndicators() { 5981 return (mPrivateFlags3 & SCROLL_INDICATORS_PFLAG3_MASK) 5982 >>> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 5983 } 5984 5985 ListenerInfo getListenerInfo() { 5986 if (mListenerInfo != null) { 5987 return mListenerInfo; 5988 } 5989 mListenerInfo = new ListenerInfo(); 5990 return mListenerInfo; 5991 } 5992 5993 /** 5994 * Register a callback to be invoked when the scroll X or Y positions of 5995 * this view change. 5996 * <p> 5997 * <b>Note:</b> Some views handle scrolling independently from View and may 5998 * have their own separate listeners for scroll-type events. For example, 5999 * {@link android.widget.ListView ListView} allows clients to register an 6000 * {@link android.widget.ListView#setOnScrollListener(android.widget.AbsListView.OnScrollListener) AbsListView.OnScrollListener} 6001 * to listen for changes in list scroll position. 6002 * 6003 * @param l The listener to notify when the scroll X or Y position changes. 6004 * @see android.view.View#getScrollX() 6005 * @see android.view.View#getScrollY() 6006 */ 6007 public void setOnScrollChangeListener(OnScrollChangeListener l) { 6008 getListenerInfo().mOnScrollChangeListener = l; 6009 } 6010 6011 /** 6012 * Register a callback to be invoked when focus of this view changed. 6013 * 6014 * @param l The callback that will run. 6015 */ 6016 public void setOnFocusChangeListener(OnFocusChangeListener l) { 6017 getListenerInfo().mOnFocusChangeListener = l; 6018 } 6019 6020 /** 6021 * Add a listener that will be called when the bounds of the view change due to 6022 * layout processing. 6023 * 6024 * @param listener The listener that will be called when layout bounds change. 6025 */ 6026 public void addOnLayoutChangeListener(OnLayoutChangeListener listener) { 6027 ListenerInfo li = getListenerInfo(); 6028 if (li.mOnLayoutChangeListeners == null) { 6029 li.mOnLayoutChangeListeners = new ArrayList<OnLayoutChangeListener>(); 6030 } 6031 if (!li.mOnLayoutChangeListeners.contains(listener)) { 6032 li.mOnLayoutChangeListeners.add(listener); 6033 } 6034 } 6035 6036 /** 6037 * Remove a listener for layout changes. 6038 * 6039 * @param listener The listener for layout bounds change. 6040 */ 6041 public void removeOnLayoutChangeListener(OnLayoutChangeListener listener) { 6042 ListenerInfo li = mListenerInfo; 6043 if (li == null || li.mOnLayoutChangeListeners == null) { 6044 return; 6045 } 6046 li.mOnLayoutChangeListeners.remove(listener); 6047 } 6048 6049 /** 6050 * Add a listener for attach state changes. 6051 * 6052 * This listener will be called whenever this view is attached or detached 6053 * from a window. Remove the listener using 6054 * {@link #removeOnAttachStateChangeListener(OnAttachStateChangeListener)}. 6055 * 6056 * @param listener Listener to attach 6057 * @see #removeOnAttachStateChangeListener(OnAttachStateChangeListener) 6058 */ 6059 public void addOnAttachStateChangeListener(OnAttachStateChangeListener listener) { 6060 ListenerInfo li = getListenerInfo(); 6061 if (li.mOnAttachStateChangeListeners == null) { 6062 li.mOnAttachStateChangeListeners 6063 = new CopyOnWriteArrayList<OnAttachStateChangeListener>(); 6064 } 6065 li.mOnAttachStateChangeListeners.add(listener); 6066 } 6067 6068 /** 6069 * Remove a listener for attach state changes. The listener will receive no further 6070 * notification of window attach/detach events. 6071 * 6072 * @param listener Listener to remove 6073 * @see #addOnAttachStateChangeListener(OnAttachStateChangeListener) 6074 */ 6075 public void removeOnAttachStateChangeListener(OnAttachStateChangeListener listener) { 6076 ListenerInfo li = mListenerInfo; 6077 if (li == null || li.mOnAttachStateChangeListeners == null) { 6078 return; 6079 } 6080 li.mOnAttachStateChangeListeners.remove(listener); 6081 } 6082 6083 /** 6084 * Returns the focus-change callback registered for this view. 6085 * 6086 * @return The callback, or null if one is not registered. 6087 */ 6088 public OnFocusChangeListener getOnFocusChangeListener() { 6089 ListenerInfo li = mListenerInfo; 6090 return li != null ? li.mOnFocusChangeListener : null; 6091 } 6092 6093 /** 6094 * Register a callback to be invoked when this view is clicked. If this view is not 6095 * clickable, it becomes clickable. 6096 * 6097 * @param l The callback that will run 6098 * 6099 * @see #setClickable(boolean) 6100 */ 6101 public void setOnClickListener(@Nullable OnClickListener l) { 6102 if (!isClickable()) { 6103 setClickable(true); 6104 } 6105 getListenerInfo().mOnClickListener = l; 6106 } 6107 6108 /** 6109 * Return whether this view has an attached OnClickListener. Returns 6110 * true if there is a listener, false if there is none. 6111 */ 6112 public boolean hasOnClickListeners() { 6113 ListenerInfo li = mListenerInfo; 6114 return (li != null && li.mOnClickListener != null); 6115 } 6116 6117 /** 6118 * Register a callback to be invoked when this view is clicked and held. If this view is not 6119 * long clickable, it becomes long clickable. 6120 * 6121 * @param l The callback that will run 6122 * 6123 * @see #setLongClickable(boolean) 6124 */ 6125 public void setOnLongClickListener(@Nullable OnLongClickListener l) { 6126 if (!isLongClickable()) { 6127 setLongClickable(true); 6128 } 6129 getListenerInfo().mOnLongClickListener = l; 6130 } 6131 6132 /** 6133 * Register a callback to be invoked when this view is context clicked. If the view is not 6134 * context clickable, it becomes context clickable. 6135 * 6136 * @param l The callback that will run 6137 * @see #setContextClickable(boolean) 6138 */ 6139 public void setOnContextClickListener(@Nullable OnContextClickListener l) { 6140 if (!isContextClickable()) { 6141 setContextClickable(true); 6142 } 6143 getListenerInfo().mOnContextClickListener = l; 6144 } 6145 6146 /** 6147 * Register a callback to be invoked when the context menu for this view is 6148 * being built. If this view is not long clickable, it becomes long clickable. 6149 * 6150 * @param l The callback that will run 6151 * 6152 */ 6153 public void setOnCreateContextMenuListener(OnCreateContextMenuListener l) { 6154 if (!isLongClickable()) { 6155 setLongClickable(true); 6156 } 6157 getListenerInfo().mOnCreateContextMenuListener = l; 6158 } 6159 6160 /** 6161 * Set an observer to collect stats for each frame rendered for this view. 6162 * 6163 * @hide 6164 */ 6165 public void addFrameMetricsListener(Window window, 6166 Window.OnFrameMetricsAvailableListener listener, 6167 Handler handler) { 6168 if (mAttachInfo != null) { 6169 if (mAttachInfo.mThreadedRenderer != null) { 6170 if (mFrameMetricsObservers == null) { 6171 mFrameMetricsObservers = new ArrayList<>(); 6172 } 6173 6174 FrameMetricsObserver fmo = new FrameMetricsObserver(window, 6175 handler.getLooper(), listener); 6176 mFrameMetricsObservers.add(fmo); 6177 mAttachInfo.mThreadedRenderer.addFrameMetricsObserver(fmo); 6178 } else { 6179 Log.w(VIEW_LOG_TAG, "View not hardware-accelerated. Unable to observe frame stats"); 6180 } 6181 } else { 6182 if (mFrameMetricsObservers == null) { 6183 mFrameMetricsObservers = new ArrayList<>(); 6184 } 6185 6186 FrameMetricsObserver fmo = new FrameMetricsObserver(window, 6187 handler.getLooper(), listener); 6188 mFrameMetricsObservers.add(fmo); 6189 } 6190 } 6191 6192 /** 6193 * Remove observer configured to collect frame stats for this view. 6194 * 6195 * @hide 6196 */ 6197 public void removeFrameMetricsListener( 6198 Window.OnFrameMetricsAvailableListener listener) { 6199 ThreadedRenderer renderer = getThreadedRenderer(); 6200 FrameMetricsObserver fmo = findFrameMetricsObserver(listener); 6201 if (fmo == null) { 6202 throw new IllegalArgumentException( 6203 "attempt to remove OnFrameMetricsAvailableListener that was never added"); 6204 } 6205 6206 if (mFrameMetricsObservers != null) { 6207 mFrameMetricsObservers.remove(fmo); 6208 if (renderer != null) { 6209 renderer.removeFrameMetricsObserver(fmo); 6210 } 6211 } 6212 } 6213 6214 private void registerPendingFrameMetricsObservers() { 6215 if (mFrameMetricsObservers != null) { 6216 ThreadedRenderer renderer = getThreadedRenderer(); 6217 if (renderer != null) { 6218 for (FrameMetricsObserver fmo : mFrameMetricsObservers) { 6219 renderer.addFrameMetricsObserver(fmo); 6220 } 6221 } else { 6222 Log.w(VIEW_LOG_TAG, "View not hardware-accelerated. Unable to observe frame stats"); 6223 } 6224 } 6225 } 6226 6227 private FrameMetricsObserver findFrameMetricsObserver( 6228 Window.OnFrameMetricsAvailableListener listener) { 6229 for (int i = 0; i < mFrameMetricsObservers.size(); i++) { 6230 FrameMetricsObserver observer = mFrameMetricsObservers.get(i); 6231 if (observer.mListener == listener) { 6232 return observer; 6233 } 6234 } 6235 6236 return null; 6237 } 6238 6239 /** 6240 * Call this view's OnClickListener, if it is defined. Performs all normal 6241 * actions associated with clicking: reporting accessibility event, playing 6242 * a sound, etc. 6243 * 6244 * @return True there was an assigned OnClickListener that was called, false 6245 * otherwise is returned. 6246 */ 6247 public boolean performClick() { 6248 final boolean result; 6249 final ListenerInfo li = mListenerInfo; 6250 if (li != null && li.mOnClickListener != null) { 6251 playSoundEffect(SoundEffectConstants.CLICK); 6252 li.mOnClickListener.onClick(this); 6253 result = true; 6254 } else { 6255 result = false; 6256 } 6257 6258 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED); 6259 6260 notifyEnterOrExitForAutoFillIfNeeded(true); 6261 6262 return result; 6263 } 6264 6265 /** 6266 * Directly call any attached OnClickListener. Unlike {@link #performClick()}, 6267 * this only calls the listener, and does not do any associated clicking 6268 * actions like reporting an accessibility event. 6269 * 6270 * @return True there was an assigned OnClickListener that was called, false 6271 * otherwise is returned. 6272 */ 6273 public boolean callOnClick() { 6274 ListenerInfo li = mListenerInfo; 6275 if (li != null && li.mOnClickListener != null) { 6276 li.mOnClickListener.onClick(this); 6277 return true; 6278 } 6279 return false; 6280 } 6281 6282 /** 6283 * Calls this view's OnLongClickListener, if it is defined. Invokes the 6284 * context menu if the OnLongClickListener did not consume the event. 6285 * 6286 * @return {@code true} if one of the above receivers consumed the event, 6287 * {@code false} otherwise 6288 */ 6289 public boolean performLongClick() { 6290 return performLongClickInternal(mLongClickX, mLongClickY); 6291 } 6292 6293 /** 6294 * Calls this view's OnLongClickListener, if it is defined. Invokes the 6295 * context menu if the OnLongClickListener did not consume the event, 6296 * anchoring it to an (x,y) coordinate. 6297 * 6298 * @param x x coordinate of the anchoring touch event, or {@link Float#NaN} 6299 * to disable anchoring 6300 * @param y y coordinate of the anchoring touch event, or {@link Float#NaN} 6301 * to disable anchoring 6302 * @return {@code true} if one of the above receivers consumed the event, 6303 * {@code false} otherwise 6304 */ 6305 public boolean performLongClick(float x, float y) { 6306 mLongClickX = x; 6307 mLongClickY = y; 6308 final boolean handled = performLongClick(); 6309 mLongClickX = Float.NaN; 6310 mLongClickY = Float.NaN; 6311 return handled; 6312 } 6313 6314 /** 6315 * Calls this view's OnLongClickListener, if it is defined. Invokes the 6316 * context menu if the OnLongClickListener did not consume the event, 6317 * optionally anchoring it to an (x,y) coordinate. 6318 * 6319 * @param x x coordinate of the anchoring touch event, or {@link Float#NaN} 6320 * to disable anchoring 6321 * @param y y coordinate of the anchoring touch event, or {@link Float#NaN} 6322 * to disable anchoring 6323 * @return {@code true} if one of the above receivers consumed the event, 6324 * {@code false} otherwise 6325 */ 6326 private boolean performLongClickInternal(float x, float y) { 6327 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_LONG_CLICKED); 6328 6329 boolean handled = false; 6330 final ListenerInfo li = mListenerInfo; 6331 if (li != null && li.mOnLongClickListener != null) { 6332 handled = li.mOnLongClickListener.onLongClick(View.this); 6333 } 6334 if (!handled) { 6335 final boolean isAnchored = !Float.isNaN(x) && !Float.isNaN(y); 6336 handled = isAnchored ? showContextMenu(x, y) : showContextMenu(); 6337 } 6338 if ((mViewFlags & TOOLTIP) == TOOLTIP) { 6339 if (!handled) { 6340 handled = showLongClickTooltip((int) x, (int) y); 6341 } 6342 } 6343 if (handled) { 6344 performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); 6345 } 6346 return handled; 6347 } 6348 6349 /** 6350 * Call this view's OnContextClickListener, if it is defined. 6351 * 6352 * @param x the x coordinate of the context click 6353 * @param y the y coordinate of the context click 6354 * @return True if there was an assigned OnContextClickListener that consumed the event, false 6355 * otherwise. 6356 */ 6357 public boolean performContextClick(float x, float y) { 6358 return performContextClick(); 6359 } 6360 6361 /** 6362 * Call this view's OnContextClickListener, if it is defined. 6363 * 6364 * @return True if there was an assigned OnContextClickListener that consumed the event, false 6365 * otherwise. 6366 */ 6367 public boolean performContextClick() { 6368 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CONTEXT_CLICKED); 6369 6370 boolean handled = false; 6371 ListenerInfo li = mListenerInfo; 6372 if (li != null && li.mOnContextClickListener != null) { 6373 handled = li.mOnContextClickListener.onContextClick(View.this); 6374 } 6375 if (handled) { 6376 performHapticFeedback(HapticFeedbackConstants.CONTEXT_CLICK); 6377 } 6378 return handled; 6379 } 6380 6381 /** 6382 * Performs button-related actions during a touch down event. 6383 * 6384 * @param event The event. 6385 * @return True if the down was consumed. 6386 * 6387 * @hide 6388 */ 6389 protected boolean performButtonActionOnTouchDown(MotionEvent event) { 6390 if (event.isFromSource(InputDevice.SOURCE_MOUSE) && 6391 (event.getButtonState() & MotionEvent.BUTTON_SECONDARY) != 0) { 6392 showContextMenu(event.getX(), event.getY()); 6393 mPrivateFlags |= PFLAG_CANCEL_NEXT_UP_EVENT; 6394 return true; 6395 } 6396 return false; 6397 } 6398 6399 /** 6400 * Shows the context menu for this view. 6401 * 6402 * @return {@code true} if the context menu was shown, {@code false} 6403 * otherwise 6404 * @see #showContextMenu(float, float) 6405 */ 6406 public boolean showContextMenu() { 6407 return getParent().showContextMenuForChild(this); 6408 } 6409 6410 /** 6411 * Shows the context menu for this view anchored to the specified 6412 * view-relative coordinate. 6413 * 6414 * @param x the X coordinate in pixels relative to the view to which the 6415 * menu should be anchored, or {@link Float#NaN} to disable anchoring 6416 * @param y the Y coordinate in pixels relative to the view to which the 6417 * menu should be anchored, or {@link Float#NaN} to disable anchoring 6418 * @return {@code true} if the context menu was shown, {@code false} 6419 * otherwise 6420 */ 6421 public boolean showContextMenu(float x, float y) { 6422 return getParent().showContextMenuForChild(this, x, y); 6423 } 6424 6425 /** 6426 * Start an action mode with the default type {@link ActionMode#TYPE_PRIMARY}. 6427 * 6428 * @param callback Callback that will control the lifecycle of the action mode 6429 * @return The new action mode if it is started, null otherwise 6430 * 6431 * @see ActionMode 6432 * @see #startActionMode(android.view.ActionMode.Callback, int) 6433 */ 6434 public ActionMode startActionMode(ActionMode.Callback callback) { 6435 return startActionMode(callback, ActionMode.TYPE_PRIMARY); 6436 } 6437 6438 /** 6439 * Start an action mode with the given type. 6440 * 6441 * @param callback Callback that will control the lifecycle of the action mode 6442 * @param type One of {@link ActionMode#TYPE_PRIMARY} or {@link ActionMode#TYPE_FLOATING}. 6443 * @return The new action mode if it is started, null otherwise 6444 * 6445 * @see ActionMode 6446 */ 6447 public ActionMode startActionMode(ActionMode.Callback callback, int type) { 6448 ViewParent parent = getParent(); 6449 if (parent == null) return null; 6450 try { 6451 return parent.startActionModeForChild(this, callback, type); 6452 } catch (AbstractMethodError ame) { 6453 // Older implementations of custom views might not implement this. 6454 return parent.startActionModeForChild(this, callback); 6455 } 6456 } 6457 6458 /** 6459 * Call {@link Context#startActivityForResult(String, Intent, int, Bundle)} for the View's 6460 * Context, creating a unique View identifier to retrieve the result. 6461 * 6462 * @param intent The Intent to be started. 6463 * @param requestCode The request code to use. 6464 * @hide 6465 */ 6466 public void startActivityForResult(Intent intent, int requestCode) { 6467 mStartActivityRequestWho = "@android:view:" + System.identityHashCode(this); 6468 getContext().startActivityForResult(mStartActivityRequestWho, intent, requestCode, null); 6469 } 6470 6471 /** 6472 * If this View corresponds to the calling who, dispatches the activity result. 6473 * @param who The identifier for the targeted View to receive the result. 6474 * @param requestCode The integer request code originally supplied to 6475 * startActivityForResult(), allowing you to identify who this 6476 * result came from. 6477 * @param resultCode The integer result code returned by the child activity 6478 * through its setResult(). 6479 * @param data An Intent, which can return result data to the caller 6480 * (various data can be attached to Intent "extras"). 6481 * @return {@code true} if the activity result was dispatched. 6482 * @hide 6483 */ 6484 public boolean dispatchActivityResult( 6485 String who, int requestCode, int resultCode, Intent data) { 6486 if (mStartActivityRequestWho != null && mStartActivityRequestWho.equals(who)) { 6487 onActivityResult(requestCode, resultCode, data); 6488 mStartActivityRequestWho = null; 6489 return true; 6490 } 6491 return false; 6492 } 6493 6494 /** 6495 * Receive the result from a previous call to {@link #startActivityForResult(Intent, int)}. 6496 * 6497 * @param requestCode The integer request code originally supplied to 6498 * startActivityForResult(), allowing you to identify who this 6499 * result came from. 6500 * @param resultCode The integer result code returned by the child activity 6501 * through its setResult(). 6502 * @param data An Intent, which can return result data to the caller 6503 * (various data can be attached to Intent "extras"). 6504 * @hide 6505 */ 6506 public void onActivityResult(int requestCode, int resultCode, Intent data) { 6507 // Do nothing. 6508 } 6509 6510 /** 6511 * Register a callback to be invoked when a hardware key is pressed in this view. 6512 * Key presses in software input methods will generally not trigger the methods of 6513 * this listener. 6514 * @param l the key listener to attach to this view 6515 */ 6516 public void setOnKeyListener(OnKeyListener l) { 6517 getListenerInfo().mOnKeyListener = l; 6518 } 6519 6520 /** 6521 * Register a callback to be invoked when a touch event is sent to this view. 6522 * @param l the touch listener to attach to this view 6523 */ 6524 public void setOnTouchListener(OnTouchListener l) { 6525 getListenerInfo().mOnTouchListener = l; 6526 } 6527 6528 /** 6529 * Register a callback to be invoked when a generic motion event is sent to this view. 6530 * @param l the generic motion listener to attach to this view 6531 */ 6532 public void setOnGenericMotionListener(OnGenericMotionListener l) { 6533 getListenerInfo().mOnGenericMotionListener = l; 6534 } 6535 6536 /** 6537 * Register a callback to be invoked when a hover event is sent to this view. 6538 * @param l the hover listener to attach to this view 6539 */ 6540 public void setOnHoverListener(OnHoverListener l) { 6541 getListenerInfo().mOnHoverListener = l; 6542 } 6543 6544 /** 6545 * Register a drag event listener callback object for this View. The parameter is 6546 * an implementation of {@link android.view.View.OnDragListener}. To send a drag event to a 6547 * View, the system calls the 6548 * {@link android.view.View.OnDragListener#onDrag(View,DragEvent)} method. 6549 * @param l An implementation of {@link android.view.View.OnDragListener}. 6550 */ 6551 public void setOnDragListener(OnDragListener l) { 6552 getListenerInfo().mOnDragListener = l; 6553 } 6554 6555 /** 6556 * Give this view focus. This will cause 6557 * {@link #onFocusChanged(boolean, int, android.graphics.Rect)} to be called. 6558 * 6559 * Note: this does not check whether this {@link View} should get focus, it just 6560 * gives it focus no matter what. It should only be called internally by framework 6561 * code that knows what it is doing, namely {@link #requestFocus(int, Rect)}. 6562 * 6563 * @param direction values are {@link View#FOCUS_UP}, {@link View#FOCUS_DOWN}, 6564 * {@link View#FOCUS_LEFT} or {@link View#FOCUS_RIGHT}. This is the direction which 6565 * focus moved when requestFocus() is called. It may not always 6566 * apply, in which case use the default View.FOCUS_DOWN. 6567 * @param previouslyFocusedRect The rectangle of the view that had focus 6568 * prior in this View's coordinate system. 6569 */ 6570 void handleFocusGainInternal(@FocusRealDirection int direction, Rect previouslyFocusedRect) { 6571 if (DBG) { 6572 System.out.println(this + " requestFocus()"); 6573 } 6574 6575 if ((mPrivateFlags & PFLAG_FOCUSED) == 0) { 6576 mPrivateFlags |= PFLAG_FOCUSED; 6577 6578 View oldFocus = (mAttachInfo != null) ? getRootView().findFocus() : null; 6579 6580 if (mParent != null) { 6581 mParent.requestChildFocus(this, this); 6582 updateFocusedInCluster(oldFocus, direction); 6583 } 6584 6585 if (mAttachInfo != null) { 6586 mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(oldFocus, this); 6587 } 6588 6589 onFocusChanged(true, direction, previouslyFocusedRect); 6590 refreshDrawableState(); 6591 } 6592 } 6593 6594 /** 6595 * Sets this view's preference for reveal behavior when it gains focus. 6596 * 6597 * <p>When set to true, this is a signal to ancestor views in the hierarchy that 6598 * this view would prefer to be brought fully into view when it gains focus. 6599 * For example, a text field that a user is meant to type into. Other views such 6600 * as scrolling containers may prefer to opt-out of this behavior.</p> 6601 * 6602 * <p>The default value for views is true, though subclasses may change this 6603 * based on their preferred behavior.</p> 6604 * 6605 * @param revealOnFocus true to request reveal on focus in ancestors, false otherwise 6606 * 6607 * @see #getRevealOnFocusHint() 6608 */ 6609 public final void setRevealOnFocusHint(boolean revealOnFocus) { 6610 if (revealOnFocus) { 6611 mPrivateFlags3 &= ~PFLAG3_NO_REVEAL_ON_FOCUS; 6612 } else { 6613 mPrivateFlags3 |= PFLAG3_NO_REVEAL_ON_FOCUS; 6614 } 6615 } 6616 6617 /** 6618 * Returns this view's preference for reveal behavior when it gains focus. 6619 * 6620 * <p>When this method returns true for a child view requesting focus, ancestor 6621 * views responding to a focus change in {@link ViewParent#requestChildFocus(View, View)} 6622 * should make a best effort to make the newly focused child fully visible to the user. 6623 * When it returns false, ancestor views should preferably not disrupt scroll positioning or 6624 * other properties affecting visibility to the user as part of the focus change.</p> 6625 * 6626 * @return true if this view would prefer to become fully visible when it gains focus, 6627 * false if it would prefer not to disrupt scroll positioning 6628 * 6629 * @see #setRevealOnFocusHint(boolean) 6630 */ 6631 public final boolean getRevealOnFocusHint() { 6632 return (mPrivateFlags3 & PFLAG3_NO_REVEAL_ON_FOCUS) == 0; 6633 } 6634 6635 /** 6636 * Populates <code>outRect</code> with the hotspot bounds. By default, 6637 * the hotspot bounds are identical to the screen bounds. 6638 * 6639 * @param outRect rect to populate with hotspot bounds 6640 * @hide Only for internal use by views and widgets. 6641 */ 6642 public void getHotspotBounds(Rect outRect) { 6643 final Drawable background = getBackground(); 6644 if (background != null) { 6645 background.getHotspotBounds(outRect); 6646 } else { 6647 getBoundsOnScreen(outRect); 6648 } 6649 } 6650 6651 /** 6652 * Request that a rectangle of this view be visible on the screen, 6653 * scrolling if necessary just enough. 6654 * 6655 * <p>A View should call this if it maintains some notion of which part 6656 * of its content is interesting. For example, a text editing view 6657 * should call this when its cursor moves. 6658 * <p>The Rectangle passed into this method should be in the View's content coordinate space. 6659 * It should not be affected by which part of the View is currently visible or its scroll 6660 * position. 6661 * 6662 * @param rectangle The rectangle in the View's content coordinate space 6663 * @return Whether any parent scrolled. 6664 */ 6665 public boolean requestRectangleOnScreen(Rect rectangle) { 6666 return requestRectangleOnScreen(rectangle, false); 6667 } 6668 6669 /** 6670 * Request that a rectangle of this view be visible on the screen, 6671 * scrolling if necessary just enough. 6672 * 6673 * <p>A View should call this if it maintains some notion of which part 6674 * of its content is interesting. For example, a text editing view 6675 * should call this when its cursor moves. 6676 * <p>The Rectangle passed into this method should be in the View's content coordinate space. 6677 * It should not be affected by which part of the View is currently visible or its scroll 6678 * position. 6679 * <p>When <code>immediate</code> is set to true, scrolling will not be 6680 * animated. 6681 * 6682 * @param rectangle The rectangle in the View's content coordinate space 6683 * @param immediate True to forbid animated scrolling, false otherwise 6684 * @return Whether any parent scrolled. 6685 */ 6686 public boolean requestRectangleOnScreen(Rect rectangle, boolean immediate) { 6687 if (mParent == null) { 6688 return false; 6689 } 6690 6691 View child = this; 6692 6693 RectF position = (mAttachInfo != null) ? mAttachInfo.mTmpTransformRect : new RectF(); 6694 position.set(rectangle); 6695 6696 ViewParent parent = mParent; 6697 boolean scrolled = false; 6698 while (parent != null) { 6699 rectangle.set((int) position.left, (int) position.top, 6700 (int) position.right, (int) position.bottom); 6701 6702 scrolled |= parent.requestChildRectangleOnScreen(child, rectangle, immediate); 6703 6704 if (!(parent instanceof View)) { 6705 break; 6706 } 6707 6708 // move it from child's content coordinate space to parent's content coordinate space 6709 position.offset(child.mLeft - child.getScrollX(), child.mTop -child.getScrollY()); 6710 6711 child = (View) parent; 6712 parent = child.getParent(); 6713 } 6714 6715 return scrolled; 6716 } 6717 6718 /** 6719 * Called when this view wants to give up focus. If focus is cleared 6720 * {@link #onFocusChanged(boolean, int, android.graphics.Rect)} is called. 6721 * <p> 6722 * <strong>Note:</strong> When a View clears focus the framework is trying 6723 * to give focus to the first focusable View from the top. Hence, if this 6724 * View is the first from the top that can take focus, then all callbacks 6725 * related to clearing focus will be invoked after which the framework will 6726 * give focus to this view. 6727 * </p> 6728 */ 6729 public void clearFocus() { 6730 if (DBG) { 6731 System.out.println(this + " clearFocus()"); 6732 } 6733 6734 clearFocusInternal(null, true, true); 6735 } 6736 6737 /** 6738 * Clears focus from the view, optionally propagating the change up through 6739 * the parent hierarchy and requesting that the root view place new focus. 6740 * 6741 * @param propagate whether to propagate the change up through the parent 6742 * hierarchy 6743 * @param refocus when propagate is true, specifies whether to request the 6744 * root view place new focus 6745 */ 6746 void clearFocusInternal(View focused, boolean propagate, boolean refocus) { 6747 if ((mPrivateFlags & PFLAG_FOCUSED) != 0) { 6748 mPrivateFlags &= ~PFLAG_FOCUSED; 6749 6750 if (propagate && mParent != null) { 6751 mParent.clearChildFocus(this); 6752 } 6753 6754 onFocusChanged(false, 0, null); 6755 refreshDrawableState(); 6756 6757 if (propagate && (!refocus || !rootViewRequestFocus())) { 6758 notifyGlobalFocusCleared(this); 6759 } 6760 } 6761 } 6762 6763 void notifyGlobalFocusCleared(View oldFocus) { 6764 if (oldFocus != null && mAttachInfo != null) { 6765 mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(oldFocus, null); 6766 } 6767 } 6768 6769 boolean rootViewRequestFocus() { 6770 final View root = getRootView(); 6771 return root != null && root.requestFocus(); 6772 } 6773 6774 /** 6775 * Called internally by the view system when a new view is getting focus. 6776 * This is what clears the old focus. 6777 * <p> 6778 * <b>NOTE:</b> The parent view's focused child must be updated manually 6779 * after calling this method. Otherwise, the view hierarchy may be left in 6780 * an inconstent state. 6781 */ 6782 void unFocus(View focused) { 6783 if (DBG) { 6784 System.out.println(this + " unFocus()"); 6785 } 6786 6787 clearFocusInternal(focused, false, false); 6788 } 6789 6790 /** 6791 * Returns true if this view has focus itself, or is the ancestor of the 6792 * view that has focus. 6793 * 6794 * @return True if this view has or contains focus, false otherwise. 6795 */ 6796 @ViewDebug.ExportedProperty(category = "focus") 6797 public boolean hasFocus() { 6798 return (mPrivateFlags & PFLAG_FOCUSED) != 0; 6799 } 6800 6801 /** 6802 * Returns true if this view is focusable or if it contains a reachable View 6803 * for which {@link #hasFocusable()} returns {@code true}. A "reachable hasFocusable()" 6804 * is a view whose parents do not block descendants focus. 6805 * Only {@link #VISIBLE} views are considered focusable. 6806 * 6807 * <p>As of {@link Build.VERSION_CODES#O} views that are determined to be focusable 6808 * through {@link #FOCUSABLE_AUTO} will also cause this method to return {@code true}. 6809 * Apps that declare a {@link android.content.pm.ApplicationInfo#targetSdkVersion} of 6810 * earlier than {@link Build.VERSION_CODES#O} will continue to see this method return 6811 * {@code false} for views not explicitly marked as focusable. 6812 * Use {@link #hasExplicitFocusable()} if you require the pre-{@link Build.VERSION_CODES#O} 6813 * behavior.</p> 6814 * 6815 * @return {@code true} if the view is focusable or if the view contains a focusable 6816 * view, {@code false} otherwise 6817 * 6818 * @see ViewGroup#FOCUS_BLOCK_DESCENDANTS 6819 * @see ViewGroup#getTouchscreenBlocksFocus() 6820 * @see #hasExplicitFocusable() 6821 */ 6822 public boolean hasFocusable() { 6823 return hasFocusable(!sHasFocusableExcludeAutoFocusable, false); 6824 } 6825 6826 /** 6827 * Returns true if this view is focusable or if it contains a reachable View 6828 * for which {@link #hasExplicitFocusable()} returns {@code true}. 6829 * A "reachable hasExplicitFocusable()" is a view whose parents do not block descendants focus. 6830 * Only {@link #VISIBLE} views for which {@link #getFocusable()} would return 6831 * {@link #FOCUSABLE} are considered focusable. 6832 * 6833 * <p>This method preserves the pre-{@link Build.VERSION_CODES#O} behavior of 6834 * {@link #hasFocusable()} in that only views explicitly set focusable will cause 6835 * this method to return true. A view set to {@link #FOCUSABLE_AUTO} that resolves 6836 * to focusable will not.</p> 6837 * 6838 * @return {@code true} if the view is focusable or if the view contains a focusable 6839 * view, {@code false} otherwise 6840 * 6841 * @see #hasFocusable() 6842 */ 6843 public boolean hasExplicitFocusable() { 6844 return hasFocusable(false, true); 6845 } 6846 6847 boolean hasFocusable(boolean allowAutoFocus, boolean dispatchExplicit) { 6848 if (!isFocusableInTouchMode()) { 6849 for (ViewParent p = mParent; p instanceof ViewGroup; p = p.getParent()) { 6850 final ViewGroup g = (ViewGroup) p; 6851 if (g.shouldBlockFocusForTouchscreen()) { 6852 return false; 6853 } 6854 } 6855 } 6856 6857 // Invisible and gone views are never focusable. 6858 if ((mViewFlags & VISIBILITY_MASK) != VISIBLE) { 6859 return false; 6860 } 6861 6862 // Only use effective focusable value when allowed. 6863 if ((allowAutoFocus || getFocusable() != FOCUSABLE_AUTO) && isFocusable()) { 6864 return true; 6865 } 6866 6867 return false; 6868 } 6869 6870 /** 6871 * Called by the view system when the focus state of this view changes. 6872 * When the focus change event is caused by directional navigation, direction 6873 * and previouslyFocusedRect provide insight into where the focus is coming from. 6874 * When overriding, be sure to call up through to the super class so that 6875 * the standard focus handling will occur. 6876 * 6877 * @param gainFocus True if the View has focus; false otherwise. 6878 * @param direction The direction focus has moved when requestFocus() 6879 * is called to give this view focus. Values are 6880 * {@link #FOCUS_UP}, {@link #FOCUS_DOWN}, {@link #FOCUS_LEFT}, 6881 * {@link #FOCUS_RIGHT}, {@link #FOCUS_FORWARD}, or {@link #FOCUS_BACKWARD}. 6882 * It may not always apply, in which case use the default. 6883 * @param previouslyFocusedRect The rectangle, in this view's coordinate 6884 * system, of the previously focused view. If applicable, this will be 6885 * passed in as finer grained information about where the focus is coming 6886 * from (in addition to direction). Will be <code>null</code> otherwise. 6887 */ 6888 @CallSuper 6889 protected void onFocusChanged(boolean gainFocus, @FocusDirection int direction, 6890 @Nullable Rect previouslyFocusedRect) { 6891 if (gainFocus) { 6892 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED); 6893 } else { 6894 notifyViewAccessibilityStateChangedIfNeeded( 6895 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 6896 } 6897 6898 // Here we check whether we still need the default focus highlight, and switch it on/off. 6899 switchDefaultFocusHighlight(); 6900 6901 InputMethodManager imm = InputMethodManager.peekInstance(); 6902 if (!gainFocus) { 6903 if (isPressed()) { 6904 setPressed(false); 6905 } 6906 if (imm != null && mAttachInfo != null && mAttachInfo.mHasWindowFocus) { 6907 imm.focusOut(this); 6908 } 6909 onFocusLost(); 6910 } else if (imm != null && mAttachInfo != null && mAttachInfo.mHasWindowFocus) { 6911 imm.focusIn(this); 6912 } 6913 6914 invalidate(true); 6915 ListenerInfo li = mListenerInfo; 6916 if (li != null && li.mOnFocusChangeListener != null) { 6917 li.mOnFocusChangeListener.onFocusChange(this, gainFocus); 6918 } 6919 6920 if (mAttachInfo != null) { 6921 mAttachInfo.mKeyDispatchState.reset(this); 6922 } 6923 6924 notifyEnterOrExitForAutoFillIfNeeded(gainFocus); 6925 } 6926 6927 private void notifyEnterOrExitForAutoFillIfNeeded(boolean enter) { 6928 if (isAutofillable() && isAttachedToWindow()) { 6929 AutofillManager afm = getAutofillManager(); 6930 if (afm != null) { 6931 if (enter && hasWindowFocus() && isFocused()) { 6932 // We have not been laid out yet, hence cannot evaluate 6933 // whether this view is visible to the user, we will do 6934 // the evaluation once layout is complete. 6935 if (!isLaidOut()) { 6936 mPrivateFlags3 |= PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT; 6937 } else if (isVisibleToUser()) { 6938 afm.notifyViewEntered(this); 6939 } 6940 } else if (!hasWindowFocus() || !isFocused()) { 6941 afm.notifyViewExited(this); 6942 } 6943 } 6944 } 6945 } 6946 6947 /** 6948 * Sends an accessibility event of the given type. If accessibility is 6949 * not enabled this method has no effect. The default implementation calls 6950 * {@link #onInitializeAccessibilityEvent(AccessibilityEvent)} first 6951 * to populate information about the event source (this View), then calls 6952 * {@link #dispatchPopulateAccessibilityEvent(AccessibilityEvent)} to 6953 * populate the text content of the event source including its descendants, 6954 * and last calls 6955 * {@link ViewParent#requestSendAccessibilityEvent(View, AccessibilityEvent)} 6956 * on its parent to request sending of the event to interested parties. 6957 * <p> 6958 * If an {@link AccessibilityDelegate} has been specified via calling 6959 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 6960 * {@link AccessibilityDelegate#sendAccessibilityEvent(View, int)} is 6961 * responsible for handling this call. 6962 * </p> 6963 * 6964 * @param eventType The type of the event to send, as defined by several types from 6965 * {@link android.view.accessibility.AccessibilityEvent}, such as 6966 * {@link android.view.accessibility.AccessibilityEvent#TYPE_VIEW_CLICKED} or 6967 * {@link android.view.accessibility.AccessibilityEvent#TYPE_VIEW_HOVER_ENTER}. 6968 * 6969 * @see #onInitializeAccessibilityEvent(AccessibilityEvent) 6970 * @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent) 6971 * @see ViewParent#requestSendAccessibilityEvent(View, AccessibilityEvent) 6972 * @see AccessibilityDelegate 6973 */ 6974 public void sendAccessibilityEvent(int eventType) { 6975 if (mAccessibilityDelegate != null) { 6976 mAccessibilityDelegate.sendAccessibilityEvent(this, eventType); 6977 } else { 6978 sendAccessibilityEventInternal(eventType); 6979 } 6980 } 6981 6982 /** 6983 * Convenience method for sending a {@link AccessibilityEvent#TYPE_ANNOUNCEMENT} 6984 * {@link AccessibilityEvent} to make an announcement which is related to some 6985 * sort of a context change for which none of the events representing UI transitions 6986 * is a good fit. For example, announcing a new page in a book. If accessibility 6987 * is not enabled this method does nothing. 6988 * 6989 * @param text The announcement text. 6990 */ 6991 public void announceForAccessibility(CharSequence text) { 6992 if (AccessibilityManager.getInstance(mContext).isEnabled() && mParent != null) { 6993 AccessibilityEvent event = AccessibilityEvent.obtain( 6994 AccessibilityEvent.TYPE_ANNOUNCEMENT); 6995 onInitializeAccessibilityEvent(event); 6996 event.getText().add(text); 6997 event.setContentDescription(null); 6998 mParent.requestSendAccessibilityEvent(this, event); 6999 } 7000 } 7001 7002 /** 7003 * @see #sendAccessibilityEvent(int) 7004 * 7005 * Note: Called from the default {@link AccessibilityDelegate}. 7006 * 7007 * @hide 7008 */ 7009 public void sendAccessibilityEventInternal(int eventType) { 7010 if (AccessibilityManager.getInstance(mContext).isEnabled()) { 7011 sendAccessibilityEventUnchecked(AccessibilityEvent.obtain(eventType)); 7012 } 7013 } 7014 7015 /** 7016 * This method behaves exactly as {@link #sendAccessibilityEvent(int)} but 7017 * takes as an argument an empty {@link AccessibilityEvent} and does not 7018 * perform a check whether accessibility is enabled. 7019 * <p> 7020 * If an {@link AccessibilityDelegate} has been specified via calling 7021 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 7022 * {@link AccessibilityDelegate#sendAccessibilityEventUnchecked(View, AccessibilityEvent)} 7023 * is responsible for handling this call. 7024 * </p> 7025 * 7026 * @param event The event to send. 7027 * 7028 * @see #sendAccessibilityEvent(int) 7029 */ 7030 public void sendAccessibilityEventUnchecked(AccessibilityEvent event) { 7031 if (mAccessibilityDelegate != null) { 7032 mAccessibilityDelegate.sendAccessibilityEventUnchecked(this, event); 7033 } else { 7034 sendAccessibilityEventUncheckedInternal(event); 7035 } 7036 } 7037 7038 /** 7039 * @see #sendAccessibilityEventUnchecked(AccessibilityEvent) 7040 * 7041 * Note: Called from the default {@link AccessibilityDelegate}. 7042 * 7043 * @hide 7044 */ 7045 public void sendAccessibilityEventUncheckedInternal(AccessibilityEvent event) { 7046 if (!isShown()) { 7047 return; 7048 } 7049 onInitializeAccessibilityEvent(event); 7050 // Only a subset of accessibility events populates text content. 7051 if ((event.getEventType() & POPULATING_ACCESSIBILITY_EVENT_TYPES) != 0) { 7052 dispatchPopulateAccessibilityEvent(event); 7053 } 7054 // In the beginning we called #isShown(), so we know that getParent() is not null. 7055 ViewParent parent = getParent(); 7056 if (parent != null) { 7057 getParent().requestSendAccessibilityEvent(this, event); 7058 } 7059 } 7060 7061 /** 7062 * Dispatches an {@link AccessibilityEvent} to the {@link View} first and then 7063 * to its children for adding their text content to the event. Note that the 7064 * event text is populated in a separate dispatch path since we add to the 7065 * event not only the text of the source but also the text of all its descendants. 7066 * A typical implementation will call 7067 * {@link #onPopulateAccessibilityEvent(AccessibilityEvent)} on the this view 7068 * and then call the {@link #dispatchPopulateAccessibilityEvent(AccessibilityEvent)} 7069 * on each child. Override this method if custom population of the event text 7070 * content is required. 7071 * <p> 7072 * If an {@link AccessibilityDelegate} has been specified via calling 7073 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 7074 * {@link AccessibilityDelegate#dispatchPopulateAccessibilityEvent(View, AccessibilityEvent)} 7075 * is responsible for handling this call. 7076 * </p> 7077 * <p> 7078 * <em>Note:</em> Accessibility events of certain types are not dispatched for 7079 * populating the event text via this method. For details refer to {@link AccessibilityEvent}. 7080 * </p> 7081 * 7082 * @param event The event. 7083 * 7084 * @return True if the event population was completed. 7085 */ 7086 public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) { 7087 if (mAccessibilityDelegate != null) { 7088 return mAccessibilityDelegate.dispatchPopulateAccessibilityEvent(this, event); 7089 } else { 7090 return dispatchPopulateAccessibilityEventInternal(event); 7091 } 7092 } 7093 7094 /** 7095 * @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent) 7096 * 7097 * Note: Called from the default {@link AccessibilityDelegate}. 7098 * 7099 * @hide 7100 */ 7101 public boolean dispatchPopulateAccessibilityEventInternal(AccessibilityEvent event) { 7102 onPopulateAccessibilityEvent(event); 7103 return false; 7104 } 7105 7106 /** 7107 * Called from {@link #dispatchPopulateAccessibilityEvent(AccessibilityEvent)} 7108 * giving a chance to this View to populate the accessibility event with its 7109 * text content. While this method is free to modify event 7110 * attributes other than text content, doing so should normally be performed in 7111 * {@link #onInitializeAccessibilityEvent(AccessibilityEvent)}. 7112 * <p> 7113 * Example: Adding formatted date string to an accessibility event in addition 7114 * to the text added by the super implementation: 7115 * <pre> public void onPopulateAccessibilityEvent(AccessibilityEvent event) { 7116 * super.onPopulateAccessibilityEvent(event); 7117 * final int flags = DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_WEEKDAY; 7118 * String selectedDateUtterance = DateUtils.formatDateTime(mContext, 7119 * mCurrentDate.getTimeInMillis(), flags); 7120 * event.getText().add(selectedDateUtterance); 7121 * }</pre> 7122 * <p> 7123 * If an {@link AccessibilityDelegate} has been specified via calling 7124 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 7125 * {@link AccessibilityDelegate#onPopulateAccessibilityEvent(View, AccessibilityEvent)} 7126 * is responsible for handling this call. 7127 * </p> 7128 * <p class="note"><strong>Note:</strong> Always call the super implementation before adding 7129 * information to the event, in case the default implementation has basic information to add. 7130 * </p> 7131 * 7132 * @param event The accessibility event which to populate. 7133 * 7134 * @see #sendAccessibilityEvent(int) 7135 * @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent) 7136 */ 7137 @CallSuper 7138 public void onPopulateAccessibilityEvent(AccessibilityEvent event) { 7139 if (mAccessibilityDelegate != null) { 7140 mAccessibilityDelegate.onPopulateAccessibilityEvent(this, event); 7141 } else { 7142 onPopulateAccessibilityEventInternal(event); 7143 } 7144 } 7145 7146 /** 7147 * @see #onPopulateAccessibilityEvent(AccessibilityEvent) 7148 * 7149 * Note: Called from the default {@link AccessibilityDelegate}. 7150 * 7151 * @hide 7152 */ 7153 public void onPopulateAccessibilityEventInternal(AccessibilityEvent event) { 7154 } 7155 7156 /** 7157 * Initializes an {@link AccessibilityEvent} with information about 7158 * this View which is the event source. In other words, the source of 7159 * an accessibility event is the view whose state change triggered firing 7160 * the event. 7161 * <p> 7162 * Example: Setting the password property of an event in addition 7163 * to properties set by the super implementation: 7164 * <pre> public void onInitializeAccessibilityEvent(AccessibilityEvent event) { 7165 * super.onInitializeAccessibilityEvent(event); 7166 * event.setPassword(true); 7167 * }</pre> 7168 * <p> 7169 * If an {@link AccessibilityDelegate} has been specified via calling 7170 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 7171 * {@link AccessibilityDelegate#onInitializeAccessibilityEvent(View, AccessibilityEvent)} 7172 * is responsible for handling this call. 7173 * </p> 7174 * <p class="note"><strong>Note:</strong> Always call the super implementation before adding 7175 * information to the event, in case the default implementation has basic information to add. 7176 * </p> 7177 * @param event The event to initialize. 7178 * 7179 * @see #sendAccessibilityEvent(int) 7180 * @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent) 7181 */ 7182 @CallSuper 7183 public void onInitializeAccessibilityEvent(AccessibilityEvent event) { 7184 if (mAccessibilityDelegate != null) { 7185 mAccessibilityDelegate.onInitializeAccessibilityEvent(this, event); 7186 } else { 7187 onInitializeAccessibilityEventInternal(event); 7188 } 7189 } 7190 7191 /** 7192 * @see #onInitializeAccessibilityEvent(AccessibilityEvent) 7193 * 7194 * Note: Called from the default {@link AccessibilityDelegate}. 7195 * 7196 * @hide 7197 */ 7198 public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) { 7199 event.setSource(this); 7200 event.setClassName(getAccessibilityClassName()); 7201 event.setPackageName(getContext().getPackageName()); 7202 event.setEnabled(isEnabled()); 7203 event.setContentDescription(mContentDescription); 7204 7205 switch (event.getEventType()) { 7206 case AccessibilityEvent.TYPE_VIEW_FOCUSED: { 7207 ArrayList<View> focusablesTempList = (mAttachInfo != null) 7208 ? mAttachInfo.mTempArrayList : new ArrayList<View>(); 7209 getRootView().addFocusables(focusablesTempList, View.FOCUS_FORWARD, FOCUSABLES_ALL); 7210 event.setItemCount(focusablesTempList.size()); 7211 event.setCurrentItemIndex(focusablesTempList.indexOf(this)); 7212 if (mAttachInfo != null) { 7213 focusablesTempList.clear(); 7214 } 7215 } break; 7216 case AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED: { 7217 CharSequence text = getIterableTextForAccessibility(); 7218 if (text != null && text.length() > 0) { 7219 event.setFromIndex(getAccessibilitySelectionStart()); 7220 event.setToIndex(getAccessibilitySelectionEnd()); 7221 event.setItemCount(text.length()); 7222 } 7223 } break; 7224 } 7225 } 7226 7227 /** 7228 * Returns an {@link AccessibilityNodeInfo} representing this view from the 7229 * point of view of an {@link android.accessibilityservice.AccessibilityService}. 7230 * This method is responsible for obtaining an accessibility node info from a 7231 * pool of reusable instances and calling 7232 * {@link #onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} on this view to 7233 * initialize the former. 7234 * <p> 7235 * Note: The client is responsible for recycling the obtained instance by calling 7236 * {@link AccessibilityNodeInfo#recycle()} to minimize object creation. 7237 * </p> 7238 * 7239 * @return A populated {@link AccessibilityNodeInfo}. 7240 * 7241 * @see AccessibilityNodeInfo 7242 */ 7243 public AccessibilityNodeInfo createAccessibilityNodeInfo() { 7244 if (mAccessibilityDelegate != null) { 7245 return mAccessibilityDelegate.createAccessibilityNodeInfo(this); 7246 } else { 7247 return createAccessibilityNodeInfoInternal(); 7248 } 7249 } 7250 7251 /** 7252 * @see #createAccessibilityNodeInfo() 7253 * 7254 * @hide 7255 */ 7256 public AccessibilityNodeInfo createAccessibilityNodeInfoInternal() { 7257 AccessibilityNodeProvider provider = getAccessibilityNodeProvider(); 7258 if (provider != null) { 7259 return provider.createAccessibilityNodeInfo(AccessibilityNodeProvider.HOST_VIEW_ID); 7260 } else { 7261 AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain(this); 7262 onInitializeAccessibilityNodeInfo(info); 7263 return info; 7264 } 7265 } 7266 7267 /** 7268 * Initializes an {@link AccessibilityNodeInfo} with information about this view. 7269 * The base implementation sets: 7270 * <ul> 7271 * <li>{@link AccessibilityNodeInfo#setParent(View)},</li> 7272 * <li>{@link AccessibilityNodeInfo#setBoundsInParent(Rect)},</li> 7273 * <li>{@link AccessibilityNodeInfo#setBoundsInScreen(Rect)},</li> 7274 * <li>{@link AccessibilityNodeInfo#setPackageName(CharSequence)},</li> 7275 * <li>{@link AccessibilityNodeInfo#setClassName(CharSequence)},</li> 7276 * <li>{@link AccessibilityNodeInfo#setContentDescription(CharSequence)},</li> 7277 * <li>{@link AccessibilityNodeInfo#setEnabled(boolean)},</li> 7278 * <li>{@link AccessibilityNodeInfo#setClickable(boolean)},</li> 7279 * <li>{@link AccessibilityNodeInfo#setFocusable(boolean)},</li> 7280 * <li>{@link AccessibilityNodeInfo#setFocused(boolean)},</li> 7281 * <li>{@link AccessibilityNodeInfo#setLongClickable(boolean)},</li> 7282 * <li>{@link AccessibilityNodeInfo#setSelected(boolean)},</li> 7283 * <li>{@link AccessibilityNodeInfo#setContextClickable(boolean)}</li> 7284 * </ul> 7285 * <p> 7286 * Subclasses should override this method, call the super implementation, 7287 * and set additional attributes. 7288 * </p> 7289 * <p> 7290 * If an {@link AccessibilityDelegate} has been specified via calling 7291 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 7292 * {@link AccessibilityDelegate#onInitializeAccessibilityNodeInfo(View, AccessibilityNodeInfo)} 7293 * is responsible for handling this call. 7294 * </p> 7295 * 7296 * @param info The instance to initialize. 7297 */ 7298 @CallSuper 7299 public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { 7300 if (mAccessibilityDelegate != null) { 7301 mAccessibilityDelegate.onInitializeAccessibilityNodeInfo(this, info); 7302 } else { 7303 onInitializeAccessibilityNodeInfoInternal(info); 7304 } 7305 } 7306 7307 /** 7308 * Gets the location of this view in screen coordinates. 7309 * 7310 * @param outRect The output location 7311 * @hide 7312 */ 7313 public void getBoundsOnScreen(Rect outRect) { 7314 getBoundsOnScreen(outRect, false); 7315 } 7316 7317 /** 7318 * Gets the location of this view in screen coordinates. 7319 * 7320 * @param outRect The output location 7321 * @param clipToParent Whether to clip child bounds to the parent ones. 7322 * @hide 7323 */ 7324 public void getBoundsOnScreen(Rect outRect, boolean clipToParent) { 7325 if (mAttachInfo == null) { 7326 return; 7327 } 7328 7329 RectF position = mAttachInfo.mTmpTransformRect; 7330 position.set(0, 0, mRight - mLeft, mBottom - mTop); 7331 mapRectFromViewToScreenCoords(position, clipToParent); 7332 outRect.set(Math.round(position.left), Math.round(position.top), 7333 Math.round(position.right), Math.round(position.bottom)); 7334 } 7335 7336 /** 7337 * Map a rectangle from view-relative coordinates to screen-relative coordinates 7338 * 7339 * @param rect The rectangle to be mapped 7340 * @param clipToParent Whether to clip child bounds to the parent ones. 7341 * @hide 7342 */ 7343 public void mapRectFromViewToScreenCoords(RectF rect, boolean clipToParent) { 7344 if (!hasIdentityMatrix()) { 7345 getMatrix().mapRect(rect); 7346 } 7347 7348 rect.offset(mLeft, mTop); 7349 7350 ViewParent parent = mParent; 7351 while (parent instanceof View) { 7352 View parentView = (View) parent; 7353 7354 rect.offset(-parentView.mScrollX, -parentView.mScrollY); 7355 7356 if (clipToParent) { 7357 rect.left = Math.max(rect.left, 0); 7358 rect.top = Math.max(rect.top, 0); 7359 rect.right = Math.min(rect.right, parentView.getWidth()); 7360 rect.bottom = Math.min(rect.bottom, parentView.getHeight()); 7361 } 7362 7363 if (!parentView.hasIdentityMatrix()) { 7364 parentView.getMatrix().mapRect(rect); 7365 } 7366 7367 rect.offset(parentView.mLeft, parentView.mTop); 7368 7369 parent = parentView.mParent; 7370 } 7371 7372 if (parent instanceof ViewRootImpl) { 7373 ViewRootImpl viewRootImpl = (ViewRootImpl) parent; 7374 rect.offset(0, -viewRootImpl.mCurScrollY); 7375 } 7376 7377 rect.offset(mAttachInfo.mWindowLeft, mAttachInfo.mWindowTop); 7378 } 7379 7380 /** 7381 * Return the class name of this object to be used for accessibility purposes. 7382 * Subclasses should only override this if they are implementing something that 7383 * should be seen as a completely new class of view when used by accessibility, 7384 * unrelated to the class it is deriving from. This is used to fill in 7385 * {@link AccessibilityNodeInfo#setClassName AccessibilityNodeInfo.setClassName}. 7386 */ 7387 public CharSequence getAccessibilityClassName() { 7388 return View.class.getName(); 7389 } 7390 7391 /** 7392 * Called when assist structure is being retrieved from a view as part of 7393 * {@link android.app.Activity#onProvideAssistData Activity.onProvideAssistData}. 7394 * @param structure Fill in with structured view data. The default implementation 7395 * fills in all data that can be inferred from the view itself. 7396 */ 7397 public void onProvideStructure(ViewStructure structure) { 7398 onProvideStructureForAssistOrAutofill(structure, false, 0); 7399 } 7400 7401 /** 7402 * Populates a {@link ViewStructure} to fullfil an autofill request. 7403 * 7404 * <p>The structure should contain at least the following properties: 7405 * <ul> 7406 * <li>Autofill id ({@link ViewStructure#setAutofillId(AutofillId, int)}). 7407 * <li>Autofill type ({@link ViewStructure#setAutofillType(int)}). 7408 * <li>Autofill value ({@link ViewStructure#setAutofillValue(AutofillValue)}). 7409 * <li>Whether the data is sensitive ({@link ViewStructure#setDataIsSensitive(boolean)}). 7410 * </ul> 7411 * 7412 * <p>It's also recommended to set the following properties - the more properties the structure 7413 * has, the higher the changes of an {@link android.service.autofill.AutofillService} properly 7414 * using the structure: 7415 * 7416 * <ul> 7417 * <li>Autofill hints ({@link ViewStructure#setAutofillHints(String[])}). 7418 * <li>Autofill options ({@link ViewStructure#setAutofillOptions(CharSequence[])}) when the 7419 * view can only be filled with predefined values (typically used when the autofill type 7420 * is {@link #AUTOFILL_TYPE_LIST}). 7421 * <li>Resource id ({@link ViewStructure#setId(int, String, String, String)}). 7422 * <li>Class name ({@link ViewStructure#setClassName(String)}). 7423 * <li>Content description ({@link ViewStructure#setContentDescription(CharSequence)}). 7424 * <li>Visual properties such as visibility ({@link ViewStructure#setVisibility(int)}), 7425 * dimensions ({@link ViewStructure#setDimens(int, int, int, int, int, int)}), and 7426 * opacity ({@link ViewStructure#setOpaque(boolean)}). 7427 * <li>For views representing text fields, text properties such as the text itself 7428 * ({@link ViewStructure#setText(CharSequence)}), text hints 7429 * ({@link ViewStructure#setHint(CharSequence)}, input type 7430 * ({@link ViewStructure#setInputType(int)}), 7431 * <li>For views representing HTML nodes, its web domain 7432 * ({@link ViewStructure#setWebDomain(String)}) and HTML properties 7433 * (({@link ViewStructure#setHtmlInfo(android.view.ViewStructure.HtmlInfo)}). 7434 * </ul> 7435 * 7436 * <p>The default implementation of this method already sets most of these properties based on 7437 * related {@link View} methods (for example, the autofill id is set using 7438 * {@link #getAutofillId()}, the autofill type set using {@link #getAutofillType()}, etc.), 7439 * and views in the standard Android widgets library also override it to set their 7440 * relevant properties (for example, {@link android.widget.TextView} already sets the text 7441 * properties), so it's recommended to only override this method 7442 * (and call {@code super.onProvideAutofillStructure()}) when: 7443 * 7444 * <ul> 7445 * <li>The view contents does not include PII (Personally Identifiable Information), so it 7446 * can call {@link ViewStructure#setDataIsSensitive(boolean)} passing {@code false}. 7447 * <li>The view can only be autofilled with predefined options, so it can call 7448 * {@link ViewStructure#setAutofillOptions(CharSequence[])}. 7449 * </ul> 7450 * 7451 * <p><b>NOTE:</b> the {@code left} and {@code top} values set in 7452 * {@link ViewStructure#setDimens(int, int, int, int, int, int)} must be relative to the next 7453 * {@link ViewGroup#isImportantForAutofill()} predecessor view included in the structure. 7454 * 7455 * <p>Views support the Autofill Framework mainly by: 7456 * <ul> 7457 * <li>Providing the metadata defining what the view means and how it can be autofilled. 7458 * <li>Notifying the Android System when the view value changed by calling 7459 * {@link AutofillManager#notifyValueChanged(View)}. 7460 * <li>Implementing the methods that autofill the view. 7461 * </ul> 7462 * <p>This method is responsible for the former; {@link #autofill(AutofillValue)} is responsible 7463 * for the latter. 7464 * 7465 * @param structure fill in with structured view data for autofill purposes. 7466 * @param flags optional flags. 7467 * 7468 * @see #AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS 7469 */ 7470 public void onProvideAutofillStructure(ViewStructure structure, @AutofillFlags int flags) { 7471 onProvideStructureForAssistOrAutofill(structure, true, flags); 7472 } 7473 7474 private void onProvideStructureForAssistOrAutofill(ViewStructure structure, 7475 boolean forAutofill, @AutofillFlags int flags) { 7476 final int id = mID; 7477 if (id != NO_ID && !isViewIdGenerated(id)) { 7478 String pkg, type, entry; 7479 try { 7480 final Resources res = getResources(); 7481 entry = res.getResourceEntryName(id); 7482 type = res.getResourceTypeName(id); 7483 pkg = res.getResourcePackageName(id); 7484 } catch (Resources.NotFoundException e) { 7485 entry = type = pkg = null; 7486 } 7487 structure.setId(id, pkg, type, entry); 7488 } else { 7489 structure.setId(id, null, null, null); 7490 } 7491 7492 if (forAutofill) { 7493 final @AutofillType int autofillType = getAutofillType(); 7494 // Don't need to fill autofill info if view does not support it. 7495 // For example, only TextViews that are editable support autofill 7496 if (autofillType != AUTOFILL_TYPE_NONE) { 7497 structure.setAutofillType(autofillType); 7498 structure.setAutofillHints(getAutofillHints()); 7499 structure.setAutofillValue(getAutofillValue()); 7500 } 7501 } 7502 7503 int ignoredParentLeft = 0; 7504 int ignoredParentTop = 0; 7505 if (forAutofill && (flags & AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS) == 0) { 7506 View parentGroup = null; 7507 7508 ViewParent viewParent = getParent(); 7509 if (viewParent instanceof View) { 7510 parentGroup = (View) viewParent; 7511 } 7512 7513 while (parentGroup != null && !parentGroup.isImportantForAutofill()) { 7514 ignoredParentLeft += parentGroup.mLeft; 7515 ignoredParentTop += parentGroup.mTop; 7516 7517 viewParent = parentGroup.getParent(); 7518 if (viewParent instanceof View) { 7519 parentGroup = (View) viewParent; 7520 } else { 7521 break; 7522 } 7523 } 7524 } 7525 7526 structure.setDimens(ignoredParentLeft + mLeft, ignoredParentTop + mTop, mScrollX, mScrollY, 7527 mRight - mLeft, mBottom - mTop); 7528 if (!forAutofill) { 7529 if (!hasIdentityMatrix()) { 7530 structure.setTransformation(getMatrix()); 7531 } 7532 structure.setElevation(getZ()); 7533 } 7534 structure.setVisibility(getVisibility()); 7535 structure.setEnabled(isEnabled()); 7536 if (isClickable()) { 7537 structure.setClickable(true); 7538 } 7539 if (isFocusable()) { 7540 structure.setFocusable(true); 7541 } 7542 if (isFocused()) { 7543 structure.setFocused(true); 7544 } 7545 if (isAccessibilityFocused()) { 7546 structure.setAccessibilityFocused(true); 7547 } 7548 if (isSelected()) { 7549 structure.setSelected(true); 7550 } 7551 if (isActivated()) { 7552 structure.setActivated(true); 7553 } 7554 if (isLongClickable()) { 7555 structure.setLongClickable(true); 7556 } 7557 if (this instanceof Checkable) { 7558 structure.setCheckable(true); 7559 if (((Checkable)this).isChecked()) { 7560 structure.setChecked(true); 7561 } 7562 } 7563 if (isOpaque()) { 7564 structure.setOpaque(true); 7565 } 7566 if (isContextClickable()) { 7567 structure.setContextClickable(true); 7568 } 7569 structure.setClassName(getAccessibilityClassName().toString()); 7570 structure.setContentDescription(getContentDescription()); 7571 } 7572 7573 /** 7574 * Called when assist structure is being retrieved from a view as part of 7575 * {@link android.app.Activity#onProvideAssistData Activity.onProvideAssistData} to 7576 * generate additional virtual structure under this view. The defaullt implementation 7577 * uses {@link #getAccessibilityNodeProvider()} to try to generate this from the 7578 * view's virtual accessibility nodes, if any. You can override this for a more 7579 * optimal implementation providing this data. 7580 */ 7581 public void onProvideVirtualStructure(ViewStructure structure) { 7582 AccessibilityNodeProvider provider = getAccessibilityNodeProvider(); 7583 if (provider != null) { 7584 AccessibilityNodeInfo info = createAccessibilityNodeInfo(); 7585 structure.setChildCount(1); 7586 ViewStructure root = structure.newChild(0); 7587 populateVirtualStructure(root, provider, info); 7588 info.recycle(); 7589 } 7590 } 7591 7592 /** 7593 * Populates a {@link ViewStructure} containing virtual children to fullfil an autofill 7594 * request. 7595 * 7596 * <p>This method should be used when the view manages a virtual structure under this view. For 7597 * example, a view that draws input fields using {@link #draw(Canvas)}. 7598 * 7599 * <p>When implementing this method, subclasses must follow the rules below: 7600 * 7601 * <ul> 7602 * <li>Add virtual children by calling the {@link ViewStructure#newChild(int)} or 7603 * {@link ViewStructure#asyncNewChild(int)} methods, where the {@code id} is an unique id 7604 * identifying the children in the virtual structure. 7605 * <li>The children hierarchy can have multiple levels if necessary, but ideally it should 7606 * exclude intermediate levels that are irrelevant for autofill; that would improve the 7607 * autofill performance. 7608 * <li>Also implement {@link #autofill(SparseArray)} to autofill the virtual 7609 * children. 7610 * <li>Set the autofill properties of the child structure as defined by 7611 * {@link #onProvideAutofillStructure(ViewStructure, int)}, using 7612 * {@link ViewStructure#setAutofillId(AutofillId, int)} to set its autofill id. 7613 * <li>Call {@link android.view.autofill.AutofillManager#notifyViewEntered(View, int, Rect)} 7614 * and/or {@link android.view.autofill.AutofillManager#notifyViewExited(View, int)} 7615 * when the focused virtual child changed. 7616 * <li>Call 7617 * {@link android.view.autofill.AutofillManager#notifyValueChanged(View, int, AutofillValue)} 7618 * when the value of a virtual child changed. 7619 * <li>Call {@link AutofillManager#commit()} when the autofill context of the view structure 7620 * changed and the current context should be committed (for example, when the user tapped 7621 * a {@code SUBMIT} button in an HTML page). 7622 * <li>Call {@link AutofillManager#cancel()} when the autofill context of the view structure 7623 * changed and the current context should be canceled (for example, when the user tapped 7624 * a {@code CANCEL} button in an HTML page). 7625 * <li>Provide ways for users to manually request autofill by calling 7626 * {@link AutofillManager#requestAutofill(View, int, Rect)}. 7627 * <li>The {@code left} and {@code top} values set in 7628 * {@link ViewStructure#setDimens(int, int, int, int, int, int)} must be relative to the 7629 * next {@link ViewGroup#isImportantForAutofill()} predecessor view included in the 7630 * structure. 7631 * </ul> 7632 * 7633 * <p>Views with virtual children support the Autofill Framework mainly by: 7634 * <ul> 7635 * <li>Providing the metadata defining what the virtual children mean and how they can be 7636 * autofilled. 7637 * <li>Implementing the methods that autofill the virtual children. 7638 * </ul> 7639 * <p>This method is responsible for the former; {@link #autofill(SparseArray)} is responsible 7640 * for the latter. 7641 * 7642 * @param structure fill in with virtual children data for autofill purposes. 7643 * @param flags optional flags. 7644 * 7645 * @see #AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS 7646 */ 7647 public void onProvideAutofillVirtualStructure(ViewStructure structure, int flags) { 7648 } 7649 7650 /** 7651 * Automatically fills the content of this view with the {@code value}. 7652 * 7653 * <p>Views support the Autofill Framework mainly by: 7654 * <ul> 7655 * <li>Providing the metadata defining what the view means and how it can be autofilled. 7656 * <li>Implementing the methods that autofill the view. 7657 * </ul> 7658 * <p>{@link #onProvideAutofillStructure(ViewStructure, int)} is responsible for the former, 7659 * this method is responsible for latter. 7660 * 7661 * <p>This method does nothing by default, but when overridden it typically: 7662 * <ol> 7663 * <li>Checks if the provided value matches the expected type (which is defined by 7664 * {@link #getAutofillType()}). 7665 * <li>Checks if the view is editable - if it isn't, it should return right away. 7666 * <li>Call the proper getter method on {@link AutofillValue} to fetch the actual value. 7667 * <li>Pass the actual value to the equivalent setter in the view. 7668 * </ol> 7669 * 7670 * <p>For example, a text-field view could implement the method this way: 7671 * 7672 * <pre class="prettyprint"> 7673 * @Override 7674 * public void autofill(AutofillValue value) { 7675 * if (!value.isText() || !this.isEditable()) { 7676 * return; 7677 * } 7678 * CharSequence text = value.getTextValue(); 7679 * if (text != null) { 7680 * this.setText(text); 7681 * } 7682 * } 7683 * </pre> 7684 * 7685 * <p>If the value is updated asynchronously, the next call to 7686 * {@link AutofillManager#notifyValueChanged(View)} must happen <b>after</b> the value was 7687 * changed to the autofilled value. If not, the view will not be considered autofilled. 7688 * 7689 * @param value value to be autofilled. 7690 */ 7691 public void autofill(@SuppressWarnings("unused") AutofillValue value) { 7692 } 7693 7694 /** 7695 * Automatically fills the content of the virtual children within this view. 7696 * 7697 * <p>Views with virtual children support the Autofill Framework mainly by: 7698 * <ul> 7699 * <li>Providing the metadata defining what the virtual children mean and how they can be 7700 * autofilled. 7701 * <li>Implementing the methods that autofill the virtual children. 7702 * </ul> 7703 * <p>{@link #onProvideAutofillVirtualStructure(ViewStructure, int)} is responsible for the 7704 * former, this method is responsible for the latter - see {@link #autofill(AutofillValue)} and 7705 * {@link #onProvideAutofillVirtualStructure(ViewStructure, int)} for more info about autofill. 7706 * 7707 * <p>If a child value is updated asynchronously, the next call to 7708 * {@link AutofillManager#notifyValueChanged(View, int, AutofillValue)} must happen 7709 * <b>after</b> the value was changed to the autofilled value. If not, the child will not be 7710 * considered autofilled. 7711 * 7712 * <p><b>NOTE:</b> to indicate that a virtual view was autofilled, 7713 * <code>?android:attr/autofilledHighlight</code> should be drawn over it until the data 7714 * changes. 7715 * 7716 * @param values map of values to be autofilled, keyed by virtual child id. 7717 * 7718 * @attr ref android.R.styleable#Theme_autofilledHighlight 7719 */ 7720 public void autofill(@NonNull @SuppressWarnings("unused") SparseArray<AutofillValue> values) { 7721 } 7722 7723 /** 7724 * Gets the unique identifier of this view in the screen, for autofill purposes. 7725 * 7726 * @return The View's autofill id. 7727 */ 7728 public final AutofillId getAutofillId() { 7729 if (mAutofillId == null) { 7730 // The autofill id needs to be unique, but its value doesn't matter, 7731 // so it's better to reuse the accessibility id to save space. 7732 mAutofillId = new AutofillId(getAutofillViewId()); 7733 } 7734 return mAutofillId; 7735 } 7736 7737 /** 7738 * Describes the autofill type of this view, so an 7739 * {@link android.service.autofill.AutofillService} can create the proper {@link AutofillValue} 7740 * when autofilling the view. 7741 * 7742 * <p>By default returns {@link #AUTOFILL_TYPE_NONE}, but views should override it to properly 7743 * support the Autofill Framework. 7744 * 7745 * @return either {@link #AUTOFILL_TYPE_NONE}, {@link #AUTOFILL_TYPE_TEXT}, 7746 * {@link #AUTOFILL_TYPE_LIST}, {@link #AUTOFILL_TYPE_DATE}, or {@link #AUTOFILL_TYPE_TOGGLE}. 7747 * 7748 * @see #onProvideAutofillStructure(ViewStructure, int) 7749 * @see #autofill(AutofillValue) 7750 */ 7751 public @AutofillType int getAutofillType() { 7752 return AUTOFILL_TYPE_NONE; 7753 } 7754 7755 /** 7756 * Gets the hints that help an {@link android.service.autofill.AutofillService} determine how 7757 * to autofill the view with the user's data. 7758 * 7759 * <p>See {@link #setAutofillHints(String...)} for more info about these hints. 7760 * 7761 * @return The hints set via the attribute or {@link #setAutofillHints(String...)}, or 7762 * {@code null} if no hints were set. 7763 * 7764 * @attr ref android.R.styleable#View_autofillHints 7765 */ 7766 @ViewDebug.ExportedProperty() 7767 @Nullable public String[] getAutofillHints() { 7768 return mAutofillHints; 7769 } 7770 7771 /** 7772 * @hide 7773 */ 7774 public boolean isAutofilled() { 7775 return (mPrivateFlags3 & PFLAG3_IS_AUTOFILLED) != 0; 7776 } 7777 7778 /** 7779 * Gets the {@link View}'s current autofill value. 7780 * 7781 * <p>By default returns {@code null}, but views should override it to properly support the 7782 * Autofill Framework. 7783 * 7784 * @see #onProvideAutofillStructure(ViewStructure, int) 7785 * @see #autofill(AutofillValue) 7786 */ 7787 @Nullable 7788 public AutofillValue getAutofillValue() { 7789 return null; 7790 } 7791 7792 /** 7793 * Gets the mode for determining whether this view is important for autofill. 7794 * 7795 * <p>See {@link #setImportantForAutofill(int)} and {@link #isImportantForAutofill()} for more 7796 * info about this mode. 7797 * 7798 * @return {@link #IMPORTANT_FOR_AUTOFILL_AUTO} by default, or value passed to 7799 * {@link #setImportantForAutofill(int)}. 7800 * 7801 * @attr ref android.R.styleable#View_importantForAutofill 7802 */ 7803 @ViewDebug.ExportedProperty(mapping = { 7804 @ViewDebug.IntToString(from = IMPORTANT_FOR_AUTOFILL_AUTO, to = "auto"), 7805 @ViewDebug.IntToString(from = IMPORTANT_FOR_AUTOFILL_YES, to = "yes"), 7806 @ViewDebug.IntToString(from = IMPORTANT_FOR_AUTOFILL_NO, to = "no"), 7807 @ViewDebug.IntToString(from = IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS, 7808 to = "yesExcludeDescendants"), 7809 @ViewDebug.IntToString(from = IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS, 7810 to = "noExcludeDescendants")}) 7811 public @AutofillImportance int getImportantForAutofill() { 7812 return (mPrivateFlags3 7813 & PFLAG3_IMPORTANT_FOR_AUTOFILL_MASK) >> PFLAG3_IMPORTANT_FOR_AUTOFILL_SHIFT; 7814 } 7815 7816 /** 7817 * Sets the mode for determining whether this view is considered important for autofill. 7818 * 7819 * <p>The platform determines the importance for autofill automatically but you 7820 * can use this method to customize the behavior. For example: 7821 * 7822 * <ol> 7823 * <li>When the view contents is irrelevant for autofill (for example, a text field used in a 7824 * "Captcha" challenge), it should be {@link #IMPORTANT_FOR_AUTOFILL_NO}. 7825 * <li>When both the view and its children are irrelevant for autofill (for example, the root 7826 * view of an activity containing a spreadhseet editor), it should be 7827 * {@link #IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS}. 7828 * <li>When the view content is relevant for autofill but its children aren't (for example, 7829 * a credit card expiration date represented by a custom view that overrides the proper 7830 * autofill methods and has 2 children representing the month and year), it should 7831 * be {@link #IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS}. 7832 * </ol> 7833 * 7834 * <p><b>NOTE:</strong> setting the mode as does {@link #IMPORTANT_FOR_AUTOFILL_NO} or 7835 * {@link #IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS} does not guarantee the view (and its 7836 * children) will be always be considered not important; for example, when the user explicitly 7837 * makes an autofill request, all views are considered important. See 7838 * {@link #isImportantForAutofill()} for more details about how the View's importance for 7839 * autofill is used. 7840 * 7841 * @param mode {@link #IMPORTANT_FOR_AUTOFILL_AUTO}, {@link #IMPORTANT_FOR_AUTOFILL_YES}, 7842 * {@link #IMPORTANT_FOR_AUTOFILL_NO}, {@link #IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS}, 7843 * or {@link #IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS}. 7844 * 7845 * @attr ref android.R.styleable#View_importantForAutofill 7846 */ 7847 public void setImportantForAutofill(@AutofillImportance int mode) { 7848 mPrivateFlags3 &= ~PFLAG3_IMPORTANT_FOR_AUTOFILL_MASK; 7849 mPrivateFlags3 |= (mode << PFLAG3_IMPORTANT_FOR_AUTOFILL_SHIFT) 7850 & PFLAG3_IMPORTANT_FOR_AUTOFILL_MASK; 7851 } 7852 7853 /** 7854 * Hints the Android System whether the {@link android.app.assist.AssistStructure.ViewNode} 7855 * associated with this view is considered important for autofill purposes. 7856 * 7857 * <p>Generally speaking, a view is important for autofill if: 7858 * <ol> 7859 * <li>The view can be autofilled by an {@link android.service.autofill.AutofillService}. 7860 * <li>The view contents can help an {@link android.service.autofill.AutofillService} 7861 * determine how other views can be autofilled. 7862 * <ol> 7863 * 7864 * <p>For example, view containers should typically return {@code false} for performance reasons 7865 * (since the important info is provided by their children), but if its properties have relevant 7866 * information (for example, a resource id called {@code credentials}, it should return 7867 * {@code true}. On the other hand, views representing labels or editable fields should 7868 * typically return {@code true}, but in some cases they could return {@code false} 7869 * (for example, if they're part of a "Captcha" mechanism). 7870 * 7871 * <p>The value returned by this method depends on the value returned by 7872 * {@link #getImportantForAutofill()}: 7873 * 7874 * <ol> 7875 * <li>if it returns {@link #IMPORTANT_FOR_AUTOFILL_YES} or 7876 * {@link #IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS}, then it returns {@code true} 7877 * <li>if it returns {@link #IMPORTANT_FOR_AUTOFILL_NO} or 7878 * {@link #IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS}, then it returns {@code false} 7879 * <li>if it returns {@link #IMPORTANT_FOR_AUTOFILL_AUTO}, then it uses some simple heuristics 7880 * that can return {@code true} in some cases (like a container with a resource id), 7881 * but {@code false} in most. 7882 * <li>otherwise, it returns {@code false}. 7883 * </ol> 7884 * 7885 * <p>When a view is considered important for autofill: 7886 * <ul> 7887 * <li>The view might automatically trigger an autofill request when focused on. 7888 * <li>The contents of the view are included in the {@link ViewStructure} used in an autofill 7889 * request. 7890 * </ul> 7891 * 7892 * <p>On the other hand, when a view is considered not important for autofill: 7893 * <ul> 7894 * <li>The view never automatically triggers autofill requests, but it can trigger a manual 7895 * request through {@link AutofillManager#requestAutofill(View)}. 7896 * <li>The contents of the view are not included in the {@link ViewStructure} used in an 7897 * autofill request, unless the request has the 7898 * {@link #AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS} flag. 7899 * </ul> 7900 * 7901 * @return whether the view is considered important for autofill. 7902 * 7903 * @see #setImportantForAutofill(int) 7904 * @see #IMPORTANT_FOR_AUTOFILL_AUTO 7905 * @see #IMPORTANT_FOR_AUTOFILL_YES 7906 * @see #IMPORTANT_FOR_AUTOFILL_NO 7907 * @see #IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS 7908 * @see #IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS 7909 * @see AutofillManager#requestAutofill(View) 7910 */ 7911 public final boolean isImportantForAutofill() { 7912 // Check parent mode to ensure we're not hidden. 7913 ViewParent parent = mParent; 7914 while (parent instanceof View) { 7915 final int parentImportance = ((View) parent).getImportantForAutofill(); 7916 if (parentImportance == IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS 7917 || parentImportance == IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS) { 7918 return false; 7919 } 7920 parent = parent.getParent(); 7921 } 7922 7923 final int importance = getImportantForAutofill(); 7924 7925 // First, check the explicit states. 7926 if (importance == IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS 7927 || importance == IMPORTANT_FOR_AUTOFILL_YES) { 7928 return true; 7929 } 7930 if (importance == IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS 7931 || importance == IMPORTANT_FOR_AUTOFILL_NO) { 7932 return false; 7933 } 7934 7935 // Then use some heuristics to handle AUTO. 7936 7937 // Always include views that have an explicit resource id. 7938 final int id = mID; 7939 if (id != NO_ID && !isViewIdGenerated(id)) { 7940 final Resources res = getResources(); 7941 String entry = null; 7942 String pkg = null; 7943 try { 7944 entry = res.getResourceEntryName(id); 7945 pkg = res.getResourcePackageName(id); 7946 } catch (Resources.NotFoundException e) { 7947 // ignore 7948 } 7949 if (entry != null && pkg != null && pkg.equals(mContext.getPackageName())) { 7950 return true; 7951 } 7952 } 7953 7954 // Otherwise, assume it's not important... 7955 return false; 7956 } 7957 7958 @Nullable 7959 private AutofillManager getAutofillManager() { 7960 return mContext.getSystemService(AutofillManager.class); 7961 } 7962 7963 private boolean isAutofillable() { 7964 return getAutofillType() != AUTOFILL_TYPE_NONE && isImportantForAutofill() 7965 && getAutofillViewId() > LAST_APP_AUTOFILL_ID; 7966 } 7967 7968 private void populateVirtualStructure(ViewStructure structure, 7969 AccessibilityNodeProvider provider, AccessibilityNodeInfo info) { 7970 structure.setId(AccessibilityNodeInfo.getVirtualDescendantId(info.getSourceNodeId()), 7971 null, null, null); 7972 Rect rect = structure.getTempRect(); 7973 info.getBoundsInParent(rect); 7974 structure.setDimens(rect.left, rect.top, 0, 0, rect.width(), rect.height()); 7975 structure.setVisibility(VISIBLE); 7976 structure.setEnabled(info.isEnabled()); 7977 if (info.isClickable()) { 7978 structure.setClickable(true); 7979 } 7980 if (info.isFocusable()) { 7981 structure.setFocusable(true); 7982 } 7983 if (info.isFocused()) { 7984 structure.setFocused(true); 7985 } 7986 if (info.isAccessibilityFocused()) { 7987 structure.setAccessibilityFocused(true); 7988 } 7989 if (info.isSelected()) { 7990 structure.setSelected(true); 7991 } 7992 if (info.isLongClickable()) { 7993 structure.setLongClickable(true); 7994 } 7995 if (info.isCheckable()) { 7996 structure.setCheckable(true); 7997 if (info.isChecked()) { 7998 structure.setChecked(true); 7999 } 8000 } 8001 if (info.isContextClickable()) { 8002 structure.setContextClickable(true); 8003 } 8004 CharSequence cname = info.getClassName(); 8005 structure.setClassName(cname != null ? cname.toString() : null); 8006 structure.setContentDescription(info.getContentDescription()); 8007 if ((info.getText() != null || info.getError() != null)) { 8008 structure.setText(info.getText(), info.getTextSelectionStart(), 8009 info.getTextSelectionEnd()); 8010 } 8011 final int NCHILDREN = info.getChildCount(); 8012 if (NCHILDREN > 0) { 8013 structure.setChildCount(NCHILDREN); 8014 for (int i=0; i<NCHILDREN; i++) { 8015 AccessibilityNodeInfo cinfo = provider.createAccessibilityNodeInfo( 8016 AccessibilityNodeInfo.getVirtualDescendantId(info.getChildId(i))); 8017 ViewStructure child = structure.newChild(i); 8018 populateVirtualStructure(child, provider, cinfo); 8019 cinfo.recycle(); 8020 } 8021 } 8022 } 8023 8024 /** 8025 * Dispatch creation of {@link ViewStructure} down the hierarchy. The default 8026 * implementation calls {@link #onProvideStructure} and 8027 * {@link #onProvideVirtualStructure}. 8028 */ 8029 public void dispatchProvideStructure(ViewStructure structure) { 8030 dispatchProvideStructureForAssistOrAutofill(structure, false, 0); 8031 } 8032 8033 /** 8034 * Dispatches creation of a {@link ViewStructure}s for autofill purposes down the hierarchy, 8035 * when an Assist structure is being created as part of an autofill request. 8036 * 8037 * <p>The default implementation does the following: 8038 * <ul> 8039 * <li>Sets the {@link AutofillId} in the structure. 8040 * <li>Calls {@link #onProvideAutofillStructure(ViewStructure, int)}. 8041 * <li>Calls {@link #onProvideAutofillVirtualStructure(ViewStructure, int)}. 8042 * </ul> 8043 * 8044 * <p>Typically, this method should only be overridden by subclasses that provide a view 8045 * hierarchy (such as {@link ViewGroup}) - other classes should override 8046 * {@link #onProvideAutofillStructure(ViewStructure, int)} or 8047 * {@link #onProvideAutofillVirtualStructure(ViewStructure, int)} instead. 8048 * 8049 * <p>When overridden, it must: 8050 * 8051 * <ul> 8052 * <li>Either call 8053 * {@code super.dispatchProvideAutofillStructure(structure, flags)} or explicitly 8054 * set the {@link AutofillId} in the structure (for example, by calling 8055 * {@code structure.setAutofillId(getAutofillId())}). 8056 * <li>Decide how to handle the {@link #AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS} flag - when 8057 * set, all views in the structure should be considered important for autofill, 8058 * regardless of what {@link #isImportantForAutofill()} returns. We encourage you to 8059 * respect this flag to provide a better user experience - this flag is typically used 8060 * when an user explicitly requested autofill. If the flag is not set, 8061 * then only views marked as important for autofill should be included in the 8062 * structure - skipping non-important views optimizes the overall autofill performance. 8063 * </ul> 8064 * 8065 * @param structure fill in with structured view data for autofill purposes. 8066 * @param flags optional flags. 8067 * 8068 * @see #AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS 8069 */ 8070 public void dispatchProvideAutofillStructure(@NonNull ViewStructure structure, 8071 @AutofillFlags int flags) { 8072 dispatchProvideStructureForAssistOrAutofill(structure, true, flags); 8073 } 8074 8075 private void dispatchProvideStructureForAssistOrAutofill(ViewStructure structure, 8076 boolean forAutofill, @AutofillFlags int flags) { 8077 if (forAutofill) { 8078 structure.setAutofillId(getAutofillId()); 8079 if (!isLaidOut()) { 8080 Log.w(VIEW_LOG_TAG, "dispatchProvideAutofillStructure(): not laid out, ignoring"); 8081 return; 8082 } 8083 onProvideAutofillStructure(structure, flags); 8084 onProvideAutofillVirtualStructure(structure, flags); 8085 } else if (!isAssistBlocked()) { 8086 onProvideStructure(structure); 8087 onProvideVirtualStructure(structure); 8088 } else { 8089 structure.setClassName(getAccessibilityClassName().toString()); 8090 structure.setAssistBlocked(true); 8091 } 8092 } 8093 8094 /** 8095 * @see #onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo) 8096 * 8097 * Note: Called from the default {@link AccessibilityDelegate}. 8098 * 8099 * @hide 8100 */ 8101 public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) { 8102 if (mAttachInfo == null) { 8103 return; 8104 } 8105 8106 Rect bounds = mAttachInfo.mTmpInvalRect; 8107 8108 getDrawingRect(bounds); 8109 info.setBoundsInParent(bounds); 8110 8111 getBoundsOnScreen(bounds, true); 8112 info.setBoundsInScreen(bounds); 8113 8114 ViewParent parent = getParentForAccessibility(); 8115 if (parent instanceof View) { 8116 info.setParent((View) parent); 8117 } 8118 8119 if (mID != View.NO_ID) { 8120 View rootView = getRootView(); 8121 if (rootView == null) { 8122 rootView = this; 8123 } 8124 8125 View label = rootView.findLabelForView(this, mID); 8126 if (label != null) { 8127 info.setLabeledBy(label); 8128 } 8129 8130 if ((mAttachInfo.mAccessibilityFetchFlags 8131 & AccessibilityNodeInfo.FLAG_REPORT_VIEW_IDS) != 0 8132 && Resources.resourceHasPackage(mID)) { 8133 try { 8134 String viewId = getResources().getResourceName(mID); 8135 info.setViewIdResourceName(viewId); 8136 } catch (Resources.NotFoundException nfe) { 8137 /* ignore */ 8138 } 8139 } 8140 } 8141 8142 if (mLabelForId != View.NO_ID) { 8143 View rootView = getRootView(); 8144 if (rootView == null) { 8145 rootView = this; 8146 } 8147 View labeled = rootView.findViewInsideOutShouldExist(this, mLabelForId); 8148 if (labeled != null) { 8149 info.setLabelFor(labeled); 8150 } 8151 } 8152 8153 if (mAccessibilityTraversalBeforeId != View.NO_ID) { 8154 View rootView = getRootView(); 8155 if (rootView == null) { 8156 rootView = this; 8157 } 8158 View next = rootView.findViewInsideOutShouldExist(this, 8159 mAccessibilityTraversalBeforeId); 8160 if (next != null && next.includeForAccessibility()) { 8161 info.setTraversalBefore(next); 8162 } 8163 } 8164 8165 if (mAccessibilityTraversalAfterId != View.NO_ID) { 8166 View rootView = getRootView(); 8167 if (rootView == null) { 8168 rootView = this; 8169 } 8170 View next = rootView.findViewInsideOutShouldExist(this, 8171 mAccessibilityTraversalAfterId); 8172 if (next != null && next.includeForAccessibility()) { 8173 info.setTraversalAfter(next); 8174 } 8175 } 8176 8177 info.setVisibleToUser(isVisibleToUser()); 8178 8179 info.setImportantForAccessibility(isImportantForAccessibility()); 8180 info.setPackageName(mContext.getPackageName()); 8181 info.setClassName(getAccessibilityClassName()); 8182 info.setContentDescription(getContentDescription()); 8183 8184 info.setEnabled(isEnabled()); 8185 info.setClickable(isClickable()); 8186 info.setFocusable(isFocusable()); 8187 info.setFocused(isFocused()); 8188 info.setAccessibilityFocused(isAccessibilityFocused()); 8189 info.setSelected(isSelected()); 8190 info.setLongClickable(isLongClickable()); 8191 info.setContextClickable(isContextClickable()); 8192 info.setLiveRegion(getAccessibilityLiveRegion()); 8193 8194 // TODO: These make sense only if we are in an AdapterView but all 8195 // views can be selected. Maybe from accessibility perspective 8196 // we should report as selectable view in an AdapterView. 8197 info.addAction(AccessibilityNodeInfo.ACTION_SELECT); 8198 info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_SELECTION); 8199 8200 if (isFocusable()) { 8201 if (isFocused()) { 8202 info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_FOCUS); 8203 } else { 8204 info.addAction(AccessibilityNodeInfo.ACTION_FOCUS); 8205 } 8206 } 8207 8208 if (!isAccessibilityFocused()) { 8209 info.addAction(AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS); 8210 } else { 8211 info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS); 8212 } 8213 8214 if (isClickable() && isEnabled()) { 8215 info.addAction(AccessibilityNodeInfo.ACTION_CLICK); 8216 } 8217 8218 if (isLongClickable() && isEnabled()) { 8219 info.addAction(AccessibilityNodeInfo.ACTION_LONG_CLICK); 8220 } 8221 8222 if (isContextClickable() && isEnabled()) { 8223 info.addAction(AccessibilityAction.ACTION_CONTEXT_CLICK); 8224 } 8225 8226 CharSequence text = getIterableTextForAccessibility(); 8227 if (text != null && text.length() > 0) { 8228 info.setTextSelection(getAccessibilitySelectionStart(), getAccessibilitySelectionEnd()); 8229 8230 info.addAction(AccessibilityNodeInfo.ACTION_SET_SELECTION); 8231 info.addAction(AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY); 8232 info.addAction(AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY); 8233 info.setMovementGranularities(AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER 8234 | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD 8235 | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH); 8236 } 8237 8238 info.addAction(AccessibilityAction.ACTION_SHOW_ON_SCREEN); 8239 populateAccessibilityNodeInfoDrawingOrderInParent(info); 8240 } 8241 8242 /** 8243 * Adds extra data to an {@link AccessibilityNodeInfo} based on an explicit request for the 8244 * additional data. 8245 * <p> 8246 * This method only needs overloading if the node is marked as having extra data available. 8247 * </p> 8248 * 8249 * @param info The info to which to add the extra data. Never {@code null}. 8250 * @param extraDataKey A key specifying the type of extra data to add to the info. The 8251 * extra data should be added to the {@link Bundle} returned by 8252 * the info's {@link AccessibilityNodeInfo#getExtras} method. Never 8253 * {@code null}. 8254 * @param arguments A {@link Bundle} holding any arguments relevant for this request. May be 8255 * {@code null} if the service provided no arguments. 8256 * 8257 * @see AccessibilityNodeInfo#setAvailableExtraData(List) 8258 */ 8259 public void addExtraDataToAccessibilityNodeInfo( 8260 @NonNull AccessibilityNodeInfo info, @NonNull String extraDataKey, 8261 @Nullable Bundle arguments) { 8262 } 8263 8264 /** 8265 * Determine the order in which this view will be drawn relative to its siblings for a11y 8266 * 8267 * @param info The info whose drawing order should be populated 8268 */ 8269 private void populateAccessibilityNodeInfoDrawingOrderInParent(AccessibilityNodeInfo info) { 8270 /* 8271 * If the view's bounds haven't been set yet, layout has not completed. In that situation, 8272 * drawing order may not be well-defined, and some Views with custom drawing order may 8273 * not be initialized sufficiently to respond properly getChildDrawingOrder. 8274 */ 8275 if ((mPrivateFlags & PFLAG_HAS_BOUNDS) == 0) { 8276 info.setDrawingOrder(0); 8277 return; 8278 } 8279 int drawingOrderInParent = 1; 8280 // Iterate up the hierarchy if parents are not important for a11y 8281 View viewAtDrawingLevel = this; 8282 final ViewParent parent = getParentForAccessibility(); 8283 while (viewAtDrawingLevel != parent) { 8284 final ViewParent currentParent = viewAtDrawingLevel.getParent(); 8285 if (!(currentParent instanceof ViewGroup)) { 8286 // Should only happen for the Decor 8287 drawingOrderInParent = 0; 8288 break; 8289 } else { 8290 final ViewGroup parentGroup = (ViewGroup) currentParent; 8291 final int childCount = parentGroup.getChildCount(); 8292 if (childCount > 1) { 8293 List<View> preorderedList = parentGroup.buildOrderedChildList(); 8294 if (preorderedList != null) { 8295 final int childDrawIndex = preorderedList.indexOf(viewAtDrawingLevel); 8296 for (int i = 0; i < childDrawIndex; i++) { 8297 drawingOrderInParent += numViewsForAccessibility(preorderedList.get(i)); 8298 } 8299 } else { 8300 final int childIndex = parentGroup.indexOfChild(viewAtDrawingLevel); 8301 final boolean customOrder = parentGroup.isChildrenDrawingOrderEnabled(); 8302 final int childDrawIndex = ((childIndex >= 0) && customOrder) ? parentGroup 8303 .getChildDrawingOrder(childCount, childIndex) : childIndex; 8304 final int numChildrenToIterate = customOrder ? childCount : childDrawIndex; 8305 if (childDrawIndex != 0) { 8306 for (int i = 0; i < numChildrenToIterate; i++) { 8307 final int otherDrawIndex = (customOrder ? 8308 parentGroup.getChildDrawingOrder(childCount, i) : i); 8309 if (otherDrawIndex < childDrawIndex) { 8310 drawingOrderInParent += 8311 numViewsForAccessibility(parentGroup.getChildAt(i)); 8312 } 8313 } 8314 } 8315 } 8316 } 8317 } 8318 viewAtDrawingLevel = (View) currentParent; 8319 } 8320 info.setDrawingOrder(drawingOrderInParent); 8321 } 8322 8323 private static int numViewsForAccessibility(View view) { 8324 if (view != null) { 8325 if (view.includeForAccessibility()) { 8326 return 1; 8327 } else if (view instanceof ViewGroup) { 8328 return ((ViewGroup) view).getNumChildrenForAccessibility(); 8329 } 8330 } 8331 return 0; 8332 } 8333 8334 private View findLabelForView(View view, int labeledId) { 8335 if (mMatchLabelForPredicate == null) { 8336 mMatchLabelForPredicate = new MatchLabelForPredicate(); 8337 } 8338 mMatchLabelForPredicate.mLabeledId = labeledId; 8339 return findViewByPredicateInsideOut(view, mMatchLabelForPredicate); 8340 } 8341 8342 /** 8343 * Computes whether this view is visible to the user. Such a view is 8344 * attached, visible, all its predecessors are visible, it is not clipped 8345 * entirely by its predecessors, and has an alpha greater than zero. 8346 * 8347 * @return Whether the view is visible on the screen. 8348 * 8349 * @hide 8350 */ 8351 protected boolean isVisibleToUser() { 8352 return isVisibleToUser(null); 8353 } 8354 8355 /** 8356 * Computes whether the given portion of this view is visible to the user. 8357 * Such a view is attached, visible, all its predecessors are visible, 8358 * has an alpha greater than zero, and the specified portion is not 8359 * clipped entirely by its predecessors. 8360 * 8361 * @param boundInView the portion of the view to test; coordinates should be relative; may be 8362 * <code>null</code>, and the entire view will be tested in this case. 8363 * When <code>true</code> is returned by the function, the actual visible 8364 * region will be stored in this parameter; that is, if boundInView is fully 8365 * contained within the view, no modification will be made, otherwise regions 8366 * outside of the visible area of the view will be clipped. 8367 * 8368 * @return Whether the specified portion of the view is visible on the screen. 8369 * 8370 * @hide 8371 */ 8372 protected boolean isVisibleToUser(Rect boundInView) { 8373 if (mAttachInfo != null) { 8374 // Attached to invisible window means this view is not visible. 8375 if (mAttachInfo.mWindowVisibility != View.VISIBLE) { 8376 return false; 8377 } 8378 // An invisible predecessor or one with alpha zero means 8379 // that this view is not visible to the user. 8380 Object current = this; 8381 while (current instanceof View) { 8382 View view = (View) current; 8383 // We have attach info so this view is attached and there is no 8384 // need to check whether we reach to ViewRootImpl on the way up. 8385 if (view.getAlpha() <= 0 || view.getTransitionAlpha() <= 0 || 8386 view.getVisibility() != VISIBLE) { 8387 return false; 8388 } 8389 current = view.mParent; 8390 } 8391 // Check if the view is entirely covered by its predecessors. 8392 Rect visibleRect = mAttachInfo.mTmpInvalRect; 8393 Point offset = mAttachInfo.mPoint; 8394 if (!getGlobalVisibleRect(visibleRect, offset)) { 8395 return false; 8396 } 8397 // Check if the visible portion intersects the rectangle of interest. 8398 if (boundInView != null) { 8399 visibleRect.offset(-offset.x, -offset.y); 8400 return boundInView.intersect(visibleRect); 8401 } 8402 return true; 8403 } 8404 return false; 8405 } 8406 8407 /** 8408 * Returns the delegate for implementing accessibility support via 8409 * composition. For more details see {@link AccessibilityDelegate}. 8410 * 8411 * @return The delegate, or null if none set. 8412 * 8413 * @hide 8414 */ 8415 public AccessibilityDelegate getAccessibilityDelegate() { 8416 return mAccessibilityDelegate; 8417 } 8418 8419 /** 8420 * Sets a delegate for implementing accessibility support via composition 8421 * (as opposed to inheritance). For more details, see 8422 * {@link AccessibilityDelegate}. 8423 * <p> 8424 * <strong>Note:</strong> On platform versions prior to 8425 * {@link android.os.Build.VERSION_CODES#M API 23}, delegate methods on 8426 * views in the {@code android.widget.*} package are called <i>before</i> 8427 * host methods. This prevents certain properties such as class name from 8428 * being modified by overriding 8429 * {@link AccessibilityDelegate#onInitializeAccessibilityNodeInfo(View, AccessibilityNodeInfo)}, 8430 * as any changes will be overwritten by the host class. 8431 * <p> 8432 * Starting in {@link android.os.Build.VERSION_CODES#M API 23}, delegate 8433 * methods are called <i>after</i> host methods, which all properties to be 8434 * modified without being overwritten by the host class. 8435 * 8436 * @param delegate the object to which accessibility method calls should be 8437 * delegated 8438 * @see AccessibilityDelegate 8439 */ 8440 public void setAccessibilityDelegate(@Nullable AccessibilityDelegate delegate) { 8441 mAccessibilityDelegate = delegate; 8442 } 8443 8444 /** 8445 * Gets the provider for managing a virtual view hierarchy rooted at this View 8446 * and reported to {@link android.accessibilityservice.AccessibilityService}s 8447 * that explore the window content. 8448 * <p> 8449 * If this method returns an instance, this instance is responsible for managing 8450 * {@link AccessibilityNodeInfo}s describing the virtual sub-tree rooted at this 8451 * View including the one representing the View itself. Similarly the returned 8452 * instance is responsible for performing accessibility actions on any virtual 8453 * view or the root view itself. 8454 * </p> 8455 * <p> 8456 * If an {@link AccessibilityDelegate} has been specified via calling 8457 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 8458 * {@link AccessibilityDelegate#getAccessibilityNodeProvider(View)} 8459 * is responsible for handling this call. 8460 * </p> 8461 * 8462 * @return The provider. 8463 * 8464 * @see AccessibilityNodeProvider 8465 */ 8466 public AccessibilityNodeProvider getAccessibilityNodeProvider() { 8467 if (mAccessibilityDelegate != null) { 8468 return mAccessibilityDelegate.getAccessibilityNodeProvider(this); 8469 } else { 8470 return null; 8471 } 8472 } 8473 8474 /** 8475 * Gets the unique identifier of this view on the screen for accessibility purposes. 8476 * 8477 * @return The view accessibility id. 8478 * 8479 * @hide 8480 */ 8481 public int getAccessibilityViewId() { 8482 if (mAccessibilityViewId == NO_ID) { 8483 mAccessibilityViewId = sNextAccessibilityViewId++; 8484 } 8485 return mAccessibilityViewId; 8486 } 8487 8488 /** 8489 * Gets the unique identifier of this view on the screen for autofill purposes. 8490 * 8491 * @return The view autofill id. 8492 * 8493 * @hide 8494 */ 8495 public int getAutofillViewId() { 8496 if (mAutofillViewId == NO_ID) { 8497 mAutofillViewId = mContext.getNextAutofillId(); 8498 } 8499 return mAutofillViewId; 8500 } 8501 8502 /** 8503 * Gets the unique identifier of the window in which this View reseides. 8504 * 8505 * @return The window accessibility id. 8506 * 8507 * @hide 8508 */ 8509 public int getAccessibilityWindowId() { 8510 return mAttachInfo != null ? mAttachInfo.mAccessibilityWindowId 8511 : AccessibilityWindowInfo.UNDEFINED_WINDOW_ID; 8512 } 8513 8514 /** 8515 * Returns the {@link View}'s content description. 8516 * <p> 8517 * <strong>Note:</strong> Do not override this method, as it will have no 8518 * effect on the content description presented to accessibility services. 8519 * You must call {@link #setContentDescription(CharSequence)} to modify the 8520 * content description. 8521 * 8522 * @return the content description 8523 * @see #setContentDescription(CharSequence) 8524 * @attr ref android.R.styleable#View_contentDescription 8525 */ 8526 @ViewDebug.ExportedProperty(category = "accessibility") 8527 public CharSequence getContentDescription() { 8528 return mContentDescription; 8529 } 8530 8531 /** 8532 * Sets the {@link View}'s content description. 8533 * <p> 8534 * A content description briefly describes the view and is primarily used 8535 * for accessibility support to determine how a view should be presented to 8536 * the user. In the case of a view with no textual representation, such as 8537 * {@link android.widget.ImageButton}, a useful content description 8538 * explains what the view does. For example, an image button with a phone 8539 * icon that is used to place a call may use "Call" as its content 8540 * description. An image of a floppy disk that is used to save a file may 8541 * use "Save". 8542 * 8543 * @param contentDescription The content description. 8544 * @see #getContentDescription() 8545 * @attr ref android.R.styleable#View_contentDescription 8546 */ 8547 @RemotableViewMethod 8548 public void setContentDescription(CharSequence contentDescription) { 8549 if (mContentDescription == null) { 8550 if (contentDescription == null) { 8551 return; 8552 } 8553 } else if (mContentDescription.equals(contentDescription)) { 8554 return; 8555 } 8556 mContentDescription = contentDescription; 8557 final boolean nonEmptyDesc = contentDescription != null && contentDescription.length() > 0; 8558 if (nonEmptyDesc && getImportantForAccessibility() == IMPORTANT_FOR_ACCESSIBILITY_AUTO) { 8559 setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES); 8560 notifySubtreeAccessibilityStateChangedIfNeeded(); 8561 } else { 8562 notifyViewAccessibilityStateChangedIfNeeded( 8563 AccessibilityEvent.CONTENT_CHANGE_TYPE_CONTENT_DESCRIPTION); 8564 } 8565 } 8566 8567 /** 8568 * Sets the id of a view before which this one is visited in accessibility traversal. 8569 * A screen-reader must visit the content of this view before the content of the one 8570 * it precedes. For example, if view B is set to be before view A, then a screen-reader 8571 * will traverse the entire content of B before traversing the entire content of A, 8572 * regardles of what traversal strategy it is using. 8573 * <p> 8574 * Views that do not have specified before/after relationships are traversed in order 8575 * determined by the screen-reader. 8576 * </p> 8577 * <p> 8578 * Setting that this view is before a view that is not important for accessibility 8579 * or if this view is not important for accessibility will have no effect as the 8580 * screen-reader is not aware of unimportant views. 8581 * </p> 8582 * 8583 * @param beforeId The id of a view this one precedes in accessibility traversal. 8584 * 8585 * @attr ref android.R.styleable#View_accessibilityTraversalBefore 8586 * 8587 * @see #setImportantForAccessibility(int) 8588 */ 8589 @RemotableViewMethod 8590 public void setAccessibilityTraversalBefore(int beforeId) { 8591 if (mAccessibilityTraversalBeforeId == beforeId) { 8592 return; 8593 } 8594 mAccessibilityTraversalBeforeId = beforeId; 8595 notifyViewAccessibilityStateChangedIfNeeded( 8596 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 8597 } 8598 8599 /** 8600 * Gets the id of a view before which this one is visited in accessibility traversal. 8601 * 8602 * @return The id of a view this one precedes in accessibility traversal if 8603 * specified, otherwise {@link #NO_ID}. 8604 * 8605 * @see #setAccessibilityTraversalBefore(int) 8606 */ 8607 public int getAccessibilityTraversalBefore() { 8608 return mAccessibilityTraversalBeforeId; 8609 } 8610 8611 /** 8612 * Sets the id of a view after which this one is visited in accessibility traversal. 8613 * A screen-reader must visit the content of the other view before the content of this 8614 * one. For example, if view B is set to be after view A, then a screen-reader 8615 * will traverse the entire content of A before traversing the entire content of B, 8616 * regardles of what traversal strategy it is using. 8617 * <p> 8618 * Views that do not have specified before/after relationships are traversed in order 8619 * determined by the screen-reader. 8620 * </p> 8621 * <p> 8622 * Setting that this view is after a view that is not important for accessibility 8623 * or if this view is not important for accessibility will have no effect as the 8624 * screen-reader is not aware of unimportant views. 8625 * </p> 8626 * 8627 * @param afterId The id of a view this one succedees in accessibility traversal. 8628 * 8629 * @attr ref android.R.styleable#View_accessibilityTraversalAfter 8630 * 8631 * @see #setImportantForAccessibility(int) 8632 */ 8633 @RemotableViewMethod 8634 public void setAccessibilityTraversalAfter(int afterId) { 8635 if (mAccessibilityTraversalAfterId == afterId) { 8636 return; 8637 } 8638 mAccessibilityTraversalAfterId = afterId; 8639 notifyViewAccessibilityStateChangedIfNeeded( 8640 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 8641 } 8642 8643 /** 8644 * Gets the id of a view after which this one is visited in accessibility traversal. 8645 * 8646 * @return The id of a view this one succeedes in accessibility traversal if 8647 * specified, otherwise {@link #NO_ID}. 8648 * 8649 * @see #setAccessibilityTraversalAfter(int) 8650 */ 8651 public int getAccessibilityTraversalAfter() { 8652 return mAccessibilityTraversalAfterId; 8653 } 8654 8655 /** 8656 * Gets the id of a view for which this view serves as a label for 8657 * accessibility purposes. 8658 * 8659 * @return The labeled view id. 8660 */ 8661 @ViewDebug.ExportedProperty(category = "accessibility") 8662 public int getLabelFor() { 8663 return mLabelForId; 8664 } 8665 8666 /** 8667 * Sets the id of a view for which this view serves as a label for 8668 * accessibility purposes. 8669 * 8670 * @param id The labeled view id. 8671 */ 8672 @RemotableViewMethod 8673 public void setLabelFor(@IdRes int id) { 8674 if (mLabelForId == id) { 8675 return; 8676 } 8677 mLabelForId = id; 8678 if (mLabelForId != View.NO_ID 8679 && mID == View.NO_ID) { 8680 mID = generateViewId(); 8681 } 8682 notifyViewAccessibilityStateChangedIfNeeded( 8683 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 8684 } 8685 8686 /** 8687 * Invoked whenever this view loses focus, either by losing window focus or by losing 8688 * focus within its window. This method can be used to clear any state tied to the 8689 * focus. For instance, if a button is held pressed with the trackball and the window 8690 * loses focus, this method can be used to cancel the press. 8691 * 8692 * Subclasses of View overriding this method should always call super.onFocusLost(). 8693 * 8694 * @see #onFocusChanged(boolean, int, android.graphics.Rect) 8695 * @see #onWindowFocusChanged(boolean) 8696 * 8697 * @hide pending API council approval 8698 */ 8699 @CallSuper 8700 protected void onFocusLost() { 8701 resetPressedState(); 8702 } 8703 8704 private void resetPressedState() { 8705 if ((mViewFlags & ENABLED_MASK) == DISABLED) { 8706 return; 8707 } 8708 8709 if (isPressed()) { 8710 setPressed(false); 8711 8712 if (!mHasPerformedLongPress) { 8713 removeLongPressCallback(); 8714 } 8715 } 8716 } 8717 8718 /** 8719 * Returns true if this view has focus 8720 * 8721 * @return True if this view has focus, false otherwise. 8722 */ 8723 @ViewDebug.ExportedProperty(category = "focus") 8724 public boolean isFocused() { 8725 return (mPrivateFlags & PFLAG_FOCUSED) != 0; 8726 } 8727 8728 /** 8729 * Find the view in the hierarchy rooted at this view that currently has 8730 * focus. 8731 * 8732 * @return The view that currently has focus, or null if no focused view can 8733 * be found. 8734 */ 8735 public View findFocus() { 8736 return (mPrivateFlags & PFLAG_FOCUSED) != 0 ? this : null; 8737 } 8738 8739 /** 8740 * Indicates whether this view is one of the set of scrollable containers in 8741 * its window. 8742 * 8743 * @return whether this view is one of the set of scrollable containers in 8744 * its window 8745 * 8746 * @attr ref android.R.styleable#View_isScrollContainer 8747 */ 8748 public boolean isScrollContainer() { 8749 return (mPrivateFlags & PFLAG_SCROLL_CONTAINER_ADDED) != 0; 8750 } 8751 8752 /** 8753 * Change whether this view is one of the set of scrollable containers in 8754 * its window. This will be used to determine whether the window can 8755 * resize or must pan when a soft input area is open -- scrollable 8756 * containers allow the window to use resize mode since the container 8757 * will appropriately shrink. 8758 * 8759 * @attr ref android.R.styleable#View_isScrollContainer 8760 */ 8761 public void setScrollContainer(boolean isScrollContainer) { 8762 if (isScrollContainer) { 8763 if (mAttachInfo != null && (mPrivateFlags&PFLAG_SCROLL_CONTAINER_ADDED) == 0) { 8764 mAttachInfo.mScrollContainers.add(this); 8765 mPrivateFlags |= PFLAG_SCROLL_CONTAINER_ADDED; 8766 } 8767 mPrivateFlags |= PFLAG_SCROLL_CONTAINER; 8768 } else { 8769 if ((mPrivateFlags&PFLAG_SCROLL_CONTAINER_ADDED) != 0) { 8770 mAttachInfo.mScrollContainers.remove(this); 8771 } 8772 mPrivateFlags &= ~(PFLAG_SCROLL_CONTAINER|PFLAG_SCROLL_CONTAINER_ADDED); 8773 } 8774 } 8775 8776 /** 8777 * Returns the quality of the drawing cache. 8778 * 8779 * @return One of {@link #DRAWING_CACHE_QUALITY_AUTO}, 8780 * {@link #DRAWING_CACHE_QUALITY_LOW}, or {@link #DRAWING_CACHE_QUALITY_HIGH} 8781 * 8782 * @see #setDrawingCacheQuality(int) 8783 * @see #setDrawingCacheEnabled(boolean) 8784 * @see #isDrawingCacheEnabled() 8785 * 8786 * @attr ref android.R.styleable#View_drawingCacheQuality 8787 */ 8788 @DrawingCacheQuality 8789 public int getDrawingCacheQuality() { 8790 return mViewFlags & DRAWING_CACHE_QUALITY_MASK; 8791 } 8792 8793 /** 8794 * Set the drawing cache quality of this view. This value is used only when the 8795 * drawing cache is enabled 8796 * 8797 * @param quality One of {@link #DRAWING_CACHE_QUALITY_AUTO}, 8798 * {@link #DRAWING_CACHE_QUALITY_LOW}, or {@link #DRAWING_CACHE_QUALITY_HIGH} 8799 * 8800 * @see #getDrawingCacheQuality() 8801 * @see #setDrawingCacheEnabled(boolean) 8802 * @see #isDrawingCacheEnabled() 8803 * 8804 * @attr ref android.R.styleable#View_drawingCacheQuality 8805 */ 8806 public void setDrawingCacheQuality(@DrawingCacheQuality int quality) { 8807 setFlags(quality, DRAWING_CACHE_QUALITY_MASK); 8808 } 8809 8810 /** 8811 * Returns whether the screen should remain on, corresponding to the current 8812 * value of {@link #KEEP_SCREEN_ON}. 8813 * 8814 * @return Returns true if {@link #KEEP_SCREEN_ON} is set. 8815 * 8816 * @see #setKeepScreenOn(boolean) 8817 * 8818 * @attr ref android.R.styleable#View_keepScreenOn 8819 */ 8820 public boolean getKeepScreenOn() { 8821 return (mViewFlags & KEEP_SCREEN_ON) != 0; 8822 } 8823 8824 /** 8825 * Controls whether the screen should remain on, modifying the 8826 * value of {@link #KEEP_SCREEN_ON}. 8827 * 8828 * @param keepScreenOn Supply true to set {@link #KEEP_SCREEN_ON}. 8829 * 8830 * @see #getKeepScreenOn() 8831 * 8832 * @attr ref android.R.styleable#View_keepScreenOn 8833 */ 8834 public void setKeepScreenOn(boolean keepScreenOn) { 8835 setFlags(keepScreenOn ? KEEP_SCREEN_ON : 0, KEEP_SCREEN_ON); 8836 } 8837 8838 /** 8839 * Gets the id of the view to use when the next focus is {@link #FOCUS_LEFT}. 8840 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically. 8841 * 8842 * @attr ref android.R.styleable#View_nextFocusLeft 8843 */ 8844 public int getNextFocusLeftId() { 8845 return mNextFocusLeftId; 8846 } 8847 8848 /** 8849 * Sets the id of the view to use when the next focus is {@link #FOCUS_LEFT}. 8850 * @param nextFocusLeftId The next focus ID, or {@link #NO_ID} if the framework should 8851 * decide automatically. 8852 * 8853 * @attr ref android.R.styleable#View_nextFocusLeft 8854 */ 8855 public void setNextFocusLeftId(int nextFocusLeftId) { 8856 mNextFocusLeftId = nextFocusLeftId; 8857 } 8858 8859 /** 8860 * Gets the id of the view to use when the next focus is {@link #FOCUS_RIGHT}. 8861 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically. 8862 * 8863 * @attr ref android.R.styleable#View_nextFocusRight 8864 */ 8865 public int getNextFocusRightId() { 8866 return mNextFocusRightId; 8867 } 8868 8869 /** 8870 * Sets the id of the view to use when the next focus is {@link #FOCUS_RIGHT}. 8871 * @param nextFocusRightId The next focus ID, or {@link #NO_ID} if the framework should 8872 * decide automatically. 8873 * 8874 * @attr ref android.R.styleable#View_nextFocusRight 8875 */ 8876 public void setNextFocusRightId(int nextFocusRightId) { 8877 mNextFocusRightId = nextFocusRightId; 8878 } 8879 8880 /** 8881 * Gets the id of the view to use when the next focus is {@link #FOCUS_UP}. 8882 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically. 8883 * 8884 * @attr ref android.R.styleable#View_nextFocusUp 8885 */ 8886 public int getNextFocusUpId() { 8887 return mNextFocusUpId; 8888 } 8889 8890 /** 8891 * Sets the id of the view to use when the next focus is {@link #FOCUS_UP}. 8892 * @param nextFocusUpId The next focus ID, or {@link #NO_ID} if the framework should 8893 * decide automatically. 8894 * 8895 * @attr ref android.R.styleable#View_nextFocusUp 8896 */ 8897 public void setNextFocusUpId(int nextFocusUpId) { 8898 mNextFocusUpId = nextFocusUpId; 8899 } 8900 8901 /** 8902 * Gets the id of the view to use when the next focus is {@link #FOCUS_DOWN}. 8903 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically. 8904 * 8905 * @attr ref android.R.styleable#View_nextFocusDown 8906 */ 8907 public int getNextFocusDownId() { 8908 return mNextFocusDownId; 8909 } 8910 8911 /** 8912 * Sets the id of the view to use when the next focus is {@link #FOCUS_DOWN}. 8913 * @param nextFocusDownId The next focus ID, or {@link #NO_ID} if the framework should 8914 * decide automatically. 8915 * 8916 * @attr ref android.R.styleable#View_nextFocusDown 8917 */ 8918 public void setNextFocusDownId(int nextFocusDownId) { 8919 mNextFocusDownId = nextFocusDownId; 8920 } 8921 8922 /** 8923 * Gets the id of the view to use when the next focus is {@link #FOCUS_FORWARD}. 8924 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically. 8925 * 8926 * @attr ref android.R.styleable#View_nextFocusForward 8927 */ 8928 public int getNextFocusForwardId() { 8929 return mNextFocusForwardId; 8930 } 8931 8932 /** 8933 * Sets the id of the view to use when the next focus is {@link #FOCUS_FORWARD}. 8934 * @param nextFocusForwardId The next focus ID, or {@link #NO_ID} if the framework should 8935 * decide automatically. 8936 * 8937 * @attr ref android.R.styleable#View_nextFocusForward 8938 */ 8939 public void setNextFocusForwardId(int nextFocusForwardId) { 8940 mNextFocusForwardId = nextFocusForwardId; 8941 } 8942 8943 /** 8944 * Gets the id of the root of the next keyboard navigation cluster. 8945 * @return The next keyboard navigation cluster ID, or {@link #NO_ID} if the framework should 8946 * decide automatically. 8947 * 8948 * @attr ref android.R.styleable#View_nextClusterForward 8949 */ 8950 public int getNextClusterForwardId() { 8951 return mNextClusterForwardId; 8952 } 8953 8954 /** 8955 * Sets the id of the view to use as the root of the next keyboard navigation cluster. 8956 * @param nextClusterForwardId The next cluster ID, or {@link #NO_ID} if the framework should 8957 * decide automatically. 8958 * 8959 * @attr ref android.R.styleable#View_nextClusterForward 8960 */ 8961 public void setNextClusterForwardId(int nextClusterForwardId) { 8962 mNextClusterForwardId = nextClusterForwardId; 8963 } 8964 8965 /** 8966 * Returns the visibility of this view and all of its ancestors 8967 * 8968 * @return True if this view and all of its ancestors are {@link #VISIBLE} 8969 */ 8970 public boolean isShown() { 8971 View current = this; 8972 //noinspection ConstantConditions 8973 do { 8974 if ((current.mViewFlags & VISIBILITY_MASK) != VISIBLE) { 8975 return false; 8976 } 8977 ViewParent parent = current.mParent; 8978 if (parent == null) { 8979 return false; // We are not attached to the view root 8980 } 8981 if (!(parent instanceof View)) { 8982 return true; 8983 } 8984 current = (View) parent; 8985 } while (current != null); 8986 8987 return false; 8988 } 8989 8990 /** 8991 * Called by the view hierarchy when the content insets for a window have 8992 * changed, to allow it to adjust its content to fit within those windows. 8993 * The content insets tell you the space that the status bar, input method, 8994 * and other system windows infringe on the application's window. 8995 * 8996 * <p>You do not normally need to deal with this function, since the default 8997 * window decoration given to applications takes care of applying it to the 8998 * content of the window. If you use {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN} 8999 * or {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION} this will not be the case, 9000 * and your content can be placed under those system elements. You can then 9001 * use this method within your view hierarchy if you have parts of your UI 9002 * which you would like to ensure are not being covered. 9003 * 9004 * <p>The default implementation of this method simply applies the content 9005 * insets to the view's padding, consuming that content (modifying the 9006 * insets to be 0), and returning true. This behavior is off by default, but can 9007 * be enabled through {@link #setFitsSystemWindows(boolean)}. 9008 * 9009 * <p>This function's traversal down the hierarchy is depth-first. The same content 9010 * insets object is propagated down the hierarchy, so any changes made to it will 9011 * be seen by all following views (including potentially ones above in 9012 * the hierarchy since this is a depth-first traversal). The first view 9013 * that returns true will abort the entire traversal. 9014 * 9015 * <p>The default implementation works well for a situation where it is 9016 * used with a container that covers the entire window, allowing it to 9017 * apply the appropriate insets to its content on all edges. If you need 9018 * a more complicated layout (such as two different views fitting system 9019 * windows, one on the top of the window, and one on the bottom), 9020 * you can override the method and handle the insets however you would like. 9021 * Note that the insets provided by the framework are always relative to the 9022 * far edges of the window, not accounting for the location of the called view 9023 * within that window. (In fact when this method is called you do not yet know 9024 * where the layout will place the view, as it is done before layout happens.) 9025 * 9026 * <p>Note: unlike many View methods, there is no dispatch phase to this 9027 * call. If you are overriding it in a ViewGroup and want to allow the 9028 * call to continue to your children, you must be sure to call the super 9029 * implementation. 9030 * 9031 * <p>Here is a sample layout that makes use of fitting system windows 9032 * to have controls for a video view placed inside of the window decorations 9033 * that it hides and shows. This can be used with code like the second 9034 * sample (video player) shown in {@link #setSystemUiVisibility(int)}. 9035 * 9036 * {@sample development/samples/ApiDemos/res/layout/video_player.xml complete} 9037 * 9038 * @param insets Current content insets of the window. Prior to 9039 * {@link android.os.Build.VERSION_CODES#JELLY_BEAN} you must not modify 9040 * the insets or else you and Android will be unhappy. 9041 * 9042 * @return {@code true} if this view applied the insets and it should not 9043 * continue propagating further down the hierarchy, {@code false} otherwise. 9044 * @see #getFitsSystemWindows() 9045 * @see #setFitsSystemWindows(boolean) 9046 * @see #setSystemUiVisibility(int) 9047 * 9048 * @deprecated As of API 20 use {@link #dispatchApplyWindowInsets(WindowInsets)} to apply 9049 * insets to views. Views should override {@link #onApplyWindowInsets(WindowInsets)} or use 9050 * {@link #setOnApplyWindowInsetsListener(android.view.View.OnApplyWindowInsetsListener)} 9051 * to implement handling their own insets. 9052 */ 9053 @Deprecated 9054 protected boolean fitSystemWindows(Rect insets) { 9055 if ((mPrivateFlags3 & PFLAG3_APPLYING_INSETS) == 0) { 9056 if (insets == null) { 9057 // Null insets by definition have already been consumed. 9058 // This call cannot apply insets since there are none to apply, 9059 // so return false. 9060 return false; 9061 } 9062 // If we're not in the process of dispatching the newer apply insets call, 9063 // that means we're not in the compatibility path. Dispatch into the newer 9064 // apply insets path and take things from there. 9065 try { 9066 mPrivateFlags3 |= PFLAG3_FITTING_SYSTEM_WINDOWS; 9067 return dispatchApplyWindowInsets(new WindowInsets(insets)).isConsumed(); 9068 } finally { 9069 mPrivateFlags3 &= ~PFLAG3_FITTING_SYSTEM_WINDOWS; 9070 } 9071 } else { 9072 // We're being called from the newer apply insets path. 9073 // Perform the standard fallback behavior. 9074 return fitSystemWindowsInt(insets); 9075 } 9076 } 9077 9078 private boolean fitSystemWindowsInt(Rect insets) { 9079 if ((mViewFlags & FITS_SYSTEM_WINDOWS) == FITS_SYSTEM_WINDOWS) { 9080 mUserPaddingStart = UNDEFINED_PADDING; 9081 mUserPaddingEnd = UNDEFINED_PADDING; 9082 Rect localInsets = sThreadLocal.get(); 9083 if (localInsets == null) { 9084 localInsets = new Rect(); 9085 sThreadLocal.set(localInsets); 9086 } 9087 boolean res = computeFitSystemWindows(insets, localInsets); 9088 mUserPaddingLeftInitial = localInsets.left; 9089 mUserPaddingRightInitial = localInsets.right; 9090 internalSetPadding(localInsets.left, localInsets.top, 9091 localInsets.right, localInsets.bottom); 9092 return res; 9093 } 9094 return false; 9095 } 9096 9097 /** 9098 * Called when the view should apply {@link WindowInsets} according to its internal policy. 9099 * 9100 * <p>This method should be overridden by views that wish to apply a policy different from or 9101 * in addition to the default behavior. Clients that wish to force a view subtree 9102 * to apply insets should call {@link #dispatchApplyWindowInsets(WindowInsets)}.</p> 9103 * 9104 * <p>Clients may supply an {@link OnApplyWindowInsetsListener} to a view. If one is set 9105 * it will be called during dispatch instead of this method. The listener may optionally 9106 * call this method from its own implementation if it wishes to apply the view's default 9107 * insets policy in addition to its own.</p> 9108 * 9109 * <p>Implementations of this method should either return the insets parameter unchanged 9110 * or a new {@link WindowInsets} cloned from the supplied insets with any insets consumed 9111 * that this view applied itself. This allows new inset types added in future platform 9112 * versions to pass through existing implementations unchanged without being erroneously 9113 * consumed.</p> 9114 * 9115 * <p>By default if a view's {@link #setFitsSystemWindows(boolean) fitsSystemWindows} 9116 * property is set then the view will consume the system window insets and apply them 9117 * as padding for the view.</p> 9118 * 9119 * @param insets Insets to apply 9120 * @return The supplied insets with any applied insets consumed 9121 */ 9122 public WindowInsets onApplyWindowInsets(WindowInsets insets) { 9123 if ((mPrivateFlags3 & PFLAG3_FITTING_SYSTEM_WINDOWS) == 0) { 9124 // We weren't called from within a direct call to fitSystemWindows, 9125 // call into it as a fallback in case we're in a class that overrides it 9126 // and has logic to perform. 9127 if (fitSystemWindows(insets.getSystemWindowInsets())) { 9128 return insets.consumeSystemWindowInsets(); 9129 } 9130 } else { 9131 // We were called from within a direct call to fitSystemWindows. 9132 if (fitSystemWindowsInt(insets.getSystemWindowInsets())) { 9133 return insets.consumeSystemWindowInsets(); 9134 } 9135 } 9136 return insets; 9137 } 9138 9139 /** 9140 * Set an {@link OnApplyWindowInsetsListener} to take over the policy for applying 9141 * window insets to this view. The listener's 9142 * {@link OnApplyWindowInsetsListener#onApplyWindowInsets(View, WindowInsets) onApplyWindowInsets} 9143 * method will be called instead of the view's 9144 * {@link #onApplyWindowInsets(WindowInsets) onApplyWindowInsets} method. 9145 * 9146 * @param listener Listener to set 9147 * 9148 * @see #onApplyWindowInsets(WindowInsets) 9149 */ 9150 public void setOnApplyWindowInsetsListener(OnApplyWindowInsetsListener listener) { 9151 getListenerInfo().mOnApplyWindowInsetsListener = listener; 9152 } 9153 9154 /** 9155 * Request to apply the given window insets to this view or another view in its subtree. 9156 * 9157 * <p>This method should be called by clients wishing to apply insets corresponding to areas 9158 * obscured by window decorations or overlays. This can include the status and navigation bars, 9159 * action bars, input methods and more. New inset categories may be added in the future. 9160 * The method returns the insets provided minus any that were applied by this view or its 9161 * children.</p> 9162 * 9163 * <p>Clients wishing to provide custom behavior should override the 9164 * {@link #onApplyWindowInsets(WindowInsets)} method or alternatively provide a 9165 * {@link OnApplyWindowInsetsListener} via the 9166 * {@link #setOnApplyWindowInsetsListener(View.OnApplyWindowInsetsListener) setOnApplyWindowInsetsListener} 9167 * method.</p> 9168 * 9169 * <p>This method replaces the older {@link #fitSystemWindows(Rect) fitSystemWindows} method. 9170 * </p> 9171 * 9172 * @param insets Insets to apply 9173 * @return The provided insets minus the insets that were consumed 9174 */ 9175 public WindowInsets dispatchApplyWindowInsets(WindowInsets insets) { 9176 try { 9177 mPrivateFlags3 |= PFLAG3_APPLYING_INSETS; 9178 if (mListenerInfo != null && mListenerInfo.mOnApplyWindowInsetsListener != null) { 9179 return mListenerInfo.mOnApplyWindowInsetsListener.onApplyWindowInsets(this, insets); 9180 } else { 9181 return onApplyWindowInsets(insets); 9182 } 9183 } finally { 9184 mPrivateFlags3 &= ~PFLAG3_APPLYING_INSETS; 9185 } 9186 } 9187 9188 /** 9189 * Compute the view's coordinate within the surface. 9190 * 9191 * <p>Computes the coordinates of this view in its surface. The argument 9192 * must be an array of two integers. After the method returns, the array 9193 * contains the x and y location in that order.</p> 9194 * @hide 9195 * @param location an array of two integers in which to hold the coordinates 9196 */ 9197 public void getLocationInSurface(@Size(2) int[] location) { 9198 getLocationInWindow(location); 9199 if (mAttachInfo != null && mAttachInfo.mViewRootImpl != null) { 9200 location[0] += mAttachInfo.mViewRootImpl.mWindowAttributes.surfaceInsets.left; 9201 location[1] += mAttachInfo.mViewRootImpl.mWindowAttributes.surfaceInsets.top; 9202 } 9203 } 9204 9205 /** 9206 * Provide original WindowInsets that are dispatched to the view hierarchy. The insets are 9207 * only available if the view is attached. 9208 * 9209 * @return WindowInsets from the top of the view hierarchy or null if View is detached 9210 */ 9211 public WindowInsets getRootWindowInsets() { 9212 if (mAttachInfo != null) { 9213 return mAttachInfo.mViewRootImpl.getWindowInsets(false /* forceConstruct */); 9214 } 9215 return null; 9216 } 9217 9218 /** 9219 * @hide Compute the insets that should be consumed by this view and the ones 9220 * that should propagate to those under it. 9221 */ 9222 protected boolean computeFitSystemWindows(Rect inoutInsets, Rect outLocalInsets) { 9223 if ((mViewFlags & OPTIONAL_FITS_SYSTEM_WINDOWS) == 0 9224 || mAttachInfo == null 9225 || ((mAttachInfo.mSystemUiVisibility & SYSTEM_UI_LAYOUT_FLAGS) == 0 9226 && !mAttachInfo.mOverscanRequested)) { 9227 outLocalInsets.set(inoutInsets); 9228 inoutInsets.set(0, 0, 0, 0); 9229 return true; 9230 } else { 9231 // The application wants to take care of fitting system window for 9232 // the content... however we still need to take care of any overscan here. 9233 final Rect overscan = mAttachInfo.mOverscanInsets; 9234 outLocalInsets.set(overscan); 9235 inoutInsets.left -= overscan.left; 9236 inoutInsets.top -= overscan.top; 9237 inoutInsets.right -= overscan.right; 9238 inoutInsets.bottom -= overscan.bottom; 9239 return false; 9240 } 9241 } 9242 9243 /** 9244 * Compute insets that should be consumed by this view and the ones that should propagate 9245 * to those under it. 9246 * 9247 * @param in Insets currently being processed by this View, likely received as a parameter 9248 * to {@link #onApplyWindowInsets(WindowInsets)}. 9249 * @param outLocalInsets A Rect that will receive the insets that should be consumed 9250 * by this view 9251 * @return Insets that should be passed along to views under this one 9252 */ 9253 public WindowInsets computeSystemWindowInsets(WindowInsets in, Rect outLocalInsets) { 9254 if ((mViewFlags & OPTIONAL_FITS_SYSTEM_WINDOWS) == 0 9255 || mAttachInfo == null 9256 || (mAttachInfo.mSystemUiVisibility & SYSTEM_UI_LAYOUT_FLAGS) == 0) { 9257 outLocalInsets.set(in.getSystemWindowInsets()); 9258 return in.consumeSystemWindowInsets(); 9259 } else { 9260 outLocalInsets.set(0, 0, 0, 0); 9261 return in; 9262 } 9263 } 9264 9265 /** 9266 * Sets whether or not this view should account for system screen decorations 9267 * such as the status bar and inset its content; that is, controlling whether 9268 * the default implementation of {@link #fitSystemWindows(Rect)} will be 9269 * executed. See that method for more details. 9270 * 9271 * <p>Note that if you are providing your own implementation of 9272 * {@link #fitSystemWindows(Rect)}, then there is no need to set this 9273 * flag to true -- your implementation will be overriding the default 9274 * implementation that checks this flag. 9275 * 9276 * @param fitSystemWindows If true, then the default implementation of 9277 * {@link #fitSystemWindows(Rect)} will be executed. 9278 * 9279 * @attr ref android.R.styleable#View_fitsSystemWindows 9280 * @see #getFitsSystemWindows() 9281 * @see #fitSystemWindows(Rect) 9282 * @see #setSystemUiVisibility(int) 9283 */ 9284 public void setFitsSystemWindows(boolean fitSystemWindows) { 9285 setFlags(fitSystemWindows ? FITS_SYSTEM_WINDOWS : 0, FITS_SYSTEM_WINDOWS); 9286 } 9287 9288 /** 9289 * Check for state of {@link #setFitsSystemWindows(boolean)}. If this method 9290 * returns {@code true}, the default implementation of {@link #fitSystemWindows(Rect)} 9291 * will be executed. 9292 * 9293 * @return {@code true} if the default implementation of 9294 * {@link #fitSystemWindows(Rect)} will be executed. 9295 * 9296 * @attr ref android.R.styleable#View_fitsSystemWindows 9297 * @see #setFitsSystemWindows(boolean) 9298 * @see #fitSystemWindows(Rect) 9299 * @see #setSystemUiVisibility(int) 9300 */ 9301 @ViewDebug.ExportedProperty 9302 public boolean getFitsSystemWindows() { 9303 return (mViewFlags & FITS_SYSTEM_WINDOWS) == FITS_SYSTEM_WINDOWS; 9304 } 9305 9306 /** @hide */ 9307 public boolean fitsSystemWindows() { 9308 return getFitsSystemWindows(); 9309 } 9310 9311 /** 9312 * Ask that a new dispatch of {@link #fitSystemWindows(Rect)} be performed. 9313 * @deprecated Use {@link #requestApplyInsets()} for newer platform versions. 9314 */ 9315 @Deprecated 9316 public void requestFitSystemWindows() { 9317 if (mParent != null) { 9318 mParent.requestFitSystemWindows(); 9319 } 9320 } 9321 9322 /** 9323 * Ask that a new dispatch of {@link #onApplyWindowInsets(WindowInsets)} be performed. 9324 */ 9325 public void requestApplyInsets() { 9326 requestFitSystemWindows(); 9327 } 9328 9329 /** 9330 * For use by PhoneWindow to make its own system window fitting optional. 9331 * @hide 9332 */ 9333 public void makeOptionalFitsSystemWindows() { 9334 setFlags(OPTIONAL_FITS_SYSTEM_WINDOWS, OPTIONAL_FITS_SYSTEM_WINDOWS); 9335 } 9336 9337 /** 9338 * Returns the outsets, which areas of the device that aren't a surface, but we would like to 9339 * treat them as such. 9340 * @hide 9341 */ 9342 public void getOutsets(Rect outOutsetRect) { 9343 if (mAttachInfo != null) { 9344 outOutsetRect.set(mAttachInfo.mOutsets); 9345 } else { 9346 outOutsetRect.setEmpty(); 9347 } 9348 } 9349 9350 /** 9351 * Returns the visibility status for this view. 9352 * 9353 * @return One of {@link #VISIBLE}, {@link #INVISIBLE}, or {@link #GONE}. 9354 * @attr ref android.R.styleable#View_visibility 9355 */ 9356 @ViewDebug.ExportedProperty(mapping = { 9357 @ViewDebug.IntToString(from = VISIBLE, to = "VISIBLE"), 9358 @ViewDebug.IntToString(from = INVISIBLE, to = "INVISIBLE"), 9359 @ViewDebug.IntToString(from = GONE, to = "GONE") 9360 }) 9361 @Visibility 9362 public int getVisibility() { 9363 return mViewFlags & VISIBILITY_MASK; 9364 } 9365 9366 /** 9367 * Set the visibility state of this view. 9368 * 9369 * @param visibility One of {@link #VISIBLE}, {@link #INVISIBLE}, or {@link #GONE}. 9370 * @attr ref android.R.styleable#View_visibility 9371 */ 9372 @RemotableViewMethod 9373 public void setVisibility(@Visibility int visibility) { 9374 setFlags(visibility, VISIBILITY_MASK); 9375 } 9376 9377 /** 9378 * Returns the enabled status for this view. The interpretation of the 9379 * enabled state varies by subclass. 9380 * 9381 * @return True if this view is enabled, false otherwise. 9382 */ 9383 @ViewDebug.ExportedProperty 9384 public boolean isEnabled() { 9385 return (mViewFlags & ENABLED_MASK) == ENABLED; 9386 } 9387 9388 /** 9389 * Set the enabled state of this view. The interpretation of the enabled 9390 * state varies by subclass. 9391 * 9392 * @param enabled True if this view is enabled, false otherwise. 9393 */ 9394 @RemotableViewMethod 9395 public void setEnabled(boolean enabled) { 9396 if (enabled == isEnabled()) return; 9397 9398 setFlags(enabled ? ENABLED : DISABLED, ENABLED_MASK); 9399 9400 /* 9401 * The View most likely has to change its appearance, so refresh 9402 * the drawable state. 9403 */ 9404 refreshDrawableState(); 9405 9406 // Invalidate too, since the default behavior for views is to be 9407 // be drawn at 50% alpha rather than to change the drawable. 9408 invalidate(true); 9409 9410 if (!enabled) { 9411 cancelPendingInputEvents(); 9412 } 9413 } 9414 9415 /** 9416 * Set whether this view can receive the focus. 9417 * <p> 9418 * Setting this to false will also ensure that this view is not focusable 9419 * in touch mode. 9420 * 9421 * @param focusable If true, this view can receive the focus. 9422 * 9423 * @see #setFocusableInTouchMode(boolean) 9424 * @see #setFocusable(int) 9425 * @attr ref android.R.styleable#View_focusable 9426 */ 9427 public void setFocusable(boolean focusable) { 9428 setFocusable(focusable ? FOCUSABLE : NOT_FOCUSABLE); 9429 } 9430 9431 /** 9432 * Sets whether this view can receive focus. 9433 * <p> 9434 * Setting this to {@link #FOCUSABLE_AUTO} tells the framework to determine focusability 9435 * automatically based on the view's interactivity. This is the default. 9436 * <p> 9437 * Setting this to NOT_FOCUSABLE will ensure that this view is also not focusable 9438 * in touch mode. 9439 * 9440 * @param focusable One of {@link #NOT_FOCUSABLE}, {@link #FOCUSABLE}, 9441 * or {@link #FOCUSABLE_AUTO}. 9442 * @see #setFocusableInTouchMode(boolean) 9443 * @attr ref android.R.styleable#View_focusable 9444 */ 9445 public void setFocusable(@Focusable int focusable) { 9446 if ((focusable & (FOCUSABLE_AUTO | FOCUSABLE)) == 0) { 9447 setFlags(0, FOCUSABLE_IN_TOUCH_MODE); 9448 } 9449 setFlags(focusable, FOCUSABLE_MASK); 9450 } 9451 9452 /** 9453 * Set whether this view can receive focus while in touch mode. 9454 * 9455 * Setting this to true will also ensure that this view is focusable. 9456 * 9457 * @param focusableInTouchMode If true, this view can receive the focus while 9458 * in touch mode. 9459 * 9460 * @see #setFocusable(boolean) 9461 * @attr ref android.R.styleable#View_focusableInTouchMode 9462 */ 9463 public void setFocusableInTouchMode(boolean focusableInTouchMode) { 9464 // Focusable in touch mode should always be set before the focusable flag 9465 // otherwise, setting the focusable flag will trigger a focusableViewAvailable() 9466 // which, in touch mode, will not successfully request focus on this view 9467 // because the focusable in touch mode flag is not set 9468 setFlags(focusableInTouchMode ? FOCUSABLE_IN_TOUCH_MODE : 0, FOCUSABLE_IN_TOUCH_MODE); 9469 9470 // Clear FOCUSABLE_AUTO if set. 9471 if (focusableInTouchMode) { 9472 // Clears FOCUSABLE_AUTO if set. 9473 setFlags(FOCUSABLE, FOCUSABLE_MASK); 9474 } 9475 } 9476 9477 /** 9478 * Sets the hints that help an {@link android.service.autofill.AutofillService} determine how 9479 * to autofill the view with the user's data. 9480 * 9481 * <p>Typically, there is only one way to autofill a view, but there could be more than one. 9482 * For example, if the application accepts either an username or email address to identify 9483 * an user. 9484 * 9485 * <p>These hints are not validated by the Android System, but passed "as is" to the service. 9486 * Hence, they can have any value, but it's recommended to use the {@code AUTOFILL_HINT_} 9487 * constants such as: 9488 * {@link #AUTOFILL_HINT_USERNAME}, {@link #AUTOFILL_HINT_PASSWORD}, 9489 * {@link #AUTOFILL_HINT_EMAIL_ADDRESS}, 9490 * {@link #AUTOFILL_HINT_NAME}, 9491 * {@link #AUTOFILL_HINT_PHONE}, 9492 * {@link #AUTOFILL_HINT_POSTAL_ADDRESS}, {@link #AUTOFILL_HINT_POSTAL_CODE}, 9493 * {@link #AUTOFILL_HINT_CREDIT_CARD_NUMBER}, {@link #AUTOFILL_HINT_CREDIT_CARD_SECURITY_CODE}, 9494 * {@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE}, 9495 * {@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DAY}, 9496 * {@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH} or 9497 * {@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR}. 9498 * 9499 * @param autofillHints The autofill hints to set. If the array is emtpy, {@code null} is set. 9500 * @attr ref android.R.styleable#View_autofillHints 9501 */ 9502 public void setAutofillHints(@Nullable String... autofillHints) { 9503 if (autofillHints == null || autofillHints.length == 0) { 9504 mAutofillHints = null; 9505 } else { 9506 mAutofillHints = autofillHints; 9507 } 9508 } 9509 9510 /** 9511 * @hide 9512 */ 9513 @TestApi 9514 public void setAutofilled(boolean isAutofilled) { 9515 boolean wasChanged = isAutofilled != isAutofilled(); 9516 9517 if (wasChanged) { 9518 if (isAutofilled) { 9519 mPrivateFlags3 |= PFLAG3_IS_AUTOFILLED; 9520 } else { 9521 mPrivateFlags3 &= ~PFLAG3_IS_AUTOFILLED; 9522 } 9523 9524 invalidate(); 9525 } 9526 } 9527 9528 /** 9529 * Set whether this view should have sound effects enabled for events such as 9530 * clicking and touching. 9531 * 9532 * <p>You may wish to disable sound effects for a view if you already play sounds, 9533 * for instance, a dial key that plays dtmf tones. 9534 * 9535 * @param soundEffectsEnabled whether sound effects are enabled for this view. 9536 * @see #isSoundEffectsEnabled() 9537 * @see #playSoundEffect(int) 9538 * @attr ref android.R.styleable#View_soundEffectsEnabled 9539 */ 9540 public void setSoundEffectsEnabled(boolean soundEffectsEnabled) { 9541 setFlags(soundEffectsEnabled ? SOUND_EFFECTS_ENABLED: 0, SOUND_EFFECTS_ENABLED); 9542 } 9543 9544 /** 9545 * @return whether this view should have sound effects enabled for events such as 9546 * clicking and touching. 9547 * 9548 * @see #setSoundEffectsEnabled(boolean) 9549 * @see #playSoundEffect(int) 9550 * @attr ref android.R.styleable#View_soundEffectsEnabled 9551 */ 9552 @ViewDebug.ExportedProperty 9553 public boolean isSoundEffectsEnabled() { 9554 return SOUND_EFFECTS_ENABLED == (mViewFlags & SOUND_EFFECTS_ENABLED); 9555 } 9556 9557 /** 9558 * Set whether this view should have haptic feedback for events such as 9559 * long presses. 9560 * 9561 * <p>You may wish to disable haptic feedback if your view already controls 9562 * its own haptic feedback. 9563 * 9564 * @param hapticFeedbackEnabled whether haptic feedback enabled for this view. 9565 * @see #isHapticFeedbackEnabled() 9566 * @see #performHapticFeedback(int) 9567 * @attr ref android.R.styleable#View_hapticFeedbackEnabled 9568 */ 9569 public void setHapticFeedbackEnabled(boolean hapticFeedbackEnabled) { 9570 setFlags(hapticFeedbackEnabled ? HAPTIC_FEEDBACK_ENABLED: 0, HAPTIC_FEEDBACK_ENABLED); 9571 } 9572 9573 /** 9574 * @return whether this view should have haptic feedback enabled for events 9575 * long presses. 9576 * 9577 * @see #setHapticFeedbackEnabled(boolean) 9578 * @see #performHapticFeedback(int) 9579 * @attr ref android.R.styleable#View_hapticFeedbackEnabled 9580 */ 9581 @ViewDebug.ExportedProperty 9582 public boolean isHapticFeedbackEnabled() { 9583 return HAPTIC_FEEDBACK_ENABLED == (mViewFlags & HAPTIC_FEEDBACK_ENABLED); 9584 } 9585 9586 /** 9587 * Returns the layout direction for this view. 9588 * 9589 * @return One of {@link #LAYOUT_DIRECTION_LTR}, 9590 * {@link #LAYOUT_DIRECTION_RTL}, 9591 * {@link #LAYOUT_DIRECTION_INHERIT} or 9592 * {@link #LAYOUT_DIRECTION_LOCALE}. 9593 * 9594 * @attr ref android.R.styleable#View_layoutDirection 9595 * 9596 * @hide 9597 */ 9598 @ViewDebug.ExportedProperty(category = "layout", mapping = { 9599 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_LTR, to = "LTR"), 9600 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_RTL, to = "RTL"), 9601 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_INHERIT, to = "INHERIT"), 9602 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_LOCALE, to = "LOCALE") 9603 }) 9604 @LayoutDir 9605 public int getRawLayoutDirection() { 9606 return (mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_MASK) >> PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 9607 } 9608 9609 /** 9610 * Set the layout direction for this view. This will propagate a reset of layout direction 9611 * resolution to the view's children and resolve layout direction for this view. 9612 * 9613 * @param layoutDirection the layout direction to set. Should be one of: 9614 * 9615 * {@link #LAYOUT_DIRECTION_LTR}, 9616 * {@link #LAYOUT_DIRECTION_RTL}, 9617 * {@link #LAYOUT_DIRECTION_INHERIT}, 9618 * {@link #LAYOUT_DIRECTION_LOCALE}. 9619 * 9620 * Resolution will be done if the value is set to LAYOUT_DIRECTION_INHERIT. The resolution 9621 * proceeds up the parent chain of the view to get the value. If there is no parent, then it 9622 * will return the default {@link #LAYOUT_DIRECTION_LTR}. 9623 * 9624 * @attr ref android.R.styleable#View_layoutDirection 9625 */ 9626 @RemotableViewMethod 9627 public void setLayoutDirection(@LayoutDir int layoutDirection) { 9628 if (getRawLayoutDirection() != layoutDirection) { 9629 // Reset the current layout direction and the resolved one 9630 mPrivateFlags2 &= ~PFLAG2_LAYOUT_DIRECTION_MASK; 9631 resetRtlProperties(); 9632 // Set the new layout direction (filtered) 9633 mPrivateFlags2 |= 9634 ((layoutDirection << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT) & PFLAG2_LAYOUT_DIRECTION_MASK); 9635 // We need to resolve all RTL properties as they all depend on layout direction 9636 resolveRtlPropertiesIfNeeded(); 9637 requestLayout(); 9638 invalidate(true); 9639 } 9640 } 9641 9642 /** 9643 * Returns the resolved layout direction for this view. 9644 * 9645 * @return {@link #LAYOUT_DIRECTION_RTL} if the layout direction is RTL or returns 9646 * {@link #LAYOUT_DIRECTION_LTR} if the layout direction is not RTL. 9647 * 9648 * For compatibility, this will return {@link #LAYOUT_DIRECTION_LTR} if API version 9649 * is lower than {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR1}. 9650 * 9651 * @attr ref android.R.styleable#View_layoutDirection 9652 */ 9653 @ViewDebug.ExportedProperty(category = "layout", mapping = { 9654 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_LTR, to = "RESOLVED_DIRECTION_LTR"), 9655 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_RTL, to = "RESOLVED_DIRECTION_RTL") 9656 }) 9657 @ResolvedLayoutDir 9658 public int getLayoutDirection() { 9659 final int targetSdkVersion = getContext().getApplicationInfo().targetSdkVersion; 9660 if (targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR1) { 9661 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED; 9662 return LAYOUT_DIRECTION_RESOLVED_DEFAULT; 9663 } 9664 return ((mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL) == 9665 PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL) ? LAYOUT_DIRECTION_RTL : LAYOUT_DIRECTION_LTR; 9666 } 9667 9668 /** 9669 * Indicates whether or not this view's layout is right-to-left. This is resolved from 9670 * layout attribute and/or the inherited value from the parent 9671 * 9672 * @return true if the layout is right-to-left. 9673 * 9674 * @hide 9675 */ 9676 @ViewDebug.ExportedProperty(category = "layout") 9677 public boolean isLayoutRtl() { 9678 return (getLayoutDirection() == LAYOUT_DIRECTION_RTL); 9679 } 9680 9681 /** 9682 * Indicates whether the view is currently tracking transient state that the 9683 * app should not need to concern itself with saving and restoring, but that 9684 * the framework should take special note to preserve when possible. 9685 * 9686 * <p>A view with transient state cannot be trivially rebound from an external 9687 * data source, such as an adapter binding item views in a list. This may be 9688 * because the view is performing an animation, tracking user selection 9689 * of content, or similar.</p> 9690 * 9691 * @return true if the view has transient state 9692 */ 9693 @ViewDebug.ExportedProperty(category = "layout") 9694 public boolean hasTransientState() { 9695 return (mPrivateFlags2 & PFLAG2_HAS_TRANSIENT_STATE) == PFLAG2_HAS_TRANSIENT_STATE; 9696 } 9697 9698 /** 9699 * Set whether this view is currently tracking transient state that the 9700 * framework should attempt to preserve when possible. This flag is reference counted, 9701 * so every call to setHasTransientState(true) should be paired with a later call 9702 * to setHasTransientState(false). 9703 * 9704 * <p>A view with transient state cannot be trivially rebound from an external 9705 * data source, such as an adapter binding item views in a list. This may be 9706 * because the view is performing an animation, tracking user selection 9707 * of content, or similar.</p> 9708 * 9709 * @param hasTransientState true if this view has transient state 9710 */ 9711 public void setHasTransientState(boolean hasTransientState) { 9712 mTransientStateCount = hasTransientState ? mTransientStateCount + 1 : 9713 mTransientStateCount - 1; 9714 if (mTransientStateCount < 0) { 9715 mTransientStateCount = 0; 9716 Log.e(VIEW_LOG_TAG, "hasTransientState decremented below 0: " + 9717 "unmatched pair of setHasTransientState calls"); 9718 } else if ((hasTransientState && mTransientStateCount == 1) || 9719 (!hasTransientState && mTransientStateCount == 0)) { 9720 // update flag if we've just incremented up from 0 or decremented down to 0 9721 mPrivateFlags2 = (mPrivateFlags2 & ~PFLAG2_HAS_TRANSIENT_STATE) | 9722 (hasTransientState ? PFLAG2_HAS_TRANSIENT_STATE : 0); 9723 if (mParent != null) { 9724 try { 9725 mParent.childHasTransientStateChanged(this, hasTransientState); 9726 } catch (AbstractMethodError e) { 9727 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 9728 " does not fully implement ViewParent", e); 9729 } 9730 } 9731 } 9732 } 9733 9734 /** 9735 * Returns true if this view is currently attached to a window. 9736 */ 9737 public boolean isAttachedToWindow() { 9738 return mAttachInfo != null; 9739 } 9740 9741 /** 9742 * Returns true if this view has been through at least one layout since it 9743 * was last attached to or detached from a window. 9744 */ 9745 public boolean isLaidOut() { 9746 return (mPrivateFlags3 & PFLAG3_IS_LAID_OUT) == PFLAG3_IS_LAID_OUT; 9747 } 9748 9749 /** 9750 * If this view doesn't do any drawing on its own, set this flag to 9751 * allow further optimizations. By default, this flag is not set on 9752 * View, but could be set on some View subclasses such as ViewGroup. 9753 * 9754 * Typically, if you override {@link #onDraw(android.graphics.Canvas)} 9755 * you should clear this flag. 9756 * 9757 * @param willNotDraw whether or not this View draw on its own 9758 */ 9759 public void setWillNotDraw(boolean willNotDraw) { 9760 setFlags(willNotDraw ? WILL_NOT_DRAW : 0, DRAW_MASK); 9761 } 9762 9763 /** 9764 * Returns whether or not this View draws on its own. 9765 * 9766 * @return true if this view has nothing to draw, false otherwise 9767 */ 9768 @ViewDebug.ExportedProperty(category = "drawing") 9769 public boolean willNotDraw() { 9770 return (mViewFlags & DRAW_MASK) == WILL_NOT_DRAW; 9771 } 9772 9773 /** 9774 * When a View's drawing cache is enabled, drawing is redirected to an 9775 * offscreen bitmap. Some views, like an ImageView, must be able to 9776 * bypass this mechanism if they already draw a single bitmap, to avoid 9777 * unnecessary usage of the memory. 9778 * 9779 * @param willNotCacheDrawing true if this view does not cache its 9780 * drawing, false otherwise 9781 */ 9782 public void setWillNotCacheDrawing(boolean willNotCacheDrawing) { 9783 setFlags(willNotCacheDrawing ? WILL_NOT_CACHE_DRAWING : 0, WILL_NOT_CACHE_DRAWING); 9784 } 9785 9786 /** 9787 * Returns whether or not this View can cache its drawing or not. 9788 * 9789 * @return true if this view does not cache its drawing, false otherwise 9790 */ 9791 @ViewDebug.ExportedProperty(category = "drawing") 9792 public boolean willNotCacheDrawing() { 9793 return (mViewFlags & WILL_NOT_CACHE_DRAWING) == WILL_NOT_CACHE_DRAWING; 9794 } 9795 9796 /** 9797 * Indicates whether this view reacts to click events or not. 9798 * 9799 * @return true if the view is clickable, false otherwise 9800 * 9801 * @see #setClickable(boolean) 9802 * @attr ref android.R.styleable#View_clickable 9803 */ 9804 @ViewDebug.ExportedProperty 9805 public boolean isClickable() { 9806 return (mViewFlags & CLICKABLE) == CLICKABLE; 9807 } 9808 9809 /** 9810 * Enables or disables click events for this view. When a view 9811 * is clickable it will change its state to "pressed" on every click. 9812 * Subclasses should set the view clickable to visually react to 9813 * user's clicks. 9814 * 9815 * @param clickable true to make the view clickable, false otherwise 9816 * 9817 * @see #isClickable() 9818 * @attr ref android.R.styleable#View_clickable 9819 */ 9820 public void setClickable(boolean clickable) { 9821 setFlags(clickable ? CLICKABLE : 0, CLICKABLE); 9822 } 9823 9824 /** 9825 * Indicates whether this view reacts to long click events or not. 9826 * 9827 * @return true if the view is long clickable, false otherwise 9828 * 9829 * @see #setLongClickable(boolean) 9830 * @attr ref android.R.styleable#View_longClickable 9831 */ 9832 public boolean isLongClickable() { 9833 return (mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE; 9834 } 9835 9836 /** 9837 * Enables or disables long click events for this view. When a view is long 9838 * clickable it reacts to the user holding down the button for a longer 9839 * duration than a tap. This event can either launch the listener or a 9840 * context menu. 9841 * 9842 * @param longClickable true to make the view long clickable, false otherwise 9843 * @see #isLongClickable() 9844 * @attr ref android.R.styleable#View_longClickable 9845 */ 9846 public void setLongClickable(boolean longClickable) { 9847 setFlags(longClickable ? LONG_CLICKABLE : 0, LONG_CLICKABLE); 9848 } 9849 9850 /** 9851 * Indicates whether this view reacts to context clicks or not. 9852 * 9853 * @return true if the view is context clickable, false otherwise 9854 * @see #setContextClickable(boolean) 9855 * @attr ref android.R.styleable#View_contextClickable 9856 */ 9857 public boolean isContextClickable() { 9858 return (mViewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE; 9859 } 9860 9861 /** 9862 * Enables or disables context clicking for this view. This event can launch the listener. 9863 * 9864 * @param contextClickable true to make the view react to a context click, false otherwise 9865 * @see #isContextClickable() 9866 * @attr ref android.R.styleable#View_contextClickable 9867 */ 9868 public void setContextClickable(boolean contextClickable) { 9869 setFlags(contextClickable ? CONTEXT_CLICKABLE : 0, CONTEXT_CLICKABLE); 9870 } 9871 9872 /** 9873 * Sets the pressed state for this view and provides a touch coordinate for 9874 * animation hinting. 9875 * 9876 * @param pressed Pass true to set the View's internal state to "pressed", 9877 * or false to reverts the View's internal state from a 9878 * previously set "pressed" state. 9879 * @param x The x coordinate of the touch that caused the press 9880 * @param y The y coordinate of the touch that caused the press 9881 */ 9882 private void setPressed(boolean pressed, float x, float y) { 9883 if (pressed) { 9884 drawableHotspotChanged(x, y); 9885 } 9886 9887 setPressed(pressed); 9888 } 9889 9890 /** 9891 * Sets the pressed state for this view. 9892 * 9893 * @see #isClickable() 9894 * @see #setClickable(boolean) 9895 * 9896 * @param pressed Pass true to set the View's internal state to "pressed", or false to reverts 9897 * the View's internal state from a previously set "pressed" state. 9898 */ 9899 public void setPressed(boolean pressed) { 9900 final boolean needsRefresh = pressed != ((mPrivateFlags & PFLAG_PRESSED) == PFLAG_PRESSED); 9901 9902 if (pressed) { 9903 mPrivateFlags |= PFLAG_PRESSED; 9904 } else { 9905 mPrivateFlags &= ~PFLAG_PRESSED; 9906 } 9907 9908 if (needsRefresh) { 9909 refreshDrawableState(); 9910 } 9911 dispatchSetPressed(pressed); 9912 } 9913 9914 /** 9915 * Dispatch setPressed to all of this View's children. 9916 * 9917 * @see #setPressed(boolean) 9918 * 9919 * @param pressed The new pressed state 9920 */ 9921 protected void dispatchSetPressed(boolean pressed) { 9922 } 9923 9924 /** 9925 * Indicates whether the view is currently in pressed state. Unless 9926 * {@link #setPressed(boolean)} is explicitly called, only clickable views can enter 9927 * the pressed state. 9928 * 9929 * @see #setPressed(boolean) 9930 * @see #isClickable() 9931 * @see #setClickable(boolean) 9932 * 9933 * @return true if the view is currently pressed, false otherwise 9934 */ 9935 @ViewDebug.ExportedProperty 9936 public boolean isPressed() { 9937 return (mPrivateFlags & PFLAG_PRESSED) == PFLAG_PRESSED; 9938 } 9939 9940 /** 9941 * @hide 9942 * Indicates whether this view will participate in data collection through 9943 * {@link ViewStructure}. If true, it will not provide any data 9944 * for itself or its children. If false, the normal data collection will be allowed. 9945 * 9946 * @return Returns false if assist data collection is not blocked, else true. 9947 * 9948 * @see #setAssistBlocked(boolean) 9949 * @attr ref android.R.styleable#View_assistBlocked 9950 */ 9951 public boolean isAssistBlocked() { 9952 return (mPrivateFlags3 & PFLAG3_ASSIST_BLOCKED) != 0; 9953 } 9954 9955 /** 9956 * @hide 9957 * Controls whether assist data collection from this view and its children is enabled 9958 * (that is, whether {@link #onProvideStructure} and 9959 * {@link #onProvideVirtualStructure} will be called). The default value is false, 9960 * allowing normal assist collection. Setting this to false will disable assist collection. 9961 * 9962 * @param enabled Set to true to <em>disable</em> assist data collection, or false 9963 * (the default) to allow it. 9964 * 9965 * @see #isAssistBlocked() 9966 * @see #onProvideStructure 9967 * @see #onProvideVirtualStructure 9968 * @attr ref android.R.styleable#View_assistBlocked 9969 */ 9970 public void setAssistBlocked(boolean enabled) { 9971 if (enabled) { 9972 mPrivateFlags3 |= PFLAG3_ASSIST_BLOCKED; 9973 } else { 9974 mPrivateFlags3 &= ~PFLAG3_ASSIST_BLOCKED; 9975 } 9976 } 9977 9978 /** 9979 * Indicates whether this view will save its state (that is, 9980 * whether its {@link #onSaveInstanceState} method will be called). 9981 * 9982 * @return Returns true if the view state saving is enabled, else false. 9983 * 9984 * @see #setSaveEnabled(boolean) 9985 * @attr ref android.R.styleable#View_saveEnabled 9986 */ 9987 public boolean isSaveEnabled() { 9988 return (mViewFlags & SAVE_DISABLED_MASK) != SAVE_DISABLED; 9989 } 9990 9991 /** 9992 * Controls whether the saving of this view's state is 9993 * enabled (that is, whether its {@link #onSaveInstanceState} method 9994 * will be called). Note that even if freezing is enabled, the 9995 * view still must have an id assigned to it (via {@link #setId(int)}) 9996 * for its state to be saved. This flag can only disable the 9997 * saving of this view; any child views may still have their state saved. 9998 * 9999 * @param enabled Set to false to <em>disable</em> state saving, or true 10000 * (the default) to allow it. 10001 * 10002 * @see #isSaveEnabled() 10003 * @see #setId(int) 10004 * @see #onSaveInstanceState() 10005 * @attr ref android.R.styleable#View_saveEnabled 10006 */ 10007 public void setSaveEnabled(boolean enabled) { 10008 setFlags(enabled ? 0 : SAVE_DISABLED, SAVE_DISABLED_MASK); 10009 } 10010 10011 /** 10012 * Gets whether the framework should discard touches when the view's 10013 * window is obscured by another visible window. 10014 * Refer to the {@link View} security documentation for more details. 10015 * 10016 * @return True if touch filtering is enabled. 10017 * 10018 * @see #setFilterTouchesWhenObscured(boolean) 10019 * @attr ref android.R.styleable#View_filterTouchesWhenObscured 10020 */ 10021 @ViewDebug.ExportedProperty 10022 public boolean getFilterTouchesWhenObscured() { 10023 return (mViewFlags & FILTER_TOUCHES_WHEN_OBSCURED) != 0; 10024 } 10025 10026 /** 10027 * Sets whether the framework should discard touches when the view's 10028 * window is obscured by another visible window. 10029 * Refer to the {@link View} security documentation for more details. 10030 * 10031 * @param enabled True if touch filtering should be enabled. 10032 * 10033 * @see #getFilterTouchesWhenObscured 10034 * @attr ref android.R.styleable#View_filterTouchesWhenObscured 10035 */ 10036 public void setFilterTouchesWhenObscured(boolean enabled) { 10037 setFlags(enabled ? FILTER_TOUCHES_WHEN_OBSCURED : 0, 10038 FILTER_TOUCHES_WHEN_OBSCURED); 10039 } 10040 10041 /** 10042 * Indicates whether the entire hierarchy under this view will save its 10043 * state when a state saving traversal occurs from its parent. The default 10044 * is true; if false, these views will not be saved unless 10045 * {@link #saveHierarchyState(SparseArray)} is called directly on this view. 10046 * 10047 * @return Returns true if the view state saving from parent is enabled, else false. 10048 * 10049 * @see #setSaveFromParentEnabled(boolean) 10050 */ 10051 public boolean isSaveFromParentEnabled() { 10052 return (mViewFlags & PARENT_SAVE_DISABLED_MASK) != PARENT_SAVE_DISABLED; 10053 } 10054 10055 /** 10056 * Controls whether the entire hierarchy under this view will save its 10057 * state when a state saving traversal occurs from its parent. The default 10058 * is true; if false, these views will not be saved unless 10059 * {@link #saveHierarchyState(SparseArray)} is called directly on this view. 10060 * 10061 * @param enabled Set to false to <em>disable</em> state saving, or true 10062 * (the default) to allow it. 10063 * 10064 * @see #isSaveFromParentEnabled() 10065 * @see #setId(int) 10066 * @see #onSaveInstanceState() 10067 */ 10068 public void setSaveFromParentEnabled(boolean enabled) { 10069 setFlags(enabled ? 0 : PARENT_SAVE_DISABLED, PARENT_SAVE_DISABLED_MASK); 10070 } 10071 10072 10073 /** 10074 * Returns whether this View is currently able to take focus. 10075 * 10076 * @return True if this view can take focus, or false otherwise. 10077 */ 10078 @ViewDebug.ExportedProperty(category = "focus") 10079 public final boolean isFocusable() { 10080 return FOCUSABLE == (mViewFlags & FOCUSABLE); 10081 } 10082 10083 /** 10084 * Returns the focusable setting for this view. 10085 * 10086 * @return One of {@link #NOT_FOCUSABLE}, {@link #FOCUSABLE}, or {@link #FOCUSABLE_AUTO}. 10087 * @attr ref android.R.styleable#View_focusable 10088 */ 10089 @ViewDebug.ExportedProperty(mapping = { 10090 @ViewDebug.IntToString(from = NOT_FOCUSABLE, to = "NOT_FOCUSABLE"), 10091 @ViewDebug.IntToString(from = FOCUSABLE, to = "FOCUSABLE"), 10092 @ViewDebug.IntToString(from = FOCUSABLE_AUTO, to = "FOCUSABLE_AUTO") 10093 }, category = "focus") 10094 @Focusable 10095 public int getFocusable() { 10096 return (mViewFlags & FOCUSABLE_AUTO) > 0 ? FOCUSABLE_AUTO : mViewFlags & FOCUSABLE; 10097 } 10098 10099 /** 10100 * When a view is focusable, it may not want to take focus when in touch mode. 10101 * For example, a button would like focus when the user is navigating via a D-pad 10102 * so that the user can click on it, but once the user starts touching the screen, 10103 * the button shouldn't take focus 10104 * @return Whether the view is focusable in touch mode. 10105 * @attr ref android.R.styleable#View_focusableInTouchMode 10106 */ 10107 @ViewDebug.ExportedProperty(category = "focus") 10108 public final boolean isFocusableInTouchMode() { 10109 return FOCUSABLE_IN_TOUCH_MODE == (mViewFlags & FOCUSABLE_IN_TOUCH_MODE); 10110 } 10111 10112 /** 10113 * Find the nearest view in the specified direction that can take focus. 10114 * This does not actually give focus to that view. 10115 * 10116 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT 10117 * 10118 * @return The nearest focusable in the specified direction, or null if none 10119 * can be found. 10120 */ 10121 public View focusSearch(@FocusRealDirection int direction) { 10122 if (mParent != null) { 10123 return mParent.focusSearch(this, direction); 10124 } else { 10125 return null; 10126 } 10127 } 10128 10129 /** 10130 * Returns whether this View is a root of a keyboard navigation cluster. 10131 * 10132 * @return True if this view is a root of a cluster, or false otherwise. 10133 * @attr ref android.R.styleable#View_keyboardNavigationCluster 10134 */ 10135 @ViewDebug.ExportedProperty(category = "focus") 10136 public final boolean isKeyboardNavigationCluster() { 10137 return (mPrivateFlags3 & PFLAG3_CLUSTER) != 0; 10138 } 10139 10140 /** 10141 * Searches up the view hierarchy to find the top-most cluster. All deeper/nested clusters 10142 * will be ignored. 10143 * 10144 * @return the keyboard navigation cluster that this view is in (can be this view) 10145 * or {@code null} if not in one 10146 */ 10147 View findKeyboardNavigationCluster() { 10148 if (mParent instanceof View) { 10149 View cluster = ((View) mParent).findKeyboardNavigationCluster(); 10150 if (cluster != null) { 10151 return cluster; 10152 } else if (isKeyboardNavigationCluster()) { 10153 return this; 10154 } 10155 } 10156 return null; 10157 } 10158 10159 /** 10160 * Set whether this view is a root of a keyboard navigation cluster. 10161 * 10162 * @param isCluster If true, this view is a root of a cluster. 10163 * 10164 * @attr ref android.R.styleable#View_keyboardNavigationCluster 10165 */ 10166 public void setKeyboardNavigationCluster(boolean isCluster) { 10167 if (isCluster) { 10168 mPrivateFlags3 |= PFLAG3_CLUSTER; 10169 } else { 10170 mPrivateFlags3 &= ~PFLAG3_CLUSTER; 10171 } 10172 } 10173 10174 /** 10175 * Sets this View as the one which receives focus the next time cluster navigation jumps 10176 * to the cluster containing this View. This does NOT change focus even if the cluster 10177 * containing this view is current. 10178 * 10179 * @hide 10180 */ 10181 public final void setFocusedInCluster() { 10182 setFocusedInCluster(findKeyboardNavigationCluster()); 10183 } 10184 10185 private void setFocusedInCluster(View cluster) { 10186 if (this instanceof ViewGroup) { 10187 ((ViewGroup) this).mFocusedInCluster = null; 10188 } 10189 if (cluster == this) { 10190 return; 10191 } 10192 ViewParent parent = mParent; 10193 View child = this; 10194 while (parent instanceof ViewGroup) { 10195 ((ViewGroup) parent).mFocusedInCluster = child; 10196 if (parent == cluster) { 10197 break; 10198 } 10199 child = (View) parent; 10200 parent = parent.getParent(); 10201 } 10202 } 10203 10204 private void updateFocusedInCluster(View oldFocus, @FocusDirection int direction) { 10205 if (oldFocus != null) { 10206 View oldCluster = oldFocus.findKeyboardNavigationCluster(); 10207 View cluster = findKeyboardNavigationCluster(); 10208 if (oldCluster != cluster) { 10209 // Going from one cluster to another, so save last-focused. 10210 // This covers cluster jumps because they are always FOCUS_DOWN 10211 oldFocus.setFocusedInCluster(oldCluster); 10212 if (!(oldFocus.mParent instanceof ViewGroup)) { 10213 return; 10214 } 10215 if (direction == FOCUS_FORWARD || direction == FOCUS_BACKWARD) { 10216 // This is a result of ordered navigation so consider navigation through 10217 // the previous cluster "complete" and clear its last-focused memory. 10218 ((ViewGroup) oldFocus.mParent).clearFocusedInCluster(oldFocus); 10219 } else if (oldFocus instanceof ViewGroup 10220 && ((ViewGroup) oldFocus).getDescendantFocusability() 10221 == ViewGroup.FOCUS_AFTER_DESCENDANTS 10222 && ViewRootImpl.isViewDescendantOf(this, oldFocus)) { 10223 // This means oldFocus is not focusable since it obviously has a focusable 10224 // child (this). Don't restore focus to it in the future. 10225 ((ViewGroup) oldFocus.mParent).clearFocusedInCluster(oldFocus); 10226 } 10227 } 10228 } 10229 } 10230 10231 /** 10232 * Returns whether this View should receive focus when the focus is restored for the view 10233 * hierarchy containing this view. 10234 * <p> 10235 * Focus gets restored for a view hierarchy when the root of the hierarchy gets added to a 10236 * window or serves as a target of cluster navigation. 10237 * 10238 * @see #restoreDefaultFocus() 10239 * 10240 * @return {@code true} if this view is the default-focus view, {@code false} otherwise 10241 * @attr ref android.R.styleable#View_focusedByDefault 10242 */ 10243 @ViewDebug.ExportedProperty(category = "focus") 10244 public final boolean isFocusedByDefault() { 10245 return (mPrivateFlags3 & PFLAG3_FOCUSED_BY_DEFAULT) != 0; 10246 } 10247 10248 /** 10249 * Sets whether this View should receive focus when the focus is restored for the view 10250 * hierarchy containing this view. 10251 * <p> 10252 * Focus gets restored for a view hierarchy when the root of the hierarchy gets added to a 10253 * window or serves as a target of cluster navigation. 10254 * 10255 * @param isFocusedByDefault {@code true} to set this view as the default-focus view, 10256 * {@code false} otherwise. 10257 * 10258 * @see #restoreDefaultFocus() 10259 * 10260 * @attr ref android.R.styleable#View_focusedByDefault 10261 */ 10262 public void setFocusedByDefault(boolean isFocusedByDefault) { 10263 if (isFocusedByDefault == ((mPrivateFlags3 & PFLAG3_FOCUSED_BY_DEFAULT) != 0)) { 10264 return; 10265 } 10266 10267 if (isFocusedByDefault) { 10268 mPrivateFlags3 |= PFLAG3_FOCUSED_BY_DEFAULT; 10269 } else { 10270 mPrivateFlags3 &= ~PFLAG3_FOCUSED_BY_DEFAULT; 10271 } 10272 10273 if (mParent instanceof ViewGroup) { 10274 if (isFocusedByDefault) { 10275 ((ViewGroup) mParent).setDefaultFocus(this); 10276 } else { 10277 ((ViewGroup) mParent).clearDefaultFocus(this); 10278 } 10279 } 10280 } 10281 10282 /** 10283 * Returns whether the view hierarchy with this view as a root contain a default-focus view. 10284 * 10285 * @return {@code true} if this view has default focus, {@code false} otherwise 10286 */ 10287 boolean hasDefaultFocus() { 10288 return isFocusedByDefault(); 10289 } 10290 10291 /** 10292 * Find the nearest keyboard navigation cluster in the specified direction. 10293 * This does not actually give focus to that cluster. 10294 * 10295 * @param currentCluster The starting point of the search. Null means the current cluster is not 10296 * found yet 10297 * @param direction Direction to look 10298 * 10299 * @return The nearest keyboard navigation cluster in the specified direction, or null if none 10300 * can be found 10301 */ 10302 public View keyboardNavigationClusterSearch(View currentCluster, 10303 @FocusDirection int direction) { 10304 if (isKeyboardNavigationCluster()) { 10305 currentCluster = this; 10306 } 10307 if (isRootNamespace()) { 10308 // Root namespace means we should consider ourselves the top of the 10309 // tree for group searching; otherwise we could be group searching 10310 // into other tabs. see LocalActivityManager and TabHost for more info. 10311 return FocusFinder.getInstance().findNextKeyboardNavigationCluster( 10312 this, currentCluster, direction); 10313 } else if (mParent != null) { 10314 return mParent.keyboardNavigationClusterSearch(currentCluster, direction); 10315 } 10316 return null; 10317 } 10318 10319 /** 10320 * This method is the last chance for the focused view and its ancestors to 10321 * respond to an arrow key. This is called when the focused view did not 10322 * consume the key internally, nor could the view system find a new view in 10323 * the requested direction to give focus to. 10324 * 10325 * @param focused The currently focused view. 10326 * @param direction The direction focus wants to move. One of FOCUS_UP, 10327 * FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT. 10328 * @return True if the this view consumed this unhandled move. 10329 */ 10330 public boolean dispatchUnhandledMove(View focused, @FocusRealDirection int direction) { 10331 return false; 10332 } 10333 10334 /** 10335 * Sets whether this View should use a default focus highlight when it gets focused but doesn't 10336 * have {@link android.R.attr#state_focused} defined in its background. 10337 * 10338 * @param defaultFocusHighlightEnabled {@code true} to set this view to use a default focus 10339 * highlight, {@code false} otherwise. 10340 * 10341 * @attr ref android.R.styleable#View_defaultFocusHighlightEnabled 10342 */ 10343 public void setDefaultFocusHighlightEnabled(boolean defaultFocusHighlightEnabled) { 10344 mDefaultFocusHighlightEnabled = defaultFocusHighlightEnabled; 10345 } 10346 10347 /** 10348 10349 /** 10350 * Returns whether this View should use a default focus highlight when it gets focused but 10351 * doesn't have {@link android.R.attr#state_focused} defined in its background. 10352 * 10353 * @return True if this View should use a default focus highlight. 10354 * @attr ref android.R.styleable#View_defaultFocusHighlightEnabled 10355 */ 10356 @ViewDebug.ExportedProperty(category = "focus") 10357 public final boolean getDefaultFocusHighlightEnabled() { 10358 return mDefaultFocusHighlightEnabled; 10359 } 10360 10361 /** 10362 * If a user manually specified the next view id for a particular direction, 10363 * use the root to look up the view. 10364 * @param root The root view of the hierarchy containing this view. 10365 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, FOCUS_RIGHT, FOCUS_FORWARD, 10366 * or FOCUS_BACKWARD. 10367 * @return The user specified next view, or null if there is none. 10368 */ 10369 View findUserSetNextFocus(View root, @FocusDirection int direction) { 10370 switch (direction) { 10371 case FOCUS_LEFT: 10372 if (mNextFocusLeftId == View.NO_ID) return null; 10373 return findViewInsideOutShouldExist(root, mNextFocusLeftId); 10374 case FOCUS_RIGHT: 10375 if (mNextFocusRightId == View.NO_ID) return null; 10376 return findViewInsideOutShouldExist(root, mNextFocusRightId); 10377 case FOCUS_UP: 10378 if (mNextFocusUpId == View.NO_ID) return null; 10379 return findViewInsideOutShouldExist(root, mNextFocusUpId); 10380 case FOCUS_DOWN: 10381 if (mNextFocusDownId == View.NO_ID) return null; 10382 return findViewInsideOutShouldExist(root, mNextFocusDownId); 10383 case FOCUS_FORWARD: 10384 if (mNextFocusForwardId == View.NO_ID) return null; 10385 return findViewInsideOutShouldExist(root, mNextFocusForwardId); 10386 case FOCUS_BACKWARD: { 10387 if (mID == View.NO_ID) return null; 10388 final int id = mID; 10389 return root.findViewByPredicateInsideOut(this, new Predicate<View>() { 10390 @Override 10391 public boolean test(View t) { 10392 return t.mNextFocusForwardId == id; 10393 } 10394 }); 10395 } 10396 } 10397 return null; 10398 } 10399 10400 /** 10401 * If a user manually specified the next keyboard-navigation cluster for a particular direction, 10402 * use the root to look up the view. 10403 * 10404 * @param root the root view of the hierarchy containing this view 10405 * @param direction {@link #FOCUS_FORWARD} or {@link #FOCUS_BACKWARD} 10406 * @return the user-specified next cluster, or {@code null} if there is none 10407 */ 10408 View findUserSetNextKeyboardNavigationCluster(View root, @FocusDirection int direction) { 10409 switch (direction) { 10410 case FOCUS_FORWARD: 10411 if (mNextClusterForwardId == View.NO_ID) return null; 10412 return findViewInsideOutShouldExist(root, mNextClusterForwardId); 10413 case FOCUS_BACKWARD: { 10414 if (mID == View.NO_ID) return null; 10415 final int id = mID; 10416 return root.findViewByPredicateInsideOut(this, 10417 (Predicate<View>) t -> t.mNextClusterForwardId == id); 10418 } 10419 } 10420 return null; 10421 } 10422 10423 private View findViewInsideOutShouldExist(View root, int id) { 10424 if (mMatchIdPredicate == null) { 10425 mMatchIdPredicate = new MatchIdPredicate(); 10426 } 10427 mMatchIdPredicate.mId = id; 10428 View result = root.findViewByPredicateInsideOut(this, mMatchIdPredicate); 10429 if (result == null) { 10430 Log.w(VIEW_LOG_TAG, "couldn't find view with id " + id); 10431 } 10432 return result; 10433 } 10434 10435 /** 10436 * Find and return all focusable views that are descendants of this view, 10437 * possibly including this view if it is focusable itself. 10438 * 10439 * @param direction The direction of the focus 10440 * @return A list of focusable views 10441 */ 10442 public ArrayList<View> getFocusables(@FocusDirection int direction) { 10443 ArrayList<View> result = new ArrayList<View>(24); 10444 addFocusables(result, direction); 10445 return result; 10446 } 10447 10448 /** 10449 * Add any focusable views that are descendants of this view (possibly 10450 * including this view if it is focusable itself) to views. If we are in touch mode, 10451 * only add views that are also focusable in touch mode. 10452 * 10453 * @param views Focusable views found so far 10454 * @param direction The direction of the focus 10455 */ 10456 public void addFocusables(ArrayList<View> views, @FocusDirection int direction) { 10457 addFocusables(views, direction, isInTouchMode() ? FOCUSABLES_TOUCH_MODE : FOCUSABLES_ALL); 10458 } 10459 10460 /** 10461 * Adds any focusable views that are descendants of this view (possibly 10462 * including this view if it is focusable itself) to views. This method 10463 * adds all focusable views regardless if we are in touch mode or 10464 * only views focusable in touch mode if we are in touch mode or 10465 * only views that can take accessibility focus if accessibility is enabled 10466 * depending on the focusable mode parameter. 10467 * 10468 * @param views Focusable views found so far or null if all we are interested is 10469 * the number of focusables. 10470 * @param direction The direction of the focus. 10471 * @param focusableMode The type of focusables to be added. 10472 * 10473 * @see #FOCUSABLES_ALL 10474 * @see #FOCUSABLES_TOUCH_MODE 10475 */ 10476 public void addFocusables(ArrayList<View> views, @FocusDirection int direction, 10477 @FocusableMode int focusableMode) { 10478 if (views == null) { 10479 return; 10480 } 10481 if (!isFocusable()) { 10482 return; 10483 } 10484 if ((focusableMode & FOCUSABLES_TOUCH_MODE) == FOCUSABLES_TOUCH_MODE 10485 && !isFocusableInTouchMode()) { 10486 return; 10487 } 10488 views.add(this); 10489 } 10490 10491 /** 10492 * Adds any keyboard navigation cluster roots that are descendants of this view (possibly 10493 * including this view if it is a cluster root itself) to views. 10494 * 10495 * @param views Keyboard navigation cluster roots found so far 10496 * @param direction Direction to look 10497 */ 10498 public void addKeyboardNavigationClusters( 10499 @NonNull Collection<View> views, 10500 int direction) { 10501 if (!isKeyboardNavigationCluster()) { 10502 return; 10503 } 10504 if (!hasFocusable()) { 10505 return; 10506 } 10507 views.add(this); 10508 } 10509 10510 /** 10511 * Finds the Views that contain given text. The containment is case insensitive. 10512 * The search is performed by either the text that the View renders or the content 10513 * description that describes the view for accessibility purposes and the view does 10514 * not render or both. Clients can specify how the search is to be performed via 10515 * passing the {@link #FIND_VIEWS_WITH_TEXT} and 10516 * {@link #FIND_VIEWS_WITH_CONTENT_DESCRIPTION} flags. 10517 * 10518 * @param outViews The output list of matching Views. 10519 * @param searched The text to match against. 10520 * 10521 * @see #FIND_VIEWS_WITH_TEXT 10522 * @see #FIND_VIEWS_WITH_CONTENT_DESCRIPTION 10523 * @see #setContentDescription(CharSequence) 10524 */ 10525 public void findViewsWithText(ArrayList<View> outViews, CharSequence searched, 10526 @FindViewFlags int flags) { 10527 if (getAccessibilityNodeProvider() != null) { 10528 if ((flags & FIND_VIEWS_WITH_ACCESSIBILITY_NODE_PROVIDERS) != 0) { 10529 outViews.add(this); 10530 } 10531 } else if ((flags & FIND_VIEWS_WITH_CONTENT_DESCRIPTION) != 0 10532 && (searched != null && searched.length() > 0) 10533 && (mContentDescription != null && mContentDescription.length() > 0)) { 10534 String searchedLowerCase = searched.toString().toLowerCase(); 10535 String contentDescriptionLowerCase = mContentDescription.toString().toLowerCase(); 10536 if (contentDescriptionLowerCase.contains(searchedLowerCase)) { 10537 outViews.add(this); 10538 } 10539 } 10540 } 10541 10542 /** 10543 * Find and return all touchable views that are descendants of this view, 10544 * possibly including this view if it is touchable itself. 10545 * 10546 * @return A list of touchable views 10547 */ 10548 public ArrayList<View> getTouchables() { 10549 ArrayList<View> result = new ArrayList<View>(); 10550 addTouchables(result); 10551 return result; 10552 } 10553 10554 /** 10555 * Add any touchable views that are descendants of this view (possibly 10556 * including this view if it is touchable itself) to views. 10557 * 10558 * @param views Touchable views found so far 10559 */ 10560 public void addTouchables(ArrayList<View> views) { 10561 final int viewFlags = mViewFlags; 10562 10563 if (((viewFlags & CLICKABLE) == CLICKABLE || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE 10564 || (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE) 10565 && (viewFlags & ENABLED_MASK) == ENABLED) { 10566 views.add(this); 10567 } 10568 } 10569 10570 /** 10571 * Returns whether this View is accessibility focused. 10572 * 10573 * @return True if this View is accessibility focused. 10574 */ 10575 public boolean isAccessibilityFocused() { 10576 return (mPrivateFlags2 & PFLAG2_ACCESSIBILITY_FOCUSED) != 0; 10577 } 10578 10579 /** 10580 * Call this to try to give accessibility focus to this view. 10581 * 10582 * A view will not actually take focus if {@link AccessibilityManager#isEnabled()} 10583 * returns false or the view is no visible or the view already has accessibility 10584 * focus. 10585 * 10586 * See also {@link #focusSearch(int)}, which is what you call to say that you 10587 * have focus, and you want your parent to look for the next one. 10588 * 10589 * @return Whether this view actually took accessibility focus. 10590 * 10591 * @hide 10592 */ 10593 public boolean requestAccessibilityFocus() { 10594 AccessibilityManager manager = AccessibilityManager.getInstance(mContext); 10595 if (!manager.isEnabled() || !manager.isTouchExplorationEnabled()) { 10596 return false; 10597 } 10598 if ((mViewFlags & VISIBILITY_MASK) != VISIBLE) { 10599 return false; 10600 } 10601 if ((mPrivateFlags2 & PFLAG2_ACCESSIBILITY_FOCUSED) == 0) { 10602 mPrivateFlags2 |= PFLAG2_ACCESSIBILITY_FOCUSED; 10603 ViewRootImpl viewRootImpl = getViewRootImpl(); 10604 if (viewRootImpl != null) { 10605 viewRootImpl.setAccessibilityFocus(this, null); 10606 } 10607 invalidate(); 10608 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED); 10609 return true; 10610 } 10611 return false; 10612 } 10613 10614 /** 10615 * Call this to try to clear accessibility focus of this view. 10616 * 10617 * See also {@link #focusSearch(int)}, which is what you call to say that you 10618 * have focus, and you want your parent to look for the next one. 10619 * 10620 * @hide 10621 */ 10622 public void clearAccessibilityFocus() { 10623 clearAccessibilityFocusNoCallbacks(0); 10624 10625 // Clear the global reference of accessibility focus if this view or 10626 // any of its descendants had accessibility focus. This will NOT send 10627 // an event or update internal state if focus is cleared from a 10628 // descendant view, which may leave views in inconsistent states. 10629 final ViewRootImpl viewRootImpl = getViewRootImpl(); 10630 if (viewRootImpl != null) { 10631 final View focusHost = viewRootImpl.getAccessibilityFocusedHost(); 10632 if (focusHost != null && ViewRootImpl.isViewDescendantOf(focusHost, this)) { 10633 viewRootImpl.setAccessibilityFocus(null, null); 10634 } 10635 } 10636 } 10637 10638 private void sendAccessibilityHoverEvent(int eventType) { 10639 // Since we are not delivering to a client accessibility events from not 10640 // important views (unless the clinet request that) we need to fire the 10641 // event from the deepest view exposed to the client. As a consequence if 10642 // the user crosses a not exposed view the client will see enter and exit 10643 // of the exposed predecessor followed by and enter and exit of that same 10644 // predecessor when entering and exiting the not exposed descendant. This 10645 // is fine since the client has a clear idea which view is hovered at the 10646 // price of a couple more events being sent. This is a simple and 10647 // working solution. 10648 View source = this; 10649 while (true) { 10650 if (source.includeForAccessibility()) { 10651 source.sendAccessibilityEvent(eventType); 10652 return; 10653 } 10654 ViewParent parent = source.getParent(); 10655 if (parent instanceof View) { 10656 source = (View) parent; 10657 } else { 10658 return; 10659 } 10660 } 10661 } 10662 10663 /** 10664 * Clears accessibility focus without calling any callback methods 10665 * normally invoked in {@link #clearAccessibilityFocus()}. This method 10666 * is used separately from that one for clearing accessibility focus when 10667 * giving this focus to another view. 10668 * 10669 * @param action The action, if any, that led to focus being cleared. Set to 10670 * AccessibilityNodeInfo#ACTION_ACCESSIBILITY_FOCUS to specify that focus is moving within 10671 * the window. 10672 */ 10673 void clearAccessibilityFocusNoCallbacks(int action) { 10674 if ((mPrivateFlags2 & PFLAG2_ACCESSIBILITY_FOCUSED) != 0) { 10675 mPrivateFlags2 &= ~PFLAG2_ACCESSIBILITY_FOCUSED; 10676 invalidate(); 10677 if (AccessibilityManager.getInstance(mContext).isEnabled()) { 10678 AccessibilityEvent event = AccessibilityEvent.obtain( 10679 AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED); 10680 event.setAction(action); 10681 if (mAccessibilityDelegate != null) { 10682 mAccessibilityDelegate.sendAccessibilityEventUnchecked(this, event); 10683 } else { 10684 sendAccessibilityEventUnchecked(event); 10685 } 10686 } 10687 } 10688 } 10689 10690 /** 10691 * Call this to try to give focus to a specific view or to one of its 10692 * descendants. 10693 * 10694 * A view will not actually take focus if it is not focusable ({@link #isFocusable} returns 10695 * false), or if it is focusable and it is not focusable in touch mode 10696 * ({@link #isFocusableInTouchMode}) while the device is in touch mode. 10697 * 10698 * See also {@link #focusSearch(int)}, which is what you call to say that you 10699 * have focus, and you want your parent to look for the next one. 10700 * 10701 * This is equivalent to calling {@link #requestFocus(int, Rect)} with arguments 10702 * {@link #FOCUS_DOWN} and <code>null</code>. 10703 * 10704 * @return Whether this view or one of its descendants actually took focus. 10705 */ 10706 public final boolean requestFocus() { 10707 return requestFocus(View.FOCUS_DOWN); 10708 } 10709 10710 /** 10711 * This will request focus for whichever View was last focused within this 10712 * cluster before a focus-jump out of it. 10713 * 10714 * @hide 10715 */ 10716 @TestApi 10717 public boolean restoreFocusInCluster(@FocusRealDirection int direction) { 10718 // Prioritize focusableByDefault over algorithmic focus selection. 10719 if (restoreDefaultFocus()) { 10720 return true; 10721 } 10722 return requestFocus(direction); 10723 } 10724 10725 /** 10726 * This will request focus for whichever View not in a cluster was last focused before a 10727 * focus-jump to a cluster. If no non-cluster View has previously had focus, this will focus 10728 * the "first" focusable view it finds. 10729 * 10730 * @hide 10731 */ 10732 @TestApi 10733 public boolean restoreFocusNotInCluster() { 10734 return requestFocus(View.FOCUS_DOWN); 10735 } 10736 10737 /** 10738 * Gives focus to the default-focus view in the view hierarchy that has this view as a root. 10739 * If the default-focus view cannot be found, falls back to calling {@link #requestFocus(int)}. 10740 * 10741 * @return Whether this view or one of its descendants actually took focus 10742 */ 10743 public boolean restoreDefaultFocus() { 10744 return requestFocus(View.FOCUS_DOWN); 10745 } 10746 10747 /** 10748 * Call this to try to give focus to a specific view or to one of its 10749 * descendants and give it a hint about what direction focus is heading. 10750 * 10751 * A view will not actually take focus if it is not focusable ({@link #isFocusable} returns 10752 * false), or if it is focusable and it is not focusable in touch mode 10753 * ({@link #isFocusableInTouchMode}) while the device is in touch mode. 10754 * 10755 * See also {@link #focusSearch(int)}, which is what you call to say that you 10756 * have focus, and you want your parent to look for the next one. 10757 * 10758 * This is equivalent to calling {@link #requestFocus(int, Rect)} with 10759 * <code>null</code> set for the previously focused rectangle. 10760 * 10761 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT 10762 * @return Whether this view or one of its descendants actually took focus. 10763 */ 10764 public final boolean requestFocus(int direction) { 10765 return requestFocus(direction, null); 10766 } 10767 10768 /** 10769 * Call this to try to give focus to a specific view or to one of its descendants 10770 * and give it hints about the direction and a specific rectangle that the focus 10771 * is coming from. The rectangle can help give larger views a finer grained hint 10772 * about where focus is coming from, and therefore, where to show selection, or 10773 * forward focus change internally. 10774 * 10775 * A view will not actually take focus if it is not focusable ({@link #isFocusable} returns 10776 * false), or if it is focusable and it is not focusable in touch mode 10777 * ({@link #isFocusableInTouchMode}) while the device is in touch mode. 10778 * 10779 * A View will not take focus if it is not visible. 10780 * 10781 * A View will not take focus if one of its parents has 10782 * {@link android.view.ViewGroup#getDescendantFocusability()} equal to 10783 * {@link ViewGroup#FOCUS_BLOCK_DESCENDANTS}. 10784 * 10785 * See also {@link #focusSearch(int)}, which is what you call to say that you 10786 * have focus, and you want your parent to look for the next one. 10787 * 10788 * You may wish to override this method if your custom {@link View} has an internal 10789 * {@link View} that it wishes to forward the request to. 10790 * 10791 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT 10792 * @param previouslyFocusedRect The rectangle (in this View's coordinate system) 10793 * to give a finer grained hint about where focus is coming from. May be null 10794 * if there is no hint. 10795 * @return Whether this view or one of its descendants actually took focus. 10796 */ 10797 public boolean requestFocus(int direction, Rect previouslyFocusedRect) { 10798 return requestFocusNoSearch(direction, previouslyFocusedRect); 10799 } 10800 10801 private boolean requestFocusNoSearch(int direction, Rect previouslyFocusedRect) { 10802 // need to be focusable 10803 if ((mViewFlags & FOCUSABLE) != FOCUSABLE 10804 || (mViewFlags & VISIBILITY_MASK) != VISIBLE) { 10805 return false; 10806 } 10807 10808 // need to be focusable in touch mode if in touch mode 10809 if (isInTouchMode() && 10810 (FOCUSABLE_IN_TOUCH_MODE != (mViewFlags & FOCUSABLE_IN_TOUCH_MODE))) { 10811 return false; 10812 } 10813 10814 // need to not have any parents blocking us 10815 if (hasAncestorThatBlocksDescendantFocus()) { 10816 return false; 10817 } 10818 10819 handleFocusGainInternal(direction, previouslyFocusedRect); 10820 return true; 10821 } 10822 10823 /** 10824 * Call this to try to give focus to a specific view or to one of its descendants. This is a 10825 * special variant of {@link #requestFocus() } that will allow views that are not focusable in 10826 * touch mode to request focus when they are touched. 10827 * 10828 * @return Whether this view or one of its descendants actually took focus. 10829 * 10830 * @see #isInTouchMode() 10831 * 10832 */ 10833 public final boolean requestFocusFromTouch() { 10834 // Leave touch mode if we need to 10835 if (isInTouchMode()) { 10836 ViewRootImpl viewRoot = getViewRootImpl(); 10837 if (viewRoot != null) { 10838 viewRoot.ensureTouchMode(false); 10839 } 10840 } 10841 return requestFocus(View.FOCUS_DOWN); 10842 } 10843 10844 /** 10845 * @return Whether any ancestor of this view blocks descendant focus. 10846 */ 10847 private boolean hasAncestorThatBlocksDescendantFocus() { 10848 final boolean focusableInTouchMode = isFocusableInTouchMode(); 10849 ViewParent ancestor = mParent; 10850 while (ancestor instanceof ViewGroup) { 10851 final ViewGroup vgAncestor = (ViewGroup) ancestor; 10852 if (vgAncestor.getDescendantFocusability() == ViewGroup.FOCUS_BLOCK_DESCENDANTS 10853 || (!focusableInTouchMode && vgAncestor.shouldBlockFocusForTouchscreen())) { 10854 return true; 10855 } else { 10856 ancestor = vgAncestor.getParent(); 10857 } 10858 } 10859 return false; 10860 } 10861 10862 /** 10863 * Gets the mode for determining whether this View is important for accessibility. 10864 * A view is important for accessibility if it fires accessibility events and if it 10865 * is reported to accessibility services that query the screen. 10866 * 10867 * @return The mode for determining whether a view is important for accessibility, one 10868 * of {@link #IMPORTANT_FOR_ACCESSIBILITY_AUTO}, {@link #IMPORTANT_FOR_ACCESSIBILITY_YES}, 10869 * {@link #IMPORTANT_FOR_ACCESSIBILITY_NO}, or 10870 * {@link #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS}. 10871 * 10872 * @attr ref android.R.styleable#View_importantForAccessibility 10873 * 10874 * @see #IMPORTANT_FOR_ACCESSIBILITY_YES 10875 * @see #IMPORTANT_FOR_ACCESSIBILITY_NO 10876 * @see #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS 10877 * @see #IMPORTANT_FOR_ACCESSIBILITY_AUTO 10878 */ 10879 @ViewDebug.ExportedProperty(category = "accessibility", mapping = { 10880 @ViewDebug.IntToString(from = IMPORTANT_FOR_ACCESSIBILITY_AUTO, to = "auto"), 10881 @ViewDebug.IntToString(from = IMPORTANT_FOR_ACCESSIBILITY_YES, to = "yes"), 10882 @ViewDebug.IntToString(from = IMPORTANT_FOR_ACCESSIBILITY_NO, to = "no"), 10883 @ViewDebug.IntToString(from = IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS, 10884 to = "noHideDescendants") 10885 }) 10886 public int getImportantForAccessibility() { 10887 return (mPrivateFlags2 & PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK) 10888 >> PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT; 10889 } 10890 10891 /** 10892 * Sets the live region mode for this view. This indicates to accessibility 10893 * services whether they should automatically notify the user about changes 10894 * to the view's content description or text, or to the content descriptions 10895 * or text of the view's children (where applicable). 10896 * <p> 10897 * For example, in a login screen with a TextView that displays an "incorrect 10898 * password" notification, that view should be marked as a live region with 10899 * mode {@link #ACCESSIBILITY_LIVE_REGION_POLITE}. 10900 * <p> 10901 * To disable change notifications for this view, use 10902 * {@link #ACCESSIBILITY_LIVE_REGION_NONE}. This is the default live region 10903 * mode for most views. 10904 * <p> 10905 * To indicate that the user should be notified of changes, use 10906 * {@link #ACCESSIBILITY_LIVE_REGION_POLITE}. 10907 * <p> 10908 * If the view's changes should interrupt ongoing speech and notify the user 10909 * immediately, use {@link #ACCESSIBILITY_LIVE_REGION_ASSERTIVE}. 10910 * 10911 * @param mode The live region mode for this view, one of: 10912 * <ul> 10913 * <li>{@link #ACCESSIBILITY_LIVE_REGION_NONE} 10914 * <li>{@link #ACCESSIBILITY_LIVE_REGION_POLITE} 10915 * <li>{@link #ACCESSIBILITY_LIVE_REGION_ASSERTIVE} 10916 * </ul> 10917 * @attr ref android.R.styleable#View_accessibilityLiveRegion 10918 */ 10919 public void setAccessibilityLiveRegion(int mode) { 10920 if (mode != getAccessibilityLiveRegion()) { 10921 mPrivateFlags2 &= ~PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK; 10922 mPrivateFlags2 |= (mode << PFLAG2_ACCESSIBILITY_LIVE_REGION_SHIFT) 10923 & PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK; 10924 notifyViewAccessibilityStateChangedIfNeeded( 10925 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 10926 } 10927 } 10928 10929 /** 10930 * Gets the live region mode for this View. 10931 * 10932 * @return The live region mode for the view. 10933 * 10934 * @attr ref android.R.styleable#View_accessibilityLiveRegion 10935 * 10936 * @see #setAccessibilityLiveRegion(int) 10937 */ 10938 public int getAccessibilityLiveRegion() { 10939 return (mPrivateFlags2 & PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK) 10940 >> PFLAG2_ACCESSIBILITY_LIVE_REGION_SHIFT; 10941 } 10942 10943 /** 10944 * Sets how to determine whether this view is important for accessibility 10945 * which is if it fires accessibility events and if it is reported to 10946 * accessibility services that query the screen. 10947 * 10948 * @param mode How to determine whether this view is important for accessibility. 10949 * 10950 * @attr ref android.R.styleable#View_importantForAccessibility 10951 * 10952 * @see #IMPORTANT_FOR_ACCESSIBILITY_YES 10953 * @see #IMPORTANT_FOR_ACCESSIBILITY_NO 10954 * @see #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS 10955 * @see #IMPORTANT_FOR_ACCESSIBILITY_AUTO 10956 */ 10957 public void setImportantForAccessibility(int mode) { 10958 final int oldMode = getImportantForAccessibility(); 10959 if (mode != oldMode) { 10960 final boolean hideDescendants = 10961 mode == IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS; 10962 10963 // If this node or its descendants are no longer important, try to 10964 // clear accessibility focus. 10965 if (mode == IMPORTANT_FOR_ACCESSIBILITY_NO || hideDescendants) { 10966 final View focusHost = findAccessibilityFocusHost(hideDescendants); 10967 if (focusHost != null) { 10968 focusHost.clearAccessibilityFocus(); 10969 } 10970 } 10971 10972 // If we're moving between AUTO and another state, we might not need 10973 // to send a subtree changed notification. We'll store the computed 10974 // importance, since we'll need to check it later to make sure. 10975 final boolean maySkipNotify = oldMode == IMPORTANT_FOR_ACCESSIBILITY_AUTO 10976 || mode == IMPORTANT_FOR_ACCESSIBILITY_AUTO; 10977 final boolean oldIncludeForAccessibility = maySkipNotify && includeForAccessibility(); 10978 mPrivateFlags2 &= ~PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK; 10979 mPrivateFlags2 |= (mode << PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT) 10980 & PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK; 10981 if (!maySkipNotify || oldIncludeForAccessibility != includeForAccessibility()) { 10982 notifySubtreeAccessibilityStateChangedIfNeeded(); 10983 } else { 10984 notifyViewAccessibilityStateChangedIfNeeded( 10985 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 10986 } 10987 } 10988 } 10989 10990 /** 10991 * Returns the view within this view's hierarchy that is hosting 10992 * accessibility focus. 10993 * 10994 * @param searchDescendants whether to search for focus in descendant views 10995 * @return the view hosting accessibility focus, or {@code null} 10996 */ 10997 private View findAccessibilityFocusHost(boolean searchDescendants) { 10998 if (isAccessibilityFocusedViewOrHost()) { 10999 return this; 11000 } 11001 11002 if (searchDescendants) { 11003 final ViewRootImpl viewRoot = getViewRootImpl(); 11004 if (viewRoot != null) { 11005 final View focusHost = viewRoot.getAccessibilityFocusedHost(); 11006 if (focusHost != null && ViewRootImpl.isViewDescendantOf(focusHost, this)) { 11007 return focusHost; 11008 } 11009 } 11010 } 11011 11012 return null; 11013 } 11014 11015 /** 11016 * Computes whether this view should be exposed for accessibility. In 11017 * general, views that are interactive or provide information are exposed 11018 * while views that serve only as containers are hidden. 11019 * <p> 11020 * If an ancestor of this view has importance 11021 * {@link #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS}, this method 11022 * returns <code>false</code>. 11023 * <p> 11024 * Otherwise, the value is computed according to the view's 11025 * {@link #getImportantForAccessibility()} value: 11026 * <ol> 11027 * <li>{@link #IMPORTANT_FOR_ACCESSIBILITY_NO} or 11028 * {@link #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS}, return <code>false 11029 * </code> 11030 * <li>{@link #IMPORTANT_FOR_ACCESSIBILITY_YES}, return <code>true</code> 11031 * <li>{@link #IMPORTANT_FOR_ACCESSIBILITY_AUTO}, return <code>true</code> if 11032 * view satisfies any of the following: 11033 * <ul> 11034 * <li>Is actionable, e.g. {@link #isClickable()}, 11035 * {@link #isLongClickable()}, or {@link #isFocusable()} 11036 * <li>Has an {@link AccessibilityDelegate} 11037 * <li>Has an interaction listener, e.g. {@link OnTouchListener}, 11038 * {@link OnKeyListener}, etc. 11039 * <li>Is an accessibility live region, e.g. 11040 * {@link #getAccessibilityLiveRegion()} is not 11041 * {@link #ACCESSIBILITY_LIVE_REGION_NONE}. 11042 * </ul> 11043 * </ol> 11044 * 11045 * @return Whether the view is exposed for accessibility. 11046 * @see #setImportantForAccessibility(int) 11047 * @see #getImportantForAccessibility() 11048 */ 11049 public boolean isImportantForAccessibility() { 11050 final int mode = (mPrivateFlags2 & PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK) 11051 >> PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT; 11052 if (mode == IMPORTANT_FOR_ACCESSIBILITY_NO 11053 || mode == IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS) { 11054 return false; 11055 } 11056 11057 // Check parent mode to ensure we're not hidden. 11058 ViewParent parent = mParent; 11059 while (parent instanceof View) { 11060 if (((View) parent).getImportantForAccessibility() 11061 == IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS) { 11062 return false; 11063 } 11064 parent = parent.getParent(); 11065 } 11066 11067 return mode == IMPORTANT_FOR_ACCESSIBILITY_YES || isActionableForAccessibility() 11068 || hasListenersForAccessibility() || getAccessibilityNodeProvider() != null 11069 || getAccessibilityLiveRegion() != ACCESSIBILITY_LIVE_REGION_NONE; 11070 } 11071 11072 /** 11073 * Gets the parent for accessibility purposes. Note that the parent for 11074 * accessibility is not necessary the immediate parent. It is the first 11075 * predecessor that is important for accessibility. 11076 * 11077 * @return The parent for accessibility purposes. 11078 */ 11079 public ViewParent getParentForAccessibility() { 11080 if (mParent instanceof View) { 11081 View parentView = (View) mParent; 11082 if (parentView.includeForAccessibility()) { 11083 return mParent; 11084 } else { 11085 return mParent.getParentForAccessibility(); 11086 } 11087 } 11088 return null; 11089 } 11090 11091 /** 11092 * Adds the children of this View relevant for accessibility to the given list 11093 * as output. Since some Views are not important for accessibility the added 11094 * child views are not necessarily direct children of this view, rather they are 11095 * the first level of descendants important for accessibility. 11096 * 11097 * @param outChildren The output list that will receive children for accessibility. 11098 */ 11099 public void addChildrenForAccessibility(ArrayList<View> outChildren) { 11100 11101 } 11102 11103 /** 11104 * Whether to regard this view for accessibility. A view is regarded for 11105 * accessibility if it is important for accessibility or the querying 11106 * accessibility service has explicitly requested that view not 11107 * important for accessibility are regarded. 11108 * 11109 * @return Whether to regard the view for accessibility. 11110 * 11111 * @hide 11112 */ 11113 public boolean includeForAccessibility() { 11114 if (mAttachInfo != null) { 11115 return (mAttachInfo.mAccessibilityFetchFlags 11116 & AccessibilityNodeInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS) != 0 11117 || isImportantForAccessibility(); 11118 } 11119 return false; 11120 } 11121 11122 /** 11123 * Returns whether the View is considered actionable from 11124 * accessibility perspective. Such view are important for 11125 * accessibility. 11126 * 11127 * @return True if the view is actionable for accessibility. 11128 * 11129 * @hide 11130 */ 11131 public boolean isActionableForAccessibility() { 11132 return (isClickable() || isLongClickable() || isFocusable()); 11133 } 11134 11135 /** 11136 * Returns whether the View has registered callbacks which makes it 11137 * important for accessibility. 11138 * 11139 * @return True if the view is actionable for accessibility. 11140 */ 11141 private boolean hasListenersForAccessibility() { 11142 ListenerInfo info = getListenerInfo(); 11143 return mTouchDelegate != null || info.mOnKeyListener != null 11144 || info.mOnTouchListener != null || info.mOnGenericMotionListener != null 11145 || info.mOnHoverListener != null || info.mOnDragListener != null; 11146 } 11147 11148 /** 11149 * Notifies that the accessibility state of this view changed. The change 11150 * is local to this view and does not represent structural changes such 11151 * as children and parent. For example, the view became focusable. The 11152 * notification is at at most once every 11153 * {@link ViewConfiguration#getSendRecurringAccessibilityEventsInterval()} 11154 * to avoid unnecessary load to the system. Also once a view has a pending 11155 * notification this method is a NOP until the notification has been sent. 11156 * 11157 * @hide 11158 */ 11159 public void notifyViewAccessibilityStateChangedIfNeeded(int changeType) { 11160 if (!AccessibilityManager.getInstance(mContext).isEnabled() || mAttachInfo == null) { 11161 return; 11162 } 11163 // If this is a live region, we should send a subtree change event 11164 // from this view immediately. Otherwise, we can let it propagate up. 11165 if (getAccessibilityLiveRegion() != ACCESSIBILITY_LIVE_REGION_NONE) { 11166 final AccessibilityEvent event = AccessibilityEvent.obtain(); 11167 event.setEventType(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED); 11168 event.setContentChangeTypes(changeType); 11169 sendAccessibilityEventUnchecked(event); 11170 } else if (mParent != null) { 11171 try { 11172 mParent.notifySubtreeAccessibilityStateChanged(this, this, changeType); 11173 } catch (AbstractMethodError e) { 11174 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 11175 " does not fully implement ViewParent", e); 11176 } 11177 } 11178 } 11179 11180 /** 11181 * Notifies that the accessibility state of this view changed. The change 11182 * is *not* local to this view and does represent structural changes such 11183 * as children and parent. For example, the view size changed. The 11184 * notification is at at most once every 11185 * {@link ViewConfiguration#getSendRecurringAccessibilityEventsInterval()} 11186 * to avoid unnecessary load to the system. Also once a view has a pending 11187 * notification this method is a NOP until the notification has been sent. 11188 * 11189 * @hide 11190 */ 11191 public void notifySubtreeAccessibilityStateChangedIfNeeded() { 11192 if (!AccessibilityManager.getInstance(mContext).isEnabled() || mAttachInfo == null) { 11193 return; 11194 } 11195 if ((mPrivateFlags2 & PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED) == 0) { 11196 mPrivateFlags2 |= PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED; 11197 if (mParent != null) { 11198 try { 11199 mParent.notifySubtreeAccessibilityStateChanged( 11200 this, this, AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE); 11201 } catch (AbstractMethodError e) { 11202 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 11203 " does not fully implement ViewParent", e); 11204 } 11205 } 11206 } 11207 } 11208 11209 /** 11210 * Change the visibility of the View without triggering any other changes. This is 11211 * important for transitions, where visibility changes should not adjust focus or 11212 * trigger a new layout. This is only used when the visibility has already been changed 11213 * and we need a transient value during an animation. When the animation completes, 11214 * the original visibility value is always restored. 11215 * 11216 * @param visibility One of {@link #VISIBLE}, {@link #INVISIBLE}, or {@link #GONE}. 11217 * @hide 11218 */ 11219 public void setTransitionVisibility(@Visibility int visibility) { 11220 mViewFlags = (mViewFlags & ~View.VISIBILITY_MASK) | visibility; 11221 } 11222 11223 /** 11224 * Reset the flag indicating the accessibility state of the subtree rooted 11225 * at this view changed. 11226 */ 11227 void resetSubtreeAccessibilityStateChanged() { 11228 mPrivateFlags2 &= ~PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED; 11229 } 11230 11231 /** 11232 * Report an accessibility action to this view's parents for delegated processing. 11233 * 11234 * <p>Implementations of {@link #performAccessibilityAction(int, Bundle)} may internally 11235 * call this method to delegate an accessibility action to a supporting parent. If the parent 11236 * returns true from its 11237 * {@link ViewParent#onNestedPrePerformAccessibilityAction(View, int, android.os.Bundle)} 11238 * method this method will return true to signify that the action was consumed.</p> 11239 * 11240 * <p>This method is useful for implementing nested scrolling child views. If 11241 * {@link #isNestedScrollingEnabled()} returns true and the action is a scrolling action 11242 * a custom view implementation may invoke this method to allow a parent to consume the 11243 * scroll first. If this method returns true the custom view should skip its own scrolling 11244 * behavior.</p> 11245 * 11246 * @param action Accessibility action to delegate 11247 * @param arguments Optional action arguments 11248 * @return true if the action was consumed by a parent 11249 */ 11250 public boolean dispatchNestedPrePerformAccessibilityAction(int action, Bundle arguments) { 11251 for (ViewParent p = getParent(); p != null; p = p.getParent()) { 11252 if (p.onNestedPrePerformAccessibilityAction(this, action, arguments)) { 11253 return true; 11254 } 11255 } 11256 return false; 11257 } 11258 11259 /** 11260 * Performs the specified accessibility action on the view. For 11261 * possible accessibility actions look at {@link AccessibilityNodeInfo}. 11262 * <p> 11263 * If an {@link AccessibilityDelegate} has been specified via calling 11264 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 11265 * {@link AccessibilityDelegate#performAccessibilityAction(View, int, Bundle)} 11266 * is responsible for handling this call. 11267 * </p> 11268 * 11269 * <p>The default implementation will delegate 11270 * {@link AccessibilityNodeInfo#ACTION_SCROLL_BACKWARD} and 11271 * {@link AccessibilityNodeInfo#ACTION_SCROLL_FORWARD} to nested scrolling parents if 11272 * {@link #isNestedScrollingEnabled() nested scrolling is enabled} on this view.</p> 11273 * 11274 * @param action The action to perform. 11275 * @param arguments Optional action arguments. 11276 * @return Whether the action was performed. 11277 */ 11278 public boolean performAccessibilityAction(int action, Bundle arguments) { 11279 if (mAccessibilityDelegate != null) { 11280 return mAccessibilityDelegate.performAccessibilityAction(this, action, arguments); 11281 } else { 11282 return performAccessibilityActionInternal(action, arguments); 11283 } 11284 } 11285 11286 /** 11287 * @see #performAccessibilityAction(int, Bundle) 11288 * 11289 * Note: Called from the default {@link AccessibilityDelegate}. 11290 * 11291 * @hide 11292 */ 11293 public boolean performAccessibilityActionInternal(int action, Bundle arguments) { 11294 if (isNestedScrollingEnabled() 11295 && (action == AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD 11296 || action == AccessibilityNodeInfo.ACTION_SCROLL_FORWARD 11297 || action == R.id.accessibilityActionScrollUp 11298 || action == R.id.accessibilityActionScrollLeft 11299 || action == R.id.accessibilityActionScrollDown 11300 || action == R.id.accessibilityActionScrollRight)) { 11301 if (dispatchNestedPrePerformAccessibilityAction(action, arguments)) { 11302 return true; 11303 } 11304 } 11305 11306 switch (action) { 11307 case AccessibilityNodeInfo.ACTION_CLICK: { 11308 if (isClickable()) { 11309 performClick(); 11310 return true; 11311 } 11312 } break; 11313 case AccessibilityNodeInfo.ACTION_LONG_CLICK: { 11314 if (isLongClickable()) { 11315 performLongClick(); 11316 return true; 11317 } 11318 } break; 11319 case AccessibilityNodeInfo.ACTION_FOCUS: { 11320 if (!hasFocus()) { 11321 // Get out of touch mode since accessibility 11322 // wants to move focus around. 11323 getViewRootImpl().ensureTouchMode(false); 11324 return requestFocus(); 11325 } 11326 } break; 11327 case AccessibilityNodeInfo.ACTION_CLEAR_FOCUS: { 11328 if (hasFocus()) { 11329 clearFocus(); 11330 return !isFocused(); 11331 } 11332 } break; 11333 case AccessibilityNodeInfo.ACTION_SELECT: { 11334 if (!isSelected()) { 11335 setSelected(true); 11336 return isSelected(); 11337 } 11338 } break; 11339 case AccessibilityNodeInfo.ACTION_CLEAR_SELECTION: { 11340 if (isSelected()) { 11341 setSelected(false); 11342 return !isSelected(); 11343 } 11344 } break; 11345 case AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS: { 11346 if (!isAccessibilityFocused()) { 11347 return requestAccessibilityFocus(); 11348 } 11349 } break; 11350 case AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS: { 11351 if (isAccessibilityFocused()) { 11352 clearAccessibilityFocus(); 11353 return true; 11354 } 11355 } break; 11356 case AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY: { 11357 if (arguments != null) { 11358 final int granularity = arguments.getInt( 11359 AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT); 11360 final boolean extendSelection = arguments.getBoolean( 11361 AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN); 11362 return traverseAtGranularity(granularity, true, extendSelection); 11363 } 11364 } break; 11365 case AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY: { 11366 if (arguments != null) { 11367 final int granularity = arguments.getInt( 11368 AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT); 11369 final boolean extendSelection = arguments.getBoolean( 11370 AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN); 11371 return traverseAtGranularity(granularity, false, extendSelection); 11372 } 11373 } break; 11374 case AccessibilityNodeInfo.ACTION_SET_SELECTION: { 11375 CharSequence text = getIterableTextForAccessibility(); 11376 if (text == null) { 11377 return false; 11378 } 11379 final int start = (arguments != null) ? arguments.getInt( 11380 AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT, -1) : -1; 11381 final int end = (arguments != null) ? arguments.getInt( 11382 AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT, -1) : -1; 11383 // Only cursor position can be specified (selection length == 0) 11384 if ((getAccessibilitySelectionStart() != start 11385 || getAccessibilitySelectionEnd() != end) 11386 && (start == end)) { 11387 setAccessibilitySelection(start, end); 11388 notifyViewAccessibilityStateChangedIfNeeded( 11389 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 11390 return true; 11391 } 11392 } break; 11393 case R.id.accessibilityActionShowOnScreen: { 11394 if (mAttachInfo != null) { 11395 final Rect r = mAttachInfo.mTmpInvalRect; 11396 getDrawingRect(r); 11397 return requestRectangleOnScreen(r, true); 11398 } 11399 } break; 11400 case R.id.accessibilityActionContextClick: { 11401 if (isContextClickable()) { 11402 performContextClick(); 11403 return true; 11404 } 11405 } break; 11406 } 11407 return false; 11408 } 11409 11410 private boolean traverseAtGranularity(int granularity, boolean forward, 11411 boolean extendSelection) { 11412 CharSequence text = getIterableTextForAccessibility(); 11413 if (text == null || text.length() == 0) { 11414 return false; 11415 } 11416 TextSegmentIterator iterator = getIteratorForGranularity(granularity); 11417 if (iterator == null) { 11418 return false; 11419 } 11420 int current = getAccessibilitySelectionEnd(); 11421 if (current == ACCESSIBILITY_CURSOR_POSITION_UNDEFINED) { 11422 current = forward ? 0 : text.length(); 11423 } 11424 final int[] range = forward ? iterator.following(current) : iterator.preceding(current); 11425 if (range == null) { 11426 return false; 11427 } 11428 final int segmentStart = range[0]; 11429 final int segmentEnd = range[1]; 11430 int selectionStart; 11431 int selectionEnd; 11432 if (extendSelection && isAccessibilitySelectionExtendable()) { 11433 selectionStart = getAccessibilitySelectionStart(); 11434 if (selectionStart == ACCESSIBILITY_CURSOR_POSITION_UNDEFINED) { 11435 selectionStart = forward ? segmentStart : segmentEnd; 11436 } 11437 selectionEnd = forward ? segmentEnd : segmentStart; 11438 } else { 11439 selectionStart = selectionEnd= forward ? segmentEnd : segmentStart; 11440 } 11441 setAccessibilitySelection(selectionStart, selectionEnd); 11442 final int action = forward ? AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY 11443 : AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY; 11444 sendViewTextTraversedAtGranularityEvent(action, granularity, segmentStart, segmentEnd); 11445 return true; 11446 } 11447 11448 /** 11449 * Gets the text reported for accessibility purposes. 11450 * 11451 * @return The accessibility text. 11452 * 11453 * @hide 11454 */ 11455 public CharSequence getIterableTextForAccessibility() { 11456 return getContentDescription(); 11457 } 11458 11459 /** 11460 * Gets whether accessibility selection can be extended. 11461 * 11462 * @return If selection is extensible. 11463 * 11464 * @hide 11465 */ 11466 public boolean isAccessibilitySelectionExtendable() { 11467 return false; 11468 } 11469 11470 /** 11471 * @hide 11472 */ 11473 public int getAccessibilitySelectionStart() { 11474 return mAccessibilityCursorPosition; 11475 } 11476 11477 /** 11478 * @hide 11479 */ 11480 public int getAccessibilitySelectionEnd() { 11481 return getAccessibilitySelectionStart(); 11482 } 11483 11484 /** 11485 * @hide 11486 */ 11487 public void setAccessibilitySelection(int start, int end) { 11488 if (start == end && end == mAccessibilityCursorPosition) { 11489 return; 11490 } 11491 if (start >= 0 && start == end && end <= getIterableTextForAccessibility().length()) { 11492 mAccessibilityCursorPosition = start; 11493 } else { 11494 mAccessibilityCursorPosition = ACCESSIBILITY_CURSOR_POSITION_UNDEFINED; 11495 } 11496 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED); 11497 } 11498 11499 private void sendViewTextTraversedAtGranularityEvent(int action, int granularity, 11500 int fromIndex, int toIndex) { 11501 if (mParent == null) { 11502 return; 11503 } 11504 AccessibilityEvent event = AccessibilityEvent.obtain( 11505 AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY); 11506 onInitializeAccessibilityEvent(event); 11507 onPopulateAccessibilityEvent(event); 11508 event.setFromIndex(fromIndex); 11509 event.setToIndex(toIndex); 11510 event.setAction(action); 11511 event.setMovementGranularity(granularity); 11512 mParent.requestSendAccessibilityEvent(this, event); 11513 } 11514 11515 /** 11516 * @hide 11517 */ 11518 public TextSegmentIterator getIteratorForGranularity(int granularity) { 11519 switch (granularity) { 11520 case AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER: { 11521 CharSequence text = getIterableTextForAccessibility(); 11522 if (text != null && text.length() > 0) { 11523 CharacterTextSegmentIterator iterator = 11524 CharacterTextSegmentIterator.getInstance( 11525 mContext.getResources().getConfiguration().locale); 11526 iterator.initialize(text.toString()); 11527 return iterator; 11528 } 11529 } break; 11530 case AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD: { 11531 CharSequence text = getIterableTextForAccessibility(); 11532 if (text != null && text.length() > 0) { 11533 WordTextSegmentIterator iterator = 11534 WordTextSegmentIterator.getInstance( 11535 mContext.getResources().getConfiguration().locale); 11536 iterator.initialize(text.toString()); 11537 return iterator; 11538 } 11539 } break; 11540 case AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH: { 11541 CharSequence text = getIterableTextForAccessibility(); 11542 if (text != null && text.length() > 0) { 11543 ParagraphTextSegmentIterator iterator = 11544 ParagraphTextSegmentIterator.getInstance(); 11545 iterator.initialize(text.toString()); 11546 return iterator; 11547 } 11548 } break; 11549 } 11550 return null; 11551 } 11552 11553 /** 11554 * Tells whether the {@link View} is in the state between {@link #onStartTemporaryDetach()} 11555 * and {@link #onFinishTemporaryDetach()}. 11556 * 11557 * <p>This method always returns {@code true} when called directly or indirectly from 11558 * {@link #onStartTemporaryDetach()}. The return value when called directly or indirectly from 11559 * {@link #onFinishTemporaryDetach()}, however, depends on the OS version. 11560 * <ul> 11561 * <li>{@code true} on {@link android.os.Build.VERSION_CODES#N API 24}</li> 11562 * <li>{@code false} on {@link android.os.Build.VERSION_CODES#N_MR1 API 25}} and later</li> 11563 * </ul> 11564 * </p> 11565 * 11566 * @return {@code true} when the View is in the state between {@link #onStartTemporaryDetach()} 11567 * and {@link #onFinishTemporaryDetach()}. 11568 */ 11569 public final boolean isTemporarilyDetached() { 11570 return (mPrivateFlags3 & PFLAG3_TEMPORARY_DETACH) != 0; 11571 } 11572 11573 /** 11574 * Dispatch {@link #onStartTemporaryDetach()} to this View and its direct children if this is 11575 * a container View. 11576 */ 11577 @CallSuper 11578 public void dispatchStartTemporaryDetach() { 11579 mPrivateFlags3 |= PFLAG3_TEMPORARY_DETACH; 11580 notifyEnterOrExitForAutoFillIfNeeded(false); 11581 onStartTemporaryDetach(); 11582 } 11583 11584 /** 11585 * This is called when a container is going to temporarily detach a child, with 11586 * {@link ViewGroup#detachViewFromParent(View) ViewGroup.detachViewFromParent}. 11587 * It will either be followed by {@link #onFinishTemporaryDetach()} or 11588 * {@link #onDetachedFromWindow()} when the container is done. 11589 */ 11590 public void onStartTemporaryDetach() { 11591 removeUnsetPressCallback(); 11592 mPrivateFlags |= PFLAG_CANCEL_NEXT_UP_EVENT; 11593 } 11594 11595 /** 11596 * Dispatch {@link #onFinishTemporaryDetach()} to this View and its direct children if this is 11597 * a container View. 11598 */ 11599 @CallSuper 11600 public void dispatchFinishTemporaryDetach() { 11601 mPrivateFlags3 &= ~PFLAG3_TEMPORARY_DETACH; 11602 onFinishTemporaryDetach(); 11603 if (hasWindowFocus() && hasFocus()) { 11604 InputMethodManager.getInstance().focusIn(this); 11605 } 11606 notifyEnterOrExitForAutoFillIfNeeded(true); 11607 } 11608 11609 /** 11610 * Called after {@link #onStartTemporaryDetach} when the container is done 11611 * changing the view. 11612 */ 11613 public void onFinishTemporaryDetach() { 11614 } 11615 11616 /** 11617 * Return the global {@link KeyEvent.DispatcherState KeyEvent.DispatcherState} 11618 * for this view's window. Returns null if the view is not currently attached 11619 * to the window. Normally you will not need to use this directly, but 11620 * just use the standard high-level event callbacks like 11621 * {@link #onKeyDown(int, KeyEvent)}. 11622 */ 11623 public KeyEvent.DispatcherState getKeyDispatcherState() { 11624 return mAttachInfo != null ? mAttachInfo.mKeyDispatchState : null; 11625 } 11626 11627 /** 11628 * Dispatch a key event before it is processed by any input method 11629 * associated with the view hierarchy. This can be used to intercept 11630 * key events in special situations before the IME consumes them; a 11631 * typical example would be handling the BACK key to update the application's 11632 * UI instead of allowing the IME to see it and close itself. 11633 * 11634 * @param event The key event to be dispatched. 11635 * @return True if the event was handled, false otherwise. 11636 */ 11637 public boolean dispatchKeyEventPreIme(KeyEvent event) { 11638 return onKeyPreIme(event.getKeyCode(), event); 11639 } 11640 11641 /** 11642 * Dispatch a key event to the next view on the focus path. This path runs 11643 * from the top of the view tree down to the currently focused view. If this 11644 * view has focus, it will dispatch to itself. Otherwise it will dispatch 11645 * the next node down the focus path. This method also fires any key 11646 * listeners. 11647 * 11648 * @param event The key event to be dispatched. 11649 * @return True if the event was handled, false otherwise. 11650 */ 11651 public boolean dispatchKeyEvent(KeyEvent event) { 11652 if (mInputEventConsistencyVerifier != null) { 11653 mInputEventConsistencyVerifier.onKeyEvent(event, 0); 11654 } 11655 11656 // Give any attached key listener a first crack at the event. 11657 //noinspection SimplifiableIfStatement 11658 ListenerInfo li = mListenerInfo; 11659 if (li != null && li.mOnKeyListener != null && (mViewFlags & ENABLED_MASK) == ENABLED 11660 && li.mOnKeyListener.onKey(this, event.getKeyCode(), event)) { 11661 return true; 11662 } 11663 11664 if (event.dispatch(this, mAttachInfo != null 11665 ? mAttachInfo.mKeyDispatchState : null, this)) { 11666 return true; 11667 } 11668 11669 if (mInputEventConsistencyVerifier != null) { 11670 mInputEventConsistencyVerifier.onUnhandledEvent(event, 0); 11671 } 11672 return false; 11673 } 11674 11675 /** 11676 * Dispatches a key shortcut event. 11677 * 11678 * @param event The key event to be dispatched. 11679 * @return True if the event was handled by the view, false otherwise. 11680 */ 11681 public boolean dispatchKeyShortcutEvent(KeyEvent event) { 11682 return onKeyShortcut(event.getKeyCode(), event); 11683 } 11684 11685 /** 11686 * Pass the touch screen motion event down to the target view, or this 11687 * view if it is the target. 11688 * 11689 * @param event The motion event to be dispatched. 11690 * @return True if the event was handled by the view, false otherwise. 11691 */ 11692 public boolean dispatchTouchEvent(MotionEvent event) { 11693 // If the event should be handled by accessibility focus first. 11694 if (event.isTargetAccessibilityFocus()) { 11695 // We don't have focus or no virtual descendant has it, do not handle the event. 11696 if (!isAccessibilityFocusedViewOrHost()) { 11697 return false; 11698 } 11699 // We have focus and got the event, then use normal event dispatch. 11700 event.setTargetAccessibilityFocus(false); 11701 } 11702 11703 boolean result = false; 11704 11705 if (mInputEventConsistencyVerifier != null) { 11706 mInputEventConsistencyVerifier.onTouchEvent(event, 0); 11707 } 11708 11709 final int actionMasked = event.getActionMasked(); 11710 if (actionMasked == MotionEvent.ACTION_DOWN) { 11711 // Defensive cleanup for new gesture 11712 stopNestedScroll(); 11713 } 11714 11715 if (onFilterTouchEventForSecurity(event)) { 11716 if ((mViewFlags & ENABLED_MASK) == ENABLED && handleScrollBarDragging(event)) { 11717 result = true; 11718 } 11719 //noinspection SimplifiableIfStatement 11720 ListenerInfo li = mListenerInfo; 11721 if (li != null && li.mOnTouchListener != null 11722 && (mViewFlags & ENABLED_MASK) == ENABLED 11723 && li.mOnTouchListener.onTouch(this, event)) { 11724 result = true; 11725 } 11726 11727 if (!result && onTouchEvent(event)) { 11728 result = true; 11729 } 11730 } 11731 11732 if (!result && mInputEventConsistencyVerifier != null) { 11733 mInputEventConsistencyVerifier.onUnhandledEvent(event, 0); 11734 } 11735 11736 // Clean up after nested scrolls if this is the end of a gesture; 11737 // also cancel it if we tried an ACTION_DOWN but we didn't want the rest 11738 // of the gesture. 11739 if (actionMasked == MotionEvent.ACTION_UP || 11740 actionMasked == MotionEvent.ACTION_CANCEL || 11741 (actionMasked == MotionEvent.ACTION_DOWN && !result)) { 11742 stopNestedScroll(); 11743 } 11744 11745 return result; 11746 } 11747 11748 boolean isAccessibilityFocusedViewOrHost() { 11749 return isAccessibilityFocused() || (getViewRootImpl() != null && getViewRootImpl() 11750 .getAccessibilityFocusedHost() == this); 11751 } 11752 11753 /** 11754 * Filter the touch event to apply security policies. 11755 * 11756 * @param event The motion event to be filtered. 11757 * @return True if the event should be dispatched, false if the event should be dropped. 11758 * 11759 * @see #getFilterTouchesWhenObscured 11760 */ 11761 public boolean onFilterTouchEventForSecurity(MotionEvent event) { 11762 //noinspection RedundantIfStatement 11763 if ((mViewFlags & FILTER_TOUCHES_WHEN_OBSCURED) != 0 11764 && (event.getFlags() & MotionEvent.FLAG_WINDOW_IS_OBSCURED) != 0) { 11765 // Window is obscured, drop this touch. 11766 return false; 11767 } 11768 return true; 11769 } 11770 11771 /** 11772 * Pass a trackball motion event down to the focused view. 11773 * 11774 * @param event The motion event to be dispatched. 11775 * @return True if the event was handled by the view, false otherwise. 11776 */ 11777 public boolean dispatchTrackballEvent(MotionEvent event) { 11778 if (mInputEventConsistencyVerifier != null) { 11779 mInputEventConsistencyVerifier.onTrackballEvent(event, 0); 11780 } 11781 11782 return onTrackballEvent(event); 11783 } 11784 11785 /** 11786 * Pass a captured pointer event down to the focused view. 11787 * 11788 * @param event The motion event to be dispatched. 11789 * @return True if the event was handled by the view, false otherwise. 11790 */ 11791 public boolean dispatchCapturedPointerEvent(MotionEvent event) { 11792 if (!hasPointerCapture()) { 11793 return false; 11794 } 11795 //noinspection SimplifiableIfStatement 11796 ListenerInfo li = mListenerInfo; 11797 if (li != null && li.mOnCapturedPointerListener != null 11798 && li.mOnCapturedPointerListener.onCapturedPointer(this, event)) { 11799 return true; 11800 } 11801 return onCapturedPointerEvent(event); 11802 } 11803 11804 /** 11805 * Dispatch a generic motion event. 11806 * <p> 11807 * Generic motion events with source class {@link InputDevice#SOURCE_CLASS_POINTER} 11808 * are delivered to the view under the pointer. All other generic motion events are 11809 * delivered to the focused view. Hover events are handled specially and are delivered 11810 * to {@link #onHoverEvent(MotionEvent)}. 11811 * </p> 11812 * 11813 * @param event The motion event to be dispatched. 11814 * @return True if the event was handled by the view, false otherwise. 11815 */ 11816 public boolean dispatchGenericMotionEvent(MotionEvent event) { 11817 if (mInputEventConsistencyVerifier != null) { 11818 mInputEventConsistencyVerifier.onGenericMotionEvent(event, 0); 11819 } 11820 11821 final int source = event.getSource(); 11822 if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) { 11823 final int action = event.getAction(); 11824 if (action == MotionEvent.ACTION_HOVER_ENTER 11825 || action == MotionEvent.ACTION_HOVER_MOVE 11826 || action == MotionEvent.ACTION_HOVER_EXIT) { 11827 if (dispatchHoverEvent(event)) { 11828 return true; 11829 } 11830 } else if (dispatchGenericPointerEvent(event)) { 11831 return true; 11832 } 11833 } else if (dispatchGenericFocusedEvent(event)) { 11834 return true; 11835 } 11836 11837 if (dispatchGenericMotionEventInternal(event)) { 11838 return true; 11839 } 11840 11841 if (mInputEventConsistencyVerifier != null) { 11842 mInputEventConsistencyVerifier.onUnhandledEvent(event, 0); 11843 } 11844 return false; 11845 } 11846 11847 private boolean dispatchGenericMotionEventInternal(MotionEvent event) { 11848 //noinspection SimplifiableIfStatement 11849 ListenerInfo li = mListenerInfo; 11850 if (li != null && li.mOnGenericMotionListener != null 11851 && (mViewFlags & ENABLED_MASK) == ENABLED 11852 && li.mOnGenericMotionListener.onGenericMotion(this, event)) { 11853 return true; 11854 } 11855 11856 if (onGenericMotionEvent(event)) { 11857 return true; 11858 } 11859 11860 final int actionButton = event.getActionButton(); 11861 switch (event.getActionMasked()) { 11862 case MotionEvent.ACTION_BUTTON_PRESS: 11863 if (isContextClickable() && !mInContextButtonPress && !mHasPerformedLongPress 11864 && (actionButton == MotionEvent.BUTTON_STYLUS_PRIMARY 11865 || actionButton == MotionEvent.BUTTON_SECONDARY)) { 11866 if (performContextClick(event.getX(), event.getY())) { 11867 mInContextButtonPress = true; 11868 setPressed(true, event.getX(), event.getY()); 11869 removeTapCallback(); 11870 removeLongPressCallback(); 11871 return true; 11872 } 11873 } 11874 break; 11875 11876 case MotionEvent.ACTION_BUTTON_RELEASE: 11877 if (mInContextButtonPress && (actionButton == MotionEvent.BUTTON_STYLUS_PRIMARY 11878 || actionButton == MotionEvent.BUTTON_SECONDARY)) { 11879 mInContextButtonPress = false; 11880 mIgnoreNextUpEvent = true; 11881 } 11882 break; 11883 } 11884 11885 if (mInputEventConsistencyVerifier != null) { 11886 mInputEventConsistencyVerifier.onUnhandledEvent(event, 0); 11887 } 11888 return false; 11889 } 11890 11891 /** 11892 * Dispatch a hover event. 11893 * <p> 11894 * Do not call this method directly. 11895 * Call {@link #dispatchGenericMotionEvent(MotionEvent)} instead. 11896 * </p> 11897 * 11898 * @param event The motion event to be dispatched. 11899 * @return True if the event was handled by the view, false otherwise. 11900 */ 11901 protected boolean dispatchHoverEvent(MotionEvent event) { 11902 ListenerInfo li = mListenerInfo; 11903 //noinspection SimplifiableIfStatement 11904 if (li != null && li.mOnHoverListener != null 11905 && (mViewFlags & ENABLED_MASK) == ENABLED 11906 && li.mOnHoverListener.onHover(this, event)) { 11907 return true; 11908 } 11909 11910 return onHoverEvent(event); 11911 } 11912 11913 /** 11914 * Returns true if the view has a child to which it has recently sent 11915 * {@link MotionEvent#ACTION_HOVER_ENTER}. If this view is hovered and 11916 * it does not have a hovered child, then it must be the innermost hovered view. 11917 * @hide 11918 */ 11919 protected boolean hasHoveredChild() { 11920 return false; 11921 } 11922 11923 /** 11924 * Dispatch a generic motion event to the view under the first pointer. 11925 * <p> 11926 * Do not call this method directly. 11927 * Call {@link #dispatchGenericMotionEvent(MotionEvent)} instead. 11928 * </p> 11929 * 11930 * @param event The motion event to be dispatched. 11931 * @return True if the event was handled by the view, false otherwise. 11932 */ 11933 protected boolean dispatchGenericPointerEvent(MotionEvent event) { 11934 return false; 11935 } 11936 11937 /** 11938 * Dispatch a generic motion event to the currently focused view. 11939 * <p> 11940 * Do not call this method directly. 11941 * Call {@link #dispatchGenericMotionEvent(MotionEvent)} instead. 11942 * </p> 11943 * 11944 * @param event The motion event to be dispatched. 11945 * @return True if the event was handled by the view, false otherwise. 11946 */ 11947 protected boolean dispatchGenericFocusedEvent(MotionEvent event) { 11948 return false; 11949 } 11950 11951 /** 11952 * Dispatch a pointer event. 11953 * <p> 11954 * Dispatches touch related pointer events to {@link #onTouchEvent(MotionEvent)} and all 11955 * other events to {@link #onGenericMotionEvent(MotionEvent)}. This separation of concerns 11956 * reinforces the invariant that {@link #onTouchEvent(MotionEvent)} is really about touches 11957 * and should not be expected to handle other pointing device features. 11958 * </p> 11959 * 11960 * @param event The motion event to be dispatched. 11961 * @return True if the event was handled by the view, false otherwise. 11962 * @hide 11963 */ 11964 public final boolean dispatchPointerEvent(MotionEvent event) { 11965 if (event.isTouchEvent()) { 11966 return dispatchTouchEvent(event); 11967 } else { 11968 return dispatchGenericMotionEvent(event); 11969 } 11970 } 11971 11972 /** 11973 * Called when the window containing this view gains or loses window focus. 11974 * ViewGroups should override to route to their children. 11975 * 11976 * @param hasFocus True if the window containing this view now has focus, 11977 * false otherwise. 11978 */ 11979 public void dispatchWindowFocusChanged(boolean hasFocus) { 11980 onWindowFocusChanged(hasFocus); 11981 } 11982 11983 /** 11984 * Called when the window containing this view gains or loses focus. Note 11985 * that this is separate from view focus: to receive key events, both 11986 * your view and its window must have focus. If a window is displayed 11987 * on top of yours that takes input focus, then your own window will lose 11988 * focus but the view focus will remain unchanged. 11989 * 11990 * @param hasWindowFocus True if the window containing this view now has 11991 * focus, false otherwise. 11992 */ 11993 public void onWindowFocusChanged(boolean hasWindowFocus) { 11994 InputMethodManager imm = InputMethodManager.peekInstance(); 11995 if (!hasWindowFocus) { 11996 if (isPressed()) { 11997 setPressed(false); 11998 } 11999 mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN; 12000 if (imm != null && (mPrivateFlags & PFLAG_FOCUSED) != 0) { 12001 imm.focusOut(this); 12002 } 12003 removeLongPressCallback(); 12004 removeTapCallback(); 12005 onFocusLost(); 12006 } else if (imm != null && (mPrivateFlags & PFLAG_FOCUSED) != 0) { 12007 imm.focusIn(this); 12008 } 12009 12010 notifyEnterOrExitForAutoFillIfNeeded(hasWindowFocus); 12011 12012 refreshDrawableState(); 12013 } 12014 12015 /** 12016 * Returns true if this view is in a window that currently has window focus. 12017 * Note that this is not the same as the view itself having focus. 12018 * 12019 * @return True if this view is in a window that currently has window focus. 12020 */ 12021 public boolean hasWindowFocus() { 12022 return mAttachInfo != null && mAttachInfo.mHasWindowFocus; 12023 } 12024 12025 /** 12026 * Dispatch a view visibility change down the view hierarchy. 12027 * ViewGroups should override to route to their children. 12028 * @param changedView The view whose visibility changed. Could be 'this' or 12029 * an ancestor view. 12030 * @param visibility The new visibility of changedView: {@link #VISIBLE}, 12031 * {@link #INVISIBLE} or {@link #GONE}. 12032 */ 12033 protected void dispatchVisibilityChanged(@NonNull View changedView, 12034 @Visibility int visibility) { 12035 onVisibilityChanged(changedView, visibility); 12036 } 12037 12038 /** 12039 * Called when the visibility of the view or an ancestor of the view has 12040 * changed. 12041 * 12042 * @param changedView The view whose visibility changed. May be 12043 * {@code this} or an ancestor view. 12044 * @param visibility The new visibility, one of {@link #VISIBLE}, 12045 * {@link #INVISIBLE} or {@link #GONE}. 12046 */ 12047 protected void onVisibilityChanged(@NonNull View changedView, @Visibility int visibility) { 12048 } 12049 12050 /** 12051 * Dispatch a hint about whether this view is displayed. For instance, when 12052 * a View moves out of the screen, it might receives a display hint indicating 12053 * the view is not displayed. Applications should not <em>rely</em> on this hint 12054 * as there is no guarantee that they will receive one. 12055 * 12056 * @param hint A hint about whether or not this view is displayed: 12057 * {@link #VISIBLE} or {@link #INVISIBLE}. 12058 */ 12059 public void dispatchDisplayHint(@Visibility int hint) { 12060 onDisplayHint(hint); 12061 } 12062 12063 /** 12064 * Gives this view a hint about whether is displayed or not. For instance, when 12065 * a View moves out of the screen, it might receives a display hint indicating 12066 * the view is not displayed. Applications should not <em>rely</em> on this hint 12067 * as there is no guarantee that they will receive one. 12068 * 12069 * @param hint A hint about whether or not this view is displayed: 12070 * {@link #VISIBLE} or {@link #INVISIBLE}. 12071 */ 12072 protected void onDisplayHint(@Visibility int hint) { 12073 } 12074 12075 /** 12076 * Dispatch a window visibility change down the view hierarchy. 12077 * ViewGroups should override to route to their children. 12078 * 12079 * @param visibility The new visibility of the window. 12080 * 12081 * @see #onWindowVisibilityChanged(int) 12082 */ 12083 public void dispatchWindowVisibilityChanged(@Visibility int visibility) { 12084 onWindowVisibilityChanged(visibility); 12085 } 12086 12087 /** 12088 * Called when the window containing has change its visibility 12089 * (between {@link #GONE}, {@link #INVISIBLE}, and {@link #VISIBLE}). Note 12090 * that this tells you whether or not your window is being made visible 12091 * to the window manager; this does <em>not</em> tell you whether or not 12092 * your window is obscured by other windows on the screen, even if it 12093 * is itself visible. 12094 * 12095 * @param visibility The new visibility of the window. 12096 */ 12097 protected void onWindowVisibilityChanged(@Visibility int visibility) { 12098 if (visibility == VISIBLE) { 12099 initialAwakenScrollBars(); 12100 } 12101 } 12102 12103 /** 12104 * Internal dispatching method for {@link #onVisibilityAggregated}. Overridden by 12105 * ViewGroup. Intended to only be called when {@link #isAttachedToWindow()}, 12106 * {@link #getWindowVisibility()} is {@link #VISIBLE} and this view's parent {@link #isShown()}. 12107 * 12108 * @param isVisible true if this view's visibility to the user is uninterrupted by its 12109 * ancestors or by window visibility 12110 * @return true if this view is visible to the user, not counting clipping or overlapping 12111 */ 12112 boolean dispatchVisibilityAggregated(boolean isVisible) { 12113 final boolean thisVisible = getVisibility() == VISIBLE; 12114 // If we're not visible but something is telling us we are, ignore it. 12115 if (thisVisible || !isVisible) { 12116 onVisibilityAggregated(isVisible); 12117 } 12118 return thisVisible && isVisible; 12119 } 12120 12121 /** 12122 * Called when the user-visibility of this View is potentially affected by a change 12123 * to this view itself, an ancestor view or the window this view is attached to. 12124 * 12125 * @param isVisible true if this view and all of its ancestors are {@link #VISIBLE} 12126 * and this view's window is also visible 12127 */ 12128 @CallSuper 12129 public void onVisibilityAggregated(boolean isVisible) { 12130 if (isVisible && mAttachInfo != null) { 12131 initialAwakenScrollBars(); 12132 } 12133 12134 final Drawable dr = mBackground; 12135 if (dr != null && isVisible != dr.isVisible()) { 12136 dr.setVisible(isVisible, false); 12137 } 12138 final Drawable hl = mDefaultFocusHighlight; 12139 if (hl != null && isVisible != hl.isVisible()) { 12140 hl.setVisible(isVisible, false); 12141 } 12142 final Drawable fg = mForegroundInfo != null ? mForegroundInfo.mDrawable : null; 12143 if (fg != null && isVisible != fg.isVisible()) { 12144 fg.setVisible(isVisible, false); 12145 } 12146 12147 if (isAutofillable()) { 12148 AutofillManager afm = getAutofillManager(); 12149 12150 if (afm != null && getAutofillViewId() > LAST_APP_AUTOFILL_ID) { 12151 if (mVisibilityChangeForAutofillHandler != null) { 12152 mVisibilityChangeForAutofillHandler.removeMessages(0); 12153 } 12154 12155 // If the view is in the background but still part of the hierarchy this is called 12156 // with isVisible=false. Hence visibility==false requires further checks 12157 if (isVisible) { 12158 afm.notifyViewVisibilityChange(this, true); 12159 } else { 12160 if (mVisibilityChangeForAutofillHandler == null) { 12161 mVisibilityChangeForAutofillHandler = 12162 new VisibilityChangeForAutofillHandler(afm, this); 12163 } 12164 // Let current operation (e.g. removal of the view from the hierarchy) 12165 // finish before checking state 12166 mVisibilityChangeForAutofillHandler.obtainMessage(0, this).sendToTarget(); 12167 } 12168 } 12169 } 12170 } 12171 12172 /** 12173 * Returns the current visibility of the window this view is attached to 12174 * (either {@link #GONE}, {@link #INVISIBLE}, or {@link #VISIBLE}). 12175 * 12176 * @return Returns the current visibility of the view's window. 12177 */ 12178 @Visibility 12179 public int getWindowVisibility() { 12180 return mAttachInfo != null ? mAttachInfo.mWindowVisibility : GONE; 12181 } 12182 12183 /** 12184 * Retrieve the overall visible display size in which the window this view is 12185 * attached to has been positioned in. This takes into account screen 12186 * decorations above the window, for both cases where the window itself 12187 * is being position inside of them or the window is being placed under 12188 * then and covered insets are used for the window to position its content 12189 * inside. In effect, this tells you the available area where content can 12190 * be placed and remain visible to users. 12191 * 12192 * <p>This function requires an IPC back to the window manager to retrieve 12193 * the requested information, so should not be used in performance critical 12194 * code like drawing. 12195 * 12196 * @param outRect Filled in with the visible display frame. If the view 12197 * is not attached to a window, this is simply the raw display size. 12198 */ 12199 public void getWindowVisibleDisplayFrame(Rect outRect) { 12200 if (mAttachInfo != null) { 12201 try { 12202 mAttachInfo.mSession.getDisplayFrame(mAttachInfo.mWindow, outRect); 12203 } catch (RemoteException e) { 12204 return; 12205 } 12206 // XXX This is really broken, and probably all needs to be done 12207 // in the window manager, and we need to know more about whether 12208 // we want the area behind or in front of the IME. 12209 final Rect insets = mAttachInfo.mVisibleInsets; 12210 outRect.left += insets.left; 12211 outRect.top += insets.top; 12212 outRect.right -= insets.right; 12213 outRect.bottom -= insets.bottom; 12214 return; 12215 } 12216 // The view is not attached to a display so we don't have a context. 12217 // Make a best guess about the display size. 12218 Display d = DisplayManagerGlobal.getInstance().getRealDisplay(Display.DEFAULT_DISPLAY); 12219 d.getRectSize(outRect); 12220 } 12221 12222 /** 12223 * Like {@link #getWindowVisibleDisplayFrame}, but returns the "full" display frame this window 12224 * is currently in without any insets. 12225 * 12226 * @hide 12227 */ 12228 public void getWindowDisplayFrame(Rect outRect) { 12229 if (mAttachInfo != null) { 12230 try { 12231 mAttachInfo.mSession.getDisplayFrame(mAttachInfo.mWindow, outRect); 12232 } catch (RemoteException e) { 12233 return; 12234 } 12235 return; 12236 } 12237 // The view is not attached to a display so we don't have a context. 12238 // Make a best guess about the display size. 12239 Display d = DisplayManagerGlobal.getInstance().getRealDisplay(Display.DEFAULT_DISPLAY); 12240 d.getRectSize(outRect); 12241 } 12242 12243 /** 12244 * Dispatch a notification about a resource configuration change down 12245 * the view hierarchy. 12246 * ViewGroups should override to route to their children. 12247 * 12248 * @param newConfig The new resource configuration. 12249 * 12250 * @see #onConfigurationChanged(android.content.res.Configuration) 12251 */ 12252 public void dispatchConfigurationChanged(Configuration newConfig) { 12253 onConfigurationChanged(newConfig); 12254 } 12255 12256 /** 12257 * Called when the current configuration of the resources being used 12258 * by the application have changed. You can use this to decide when 12259 * to reload resources that can changed based on orientation and other 12260 * configuration characteristics. You only need to use this if you are 12261 * not relying on the normal {@link android.app.Activity} mechanism of 12262 * recreating the activity instance upon a configuration change. 12263 * 12264 * @param newConfig The new resource configuration. 12265 */ 12266 protected void onConfigurationChanged(Configuration newConfig) { 12267 } 12268 12269 /** 12270 * Private function to aggregate all per-view attributes in to the view 12271 * root. 12272 */ 12273 void dispatchCollectViewAttributes(AttachInfo attachInfo, int visibility) { 12274 performCollectViewAttributes(attachInfo, visibility); 12275 } 12276 12277 void performCollectViewAttributes(AttachInfo attachInfo, int visibility) { 12278 if ((visibility & VISIBILITY_MASK) == VISIBLE) { 12279 if ((mViewFlags & KEEP_SCREEN_ON) == KEEP_SCREEN_ON) { 12280 attachInfo.mKeepScreenOn = true; 12281 } 12282 attachInfo.mSystemUiVisibility |= mSystemUiVisibility; 12283 ListenerInfo li = mListenerInfo; 12284 if (li != null && li.mOnSystemUiVisibilityChangeListener != null) { 12285 attachInfo.mHasSystemUiListeners = true; 12286 } 12287 } 12288 } 12289 12290 void needGlobalAttributesUpdate(boolean force) { 12291 final AttachInfo ai = mAttachInfo; 12292 if (ai != null && !ai.mRecomputeGlobalAttributes) { 12293 if (force || ai.mKeepScreenOn || (ai.mSystemUiVisibility != 0) 12294 || ai.mHasSystemUiListeners) { 12295 ai.mRecomputeGlobalAttributes = true; 12296 } 12297 } 12298 } 12299 12300 /** 12301 * Returns whether the device is currently in touch mode. Touch mode is entered 12302 * once the user begins interacting with the device by touch, and affects various 12303 * things like whether focus is always visible to the user. 12304 * 12305 * @return Whether the device is in touch mode. 12306 */ 12307 @ViewDebug.ExportedProperty 12308 public boolean isInTouchMode() { 12309 if (mAttachInfo != null) { 12310 return mAttachInfo.mInTouchMode; 12311 } else { 12312 return ViewRootImpl.isInTouchMode(); 12313 } 12314 } 12315 12316 /** 12317 * Returns the context the view is running in, through which it can 12318 * access the current theme, resources, etc. 12319 * 12320 * @return The view's Context. 12321 */ 12322 @ViewDebug.CapturedViewProperty 12323 public final Context getContext() { 12324 return mContext; 12325 } 12326 12327 /** 12328 * Handle a key event before it is processed by any input method 12329 * associated with the view hierarchy. This can be used to intercept 12330 * key events in special situations before the IME consumes them; a 12331 * typical example would be handling the BACK key to update the application's 12332 * UI instead of allowing the IME to see it and close itself. 12333 * 12334 * @param keyCode The value in event.getKeyCode(). 12335 * @param event Description of the key event. 12336 * @return If you handled the event, return true. If you want to allow the 12337 * event to be handled by the next receiver, return false. 12338 */ 12339 public boolean onKeyPreIme(int keyCode, KeyEvent event) { 12340 return false; 12341 } 12342 12343 /** 12344 * Default implementation of {@link KeyEvent.Callback#onKeyDown(int, KeyEvent) 12345 * KeyEvent.Callback.onKeyDown()}: perform press of the view 12346 * when {@link KeyEvent#KEYCODE_DPAD_CENTER} or {@link KeyEvent#KEYCODE_ENTER} 12347 * is released, if the view is enabled and clickable. 12348 * <p> 12349 * Key presses in software keyboards will generally NOT trigger this 12350 * listener, although some may elect to do so in some situations. Do not 12351 * rely on this to catch software key presses. 12352 * 12353 * @param keyCode a key code that represents the button pressed, from 12354 * {@link android.view.KeyEvent} 12355 * @param event the KeyEvent object that defines the button action 12356 */ 12357 public boolean onKeyDown(int keyCode, KeyEvent event) { 12358 if (KeyEvent.isConfirmKey(keyCode)) { 12359 if ((mViewFlags & ENABLED_MASK) == DISABLED) { 12360 return true; 12361 } 12362 12363 if (event.getRepeatCount() == 0) { 12364 // Long clickable items don't necessarily have to be clickable. 12365 final boolean clickable = (mViewFlags & CLICKABLE) == CLICKABLE 12366 || (mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE; 12367 if (clickable || (mViewFlags & TOOLTIP) == TOOLTIP) { 12368 // For the purposes of menu anchoring and drawable hotspots, 12369 // key events are considered to be at the center of the view. 12370 final float x = getWidth() / 2f; 12371 final float y = getHeight() / 2f; 12372 if (clickable) { 12373 setPressed(true, x, y); 12374 } 12375 checkForLongClick(0, x, y); 12376 return true; 12377 } 12378 } 12379 } 12380 12381 return false; 12382 } 12383 12384 /** 12385 * Default implementation of {@link KeyEvent.Callback#onKeyLongPress(int, KeyEvent) 12386 * KeyEvent.Callback.onKeyLongPress()}: always returns false (doesn't handle 12387 * the event). 12388 * <p>Key presses in software keyboards will generally NOT trigger this listener, 12389 * although some may elect to do so in some situations. Do not rely on this to 12390 * catch software key presses. 12391 */ 12392 public boolean onKeyLongPress(int keyCode, KeyEvent event) { 12393 return false; 12394 } 12395 12396 /** 12397 * Default implementation of {@link KeyEvent.Callback#onKeyUp(int, KeyEvent) 12398 * KeyEvent.Callback.onKeyUp()}: perform clicking of the view 12399 * when {@link KeyEvent#KEYCODE_DPAD_CENTER}, {@link KeyEvent#KEYCODE_ENTER} 12400 * or {@link KeyEvent#KEYCODE_SPACE} is released. 12401 * <p>Key presses in software keyboards will generally NOT trigger this listener, 12402 * although some may elect to do so in some situations. Do not rely on this to 12403 * catch software key presses. 12404 * 12405 * @param keyCode A key code that represents the button pressed, from 12406 * {@link android.view.KeyEvent}. 12407 * @param event The KeyEvent object that defines the button action. 12408 */ 12409 public boolean onKeyUp(int keyCode, KeyEvent event) { 12410 if (KeyEvent.isConfirmKey(keyCode)) { 12411 if ((mViewFlags & ENABLED_MASK) == DISABLED) { 12412 return true; 12413 } 12414 if ((mViewFlags & CLICKABLE) == CLICKABLE && isPressed()) { 12415 setPressed(false); 12416 12417 if (!mHasPerformedLongPress) { 12418 // This is a tap, so remove the longpress check 12419 removeLongPressCallback(); 12420 if (!event.isCanceled()) { 12421 return performClick(); 12422 } 12423 } 12424 } 12425 } 12426 return false; 12427 } 12428 12429 /** 12430 * Default implementation of {@link KeyEvent.Callback#onKeyMultiple(int, int, KeyEvent) 12431 * KeyEvent.Callback.onKeyMultiple()}: always returns false (doesn't handle 12432 * the event). 12433 * <p>Key presses in software keyboards will generally NOT trigger this listener, 12434 * although some may elect to do so in some situations. Do not rely on this to 12435 * catch software key presses. 12436 * 12437 * @param keyCode A key code that represents the button pressed, from 12438 * {@link android.view.KeyEvent}. 12439 * @param repeatCount The number of times the action was made. 12440 * @param event The KeyEvent object that defines the button action. 12441 */ 12442 public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event) { 12443 return false; 12444 } 12445 12446 /** 12447 * Called on the focused view when a key shortcut event is not handled. 12448 * Override this method to implement local key shortcuts for the View. 12449 * Key shortcuts can also be implemented by setting the 12450 * {@link MenuItem#setShortcut(char, char) shortcut} property of menu items. 12451 * 12452 * @param keyCode The value in event.getKeyCode(). 12453 * @param event Description of the key event. 12454 * @return If you handled the event, return true. If you want to allow the 12455 * event to be handled by the next receiver, return false. 12456 */ 12457 public boolean onKeyShortcut(int keyCode, KeyEvent event) { 12458 return false; 12459 } 12460 12461 /** 12462 * Check whether the called view is a text editor, in which case it 12463 * would make sense to automatically display a soft input window for 12464 * it. Subclasses should override this if they implement 12465 * {@link #onCreateInputConnection(EditorInfo)} to return true if 12466 * a call on that method would return a non-null InputConnection, and 12467 * they are really a first-class editor that the user would normally 12468 * start typing on when the go into a window containing your view. 12469 * 12470 * <p>The default implementation always returns false. This does 12471 * <em>not</em> mean that its {@link #onCreateInputConnection(EditorInfo)} 12472 * will not be called or the user can not otherwise perform edits on your 12473 * view; it is just a hint to the system that this is not the primary 12474 * purpose of this view. 12475 * 12476 * @return Returns true if this view is a text editor, else false. 12477 */ 12478 public boolean onCheckIsTextEditor() { 12479 return false; 12480 } 12481 12482 /** 12483 * Create a new InputConnection for an InputMethod to interact 12484 * with the view. The default implementation returns null, since it doesn't 12485 * support input methods. You can override this to implement such support. 12486 * This is only needed for views that take focus and text input. 12487 * 12488 * <p>When implementing this, you probably also want to implement 12489 * {@link #onCheckIsTextEditor()} to indicate you will return a 12490 * non-null InputConnection.</p> 12491 * 12492 * <p>Also, take good care to fill in the {@link android.view.inputmethod.EditorInfo} 12493 * object correctly and in its entirety, so that the connected IME can rely 12494 * on its values. For example, {@link android.view.inputmethod.EditorInfo#initialSelStart} 12495 * and {@link android.view.inputmethod.EditorInfo#initialSelEnd} members 12496 * must be filled in with the correct cursor position for IMEs to work correctly 12497 * with your application.</p> 12498 * 12499 * @param outAttrs Fill in with attribute information about the connection. 12500 */ 12501 public InputConnection onCreateInputConnection(EditorInfo outAttrs) { 12502 return null; 12503 } 12504 12505 /** 12506 * Called by the {@link android.view.inputmethod.InputMethodManager} 12507 * when a view who is not the current 12508 * input connection target is trying to make a call on the manager. The 12509 * default implementation returns false; you can override this to return 12510 * true for certain views if you are performing InputConnection proxying 12511 * to them. 12512 * @param view The View that is making the InputMethodManager call. 12513 * @return Return true to allow the call, false to reject. 12514 */ 12515 public boolean checkInputConnectionProxy(View view) { 12516 return false; 12517 } 12518 12519 /** 12520 * Show the context menu for this view. It is not safe to hold on to the 12521 * menu after returning from this method. 12522 * 12523 * You should normally not overload this method. Overload 12524 * {@link #onCreateContextMenu(ContextMenu)} or define an 12525 * {@link OnCreateContextMenuListener} to add items to the context menu. 12526 * 12527 * @param menu The context menu to populate 12528 */ 12529 public void createContextMenu(ContextMenu menu) { 12530 ContextMenuInfo menuInfo = getContextMenuInfo(); 12531 12532 // Sets the current menu info so all items added to menu will have 12533 // my extra info set. 12534 ((MenuBuilder)menu).setCurrentMenuInfo(menuInfo); 12535 12536 onCreateContextMenu(menu); 12537 ListenerInfo li = mListenerInfo; 12538 if (li != null && li.mOnCreateContextMenuListener != null) { 12539 li.mOnCreateContextMenuListener.onCreateContextMenu(menu, this, menuInfo); 12540 } 12541 12542 // Clear the extra information so subsequent items that aren't mine don't 12543 // have my extra info. 12544 ((MenuBuilder)menu).setCurrentMenuInfo(null); 12545 12546 if (mParent != null) { 12547 mParent.createContextMenu(menu); 12548 } 12549 } 12550 12551 /** 12552 * Views should implement this if they have extra information to associate 12553 * with the context menu. The return result is supplied as a parameter to 12554 * the {@link OnCreateContextMenuListener#onCreateContextMenu(ContextMenu, View, ContextMenuInfo)} 12555 * callback. 12556 * 12557 * @return Extra information about the item for which the context menu 12558 * should be shown. This information will vary across different 12559 * subclasses of View. 12560 */ 12561 protected ContextMenuInfo getContextMenuInfo() { 12562 return null; 12563 } 12564 12565 /** 12566 * Views should implement this if the view itself is going to add items to 12567 * the context menu. 12568 * 12569 * @param menu the context menu to populate 12570 */ 12571 protected void onCreateContextMenu(ContextMenu menu) { 12572 } 12573 12574 /** 12575 * Implement this method to handle trackball motion events. The 12576 * <em>relative</em> movement of the trackball since the last event 12577 * can be retrieve with {@link MotionEvent#getX MotionEvent.getX()} and 12578 * {@link MotionEvent#getY MotionEvent.getY()}. These are normalized so 12579 * that a movement of 1 corresponds to the user pressing one DPAD key (so 12580 * they will often be fractional values, representing the more fine-grained 12581 * movement information available from a trackball). 12582 * 12583 * @param event The motion event. 12584 * @return True if the event was handled, false otherwise. 12585 */ 12586 public boolean onTrackballEvent(MotionEvent event) { 12587 return false; 12588 } 12589 12590 /** 12591 * Implement this method to handle generic motion events. 12592 * <p> 12593 * Generic motion events describe joystick movements, mouse hovers, track pad 12594 * touches, scroll wheel movements and other input events. The 12595 * {@link MotionEvent#getSource() source} of the motion event specifies 12596 * the class of input that was received. Implementations of this method 12597 * must examine the bits in the source before processing the event. 12598 * The following code example shows how this is done. 12599 * </p><p> 12600 * Generic motion events with source class {@link InputDevice#SOURCE_CLASS_POINTER} 12601 * are delivered to the view under the pointer. All other generic motion events are 12602 * delivered to the focused view. 12603 * </p> 12604 * <pre> public boolean onGenericMotionEvent(MotionEvent event) { 12605 * if (event.isFromSource(InputDevice.SOURCE_CLASS_JOYSTICK)) { 12606 * if (event.getAction() == MotionEvent.ACTION_MOVE) { 12607 * // process the joystick movement... 12608 * return true; 12609 * } 12610 * } 12611 * if (event.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) { 12612 * switch (event.getAction()) { 12613 * case MotionEvent.ACTION_HOVER_MOVE: 12614 * // process the mouse hover movement... 12615 * return true; 12616 * case MotionEvent.ACTION_SCROLL: 12617 * // process the scroll wheel movement... 12618 * return true; 12619 * } 12620 * } 12621 * return super.onGenericMotionEvent(event); 12622 * }</pre> 12623 * 12624 * @param event The generic motion event being processed. 12625 * @return True if the event was handled, false otherwise. 12626 */ 12627 public boolean onGenericMotionEvent(MotionEvent event) { 12628 return false; 12629 } 12630 12631 /** 12632 * Implement this method to handle hover events. 12633 * <p> 12634 * This method is called whenever a pointer is hovering into, over, or out of the 12635 * bounds of a view and the view is not currently being touched. 12636 * Hover events are represented as pointer events with action 12637 * {@link MotionEvent#ACTION_HOVER_ENTER}, {@link MotionEvent#ACTION_HOVER_MOVE}, 12638 * or {@link MotionEvent#ACTION_HOVER_EXIT}. 12639 * </p> 12640 * <ul> 12641 * <li>The view receives a hover event with action {@link MotionEvent#ACTION_HOVER_ENTER} 12642 * when the pointer enters the bounds of the view.</li> 12643 * <li>The view receives a hover event with action {@link MotionEvent#ACTION_HOVER_MOVE} 12644 * when the pointer has already entered the bounds of the view and has moved.</li> 12645 * <li>The view receives a hover event with action {@link MotionEvent#ACTION_HOVER_EXIT} 12646 * when the pointer has exited the bounds of the view or when the pointer is 12647 * about to go down due to a button click, tap, or similar user action that 12648 * causes the view to be touched.</li> 12649 * </ul> 12650 * <p> 12651 * The view should implement this method to return true to indicate that it is 12652 * handling the hover event, such as by changing its drawable state. 12653 * </p><p> 12654 * The default implementation calls {@link #setHovered} to update the hovered state 12655 * of the view when a hover enter or hover exit event is received, if the view 12656 * is enabled and is clickable. The default implementation also sends hover 12657 * accessibility events. 12658 * </p> 12659 * 12660 * @param event The motion event that describes the hover. 12661 * @return True if the view handled the hover event. 12662 * 12663 * @see #isHovered 12664 * @see #setHovered 12665 * @see #onHoverChanged 12666 */ 12667 public boolean onHoverEvent(MotionEvent event) { 12668 // The root view may receive hover (or touch) events that are outside the bounds of 12669 // the window. This code ensures that we only send accessibility events for 12670 // hovers that are actually within the bounds of the root view. 12671 final int action = event.getActionMasked(); 12672 if (!mSendingHoverAccessibilityEvents) { 12673 if ((action == MotionEvent.ACTION_HOVER_ENTER 12674 || action == MotionEvent.ACTION_HOVER_MOVE) 12675 && !hasHoveredChild() 12676 && pointInView(event.getX(), event.getY())) { 12677 sendAccessibilityHoverEvent(AccessibilityEvent.TYPE_VIEW_HOVER_ENTER); 12678 mSendingHoverAccessibilityEvents = true; 12679 } 12680 } else { 12681 if (action == MotionEvent.ACTION_HOVER_EXIT 12682 || (action == MotionEvent.ACTION_MOVE 12683 && !pointInView(event.getX(), event.getY()))) { 12684 mSendingHoverAccessibilityEvents = false; 12685 sendAccessibilityHoverEvent(AccessibilityEvent.TYPE_VIEW_HOVER_EXIT); 12686 } 12687 } 12688 12689 if ((action == MotionEvent.ACTION_HOVER_ENTER || action == MotionEvent.ACTION_HOVER_MOVE) 12690 && event.isFromSource(InputDevice.SOURCE_MOUSE) 12691 && isOnScrollbar(event.getX(), event.getY())) { 12692 awakenScrollBars(); 12693 } 12694 12695 // If we consider ourself hoverable, or if we we're already hovered, 12696 // handle changing state in response to ENTER and EXIT events. 12697 if (isHoverable() || isHovered()) { 12698 switch (action) { 12699 case MotionEvent.ACTION_HOVER_ENTER: 12700 setHovered(true); 12701 break; 12702 case MotionEvent.ACTION_HOVER_EXIT: 12703 setHovered(false); 12704 break; 12705 } 12706 12707 // Dispatch the event to onGenericMotionEvent before returning true. 12708 // This is to provide compatibility with existing applications that 12709 // handled HOVER_MOVE events in onGenericMotionEvent and that would 12710 // break because of the new default handling for hoverable views 12711 // in onHoverEvent. 12712 // Note that onGenericMotionEvent will be called by default when 12713 // onHoverEvent returns false (refer to dispatchGenericMotionEvent). 12714 dispatchGenericMotionEventInternal(event); 12715 // The event was already handled by calling setHovered(), so always 12716 // return true. 12717 return true; 12718 } 12719 12720 return false; 12721 } 12722 12723 /** 12724 * Returns true if the view should handle {@link #onHoverEvent} 12725 * by calling {@link #setHovered} to change its hovered state. 12726 * 12727 * @return True if the view is hoverable. 12728 */ 12729 private boolean isHoverable() { 12730 final int viewFlags = mViewFlags; 12731 if ((viewFlags & ENABLED_MASK) == DISABLED) { 12732 return false; 12733 } 12734 12735 return (viewFlags & CLICKABLE) == CLICKABLE 12736 || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE 12737 || (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE; 12738 } 12739 12740 /** 12741 * Returns true if the view is currently hovered. 12742 * 12743 * @return True if the view is currently hovered. 12744 * 12745 * @see #setHovered 12746 * @see #onHoverChanged 12747 */ 12748 @ViewDebug.ExportedProperty 12749 public boolean isHovered() { 12750 return (mPrivateFlags & PFLAG_HOVERED) != 0; 12751 } 12752 12753 /** 12754 * Sets whether the view is currently hovered. 12755 * <p> 12756 * Calling this method also changes the drawable state of the view. This 12757 * enables the view to react to hover by using different drawable resources 12758 * to change its appearance. 12759 * </p><p> 12760 * The {@link #onHoverChanged} method is called when the hovered state changes. 12761 * </p> 12762 * 12763 * @param hovered True if the view is hovered. 12764 * 12765 * @see #isHovered 12766 * @see #onHoverChanged 12767 */ 12768 public void setHovered(boolean hovered) { 12769 if (hovered) { 12770 if ((mPrivateFlags & PFLAG_HOVERED) == 0) { 12771 mPrivateFlags |= PFLAG_HOVERED; 12772 refreshDrawableState(); 12773 onHoverChanged(true); 12774 } 12775 } else { 12776 if ((mPrivateFlags & PFLAG_HOVERED) != 0) { 12777 mPrivateFlags &= ~PFLAG_HOVERED; 12778 refreshDrawableState(); 12779 onHoverChanged(false); 12780 } 12781 } 12782 } 12783 12784 /** 12785 * Implement this method to handle hover state changes. 12786 * <p> 12787 * This method is called whenever the hover state changes as a result of a 12788 * call to {@link #setHovered}. 12789 * </p> 12790 * 12791 * @param hovered The current hover state, as returned by {@link #isHovered}. 12792 * 12793 * @see #isHovered 12794 * @see #setHovered 12795 */ 12796 public void onHoverChanged(boolean hovered) { 12797 } 12798 12799 /** 12800 * Handles scroll bar dragging by mouse input. 12801 * 12802 * @hide 12803 * @param event The motion event. 12804 * 12805 * @return true if the event was handled as a scroll bar dragging, false otherwise. 12806 */ 12807 protected boolean handleScrollBarDragging(MotionEvent event) { 12808 if (mScrollCache == null) { 12809 return false; 12810 } 12811 final float x = event.getX(); 12812 final float y = event.getY(); 12813 final int action = event.getAction(); 12814 if ((mScrollCache.mScrollBarDraggingState == ScrollabilityCache.NOT_DRAGGING 12815 && action != MotionEvent.ACTION_DOWN) 12816 || !event.isFromSource(InputDevice.SOURCE_MOUSE) 12817 || !event.isButtonPressed(MotionEvent.BUTTON_PRIMARY)) { 12818 mScrollCache.mScrollBarDraggingState = ScrollabilityCache.NOT_DRAGGING; 12819 return false; 12820 } 12821 12822 switch (action) { 12823 case MotionEvent.ACTION_MOVE: 12824 if (mScrollCache.mScrollBarDraggingState == ScrollabilityCache.NOT_DRAGGING) { 12825 return false; 12826 } 12827 if (mScrollCache.mScrollBarDraggingState 12828 == ScrollabilityCache.DRAGGING_VERTICAL_SCROLL_BAR) { 12829 final Rect bounds = mScrollCache.mScrollBarBounds; 12830 getVerticalScrollBarBounds(bounds, null); 12831 final int range = computeVerticalScrollRange(); 12832 final int offset = computeVerticalScrollOffset(); 12833 final int extent = computeVerticalScrollExtent(); 12834 12835 final int thumbLength = ScrollBarUtils.getThumbLength( 12836 bounds.height(), bounds.width(), extent, range); 12837 final int thumbOffset = ScrollBarUtils.getThumbOffset( 12838 bounds.height(), thumbLength, extent, range, offset); 12839 12840 final float diff = y - mScrollCache.mScrollBarDraggingPos; 12841 final float maxThumbOffset = bounds.height() - thumbLength; 12842 final float newThumbOffset = 12843 Math.min(Math.max(thumbOffset + diff, 0.0f), maxThumbOffset); 12844 final int height = getHeight(); 12845 if (Math.round(newThumbOffset) != thumbOffset && maxThumbOffset > 0 12846 && height > 0 && extent > 0) { 12847 final int newY = Math.round((range - extent) 12848 / ((float)extent / height) * (newThumbOffset / maxThumbOffset)); 12849 if (newY != getScrollY()) { 12850 mScrollCache.mScrollBarDraggingPos = y; 12851 setScrollY(newY); 12852 } 12853 } 12854 return true; 12855 } 12856 if (mScrollCache.mScrollBarDraggingState 12857 == ScrollabilityCache.DRAGGING_HORIZONTAL_SCROLL_BAR) { 12858 final Rect bounds = mScrollCache.mScrollBarBounds; 12859 getHorizontalScrollBarBounds(bounds, null); 12860 final int range = computeHorizontalScrollRange(); 12861 final int offset = computeHorizontalScrollOffset(); 12862 final int extent = computeHorizontalScrollExtent(); 12863 12864 final int thumbLength = ScrollBarUtils.getThumbLength( 12865 bounds.width(), bounds.height(), extent, range); 12866 final int thumbOffset = ScrollBarUtils.getThumbOffset( 12867 bounds.width(), thumbLength, extent, range, offset); 12868 12869 final float diff = x - mScrollCache.mScrollBarDraggingPos; 12870 final float maxThumbOffset = bounds.width() - thumbLength; 12871 final float newThumbOffset = 12872 Math.min(Math.max(thumbOffset + diff, 0.0f), maxThumbOffset); 12873 final int width = getWidth(); 12874 if (Math.round(newThumbOffset) != thumbOffset && maxThumbOffset > 0 12875 && width > 0 && extent > 0) { 12876 final int newX = Math.round((range - extent) 12877 / ((float)extent / width) * (newThumbOffset / maxThumbOffset)); 12878 if (newX != getScrollX()) { 12879 mScrollCache.mScrollBarDraggingPos = x; 12880 setScrollX(newX); 12881 } 12882 } 12883 return true; 12884 } 12885 case MotionEvent.ACTION_DOWN: 12886 if (mScrollCache.state == ScrollabilityCache.OFF) { 12887 return false; 12888 } 12889 if (isOnVerticalScrollbarThumb(x, y)) { 12890 mScrollCache.mScrollBarDraggingState = 12891 ScrollabilityCache.DRAGGING_VERTICAL_SCROLL_BAR; 12892 mScrollCache.mScrollBarDraggingPos = y; 12893 return true; 12894 } 12895 if (isOnHorizontalScrollbarThumb(x, y)) { 12896 mScrollCache.mScrollBarDraggingState = 12897 ScrollabilityCache.DRAGGING_HORIZONTAL_SCROLL_BAR; 12898 mScrollCache.mScrollBarDraggingPos = x; 12899 return true; 12900 } 12901 } 12902 mScrollCache.mScrollBarDraggingState = ScrollabilityCache.NOT_DRAGGING; 12903 return false; 12904 } 12905 12906 /** 12907 * Implement this method to handle touch screen motion events. 12908 * <p> 12909 * If this method is used to detect click actions, it is recommended that 12910 * the actions be performed by implementing and calling 12911 * {@link #performClick()}. This will ensure consistent system behavior, 12912 * including: 12913 * <ul> 12914 * <li>obeying click sound preferences 12915 * <li>dispatching OnClickListener calls 12916 * <li>handling {@link AccessibilityNodeInfo#ACTION_CLICK ACTION_CLICK} when 12917 * accessibility features are enabled 12918 * </ul> 12919 * 12920 * @param event The motion event. 12921 * @return True if the event was handled, false otherwise. 12922 */ 12923 public boolean onTouchEvent(MotionEvent event) { 12924 final float x = event.getX(); 12925 final float y = event.getY(); 12926 final int viewFlags = mViewFlags; 12927 final int action = event.getAction(); 12928 12929 final boolean clickable = ((viewFlags & CLICKABLE) == CLICKABLE 12930 || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE) 12931 || (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE; 12932 12933 if ((viewFlags & ENABLED_MASK) == DISABLED) { 12934 if (action == MotionEvent.ACTION_UP && (mPrivateFlags & PFLAG_PRESSED) != 0) { 12935 setPressed(false); 12936 } 12937 mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN; 12938 // A disabled view that is clickable still consumes the touch 12939 // events, it just doesn't respond to them. 12940 return clickable; 12941 } 12942 if (mTouchDelegate != null) { 12943 if (mTouchDelegate.onTouchEvent(event)) { 12944 return true; 12945 } 12946 } 12947 12948 if (clickable || (viewFlags & TOOLTIP) == TOOLTIP) { 12949 switch (action) { 12950 case MotionEvent.ACTION_UP: 12951 mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN; 12952 if ((viewFlags & TOOLTIP) == TOOLTIP) { 12953 handleTooltipUp(); 12954 } 12955 if (!clickable) { 12956 removeTapCallback(); 12957 removeLongPressCallback(); 12958 mInContextButtonPress = false; 12959 mHasPerformedLongPress = false; 12960 mIgnoreNextUpEvent = false; 12961 break; 12962 } 12963 boolean prepressed = (mPrivateFlags & PFLAG_PREPRESSED) != 0; 12964 if ((mPrivateFlags & PFLAG_PRESSED) != 0 || prepressed) { 12965 // take focus if we don't have it already and we should in 12966 // touch mode. 12967 boolean focusTaken = false; 12968 if (isFocusable() && isFocusableInTouchMode() && !isFocused()) { 12969 focusTaken = requestFocus(); 12970 } 12971 12972 if (prepressed) { 12973 // The button is being released before we actually 12974 // showed it as pressed. Make it show the pressed 12975 // state now (before scheduling the click) to ensure 12976 // the user sees it. 12977 setPressed(true, x, y); 12978 } 12979 12980 if (!mHasPerformedLongPress && !mIgnoreNextUpEvent) { 12981 // This is a tap, so remove the longpress check 12982 removeLongPressCallback(); 12983 12984 // Only perform take click actions if we were in the pressed state 12985 if (!focusTaken) { 12986 // Use a Runnable and post this rather than calling 12987 // performClick directly. This lets other visual state 12988 // of the view update before click actions start. 12989 if (mPerformClick == null) { 12990 mPerformClick = new PerformClick(); 12991 } 12992 if (!post(mPerformClick)) { 12993 performClick(); 12994 } 12995 } 12996 } 12997 12998 if (mUnsetPressedState == null) { 12999 mUnsetPressedState = new UnsetPressedState(); 13000 } 13001 13002 if (prepressed) { 13003 postDelayed(mUnsetPressedState, 13004 ViewConfiguration.getPressedStateDuration()); 13005 } else if (!post(mUnsetPressedState)) { 13006 // If the post failed, unpress right now 13007 mUnsetPressedState.run(); 13008 } 13009 13010 removeTapCallback(); 13011 } 13012 mIgnoreNextUpEvent = false; 13013 break; 13014 13015 case MotionEvent.ACTION_DOWN: 13016 if (event.getSource() == InputDevice.SOURCE_TOUCHSCREEN) { 13017 mPrivateFlags3 |= PFLAG3_FINGER_DOWN; 13018 } 13019 mHasPerformedLongPress = false; 13020 13021 if (!clickable) { 13022 checkForLongClick(0, x, y); 13023 break; 13024 } 13025 13026 if (performButtonActionOnTouchDown(event)) { 13027 break; 13028 } 13029 13030 // Walk up the hierarchy to determine if we're inside a scrolling container. 13031 boolean isInScrollingContainer = isInScrollingContainer(); 13032 13033 // For views inside a scrolling container, delay the pressed feedback for 13034 // a short period in case this is a scroll. 13035 if (isInScrollingContainer) { 13036 mPrivateFlags |= PFLAG_PREPRESSED; 13037 if (mPendingCheckForTap == null) { 13038 mPendingCheckForTap = new CheckForTap(); 13039 } 13040 mPendingCheckForTap.x = event.getX(); 13041 mPendingCheckForTap.y = event.getY(); 13042 postDelayed(mPendingCheckForTap, ViewConfiguration.getTapTimeout()); 13043 } else { 13044 // Not inside a scrolling container, so show the feedback right away 13045 setPressed(true, x, y); 13046 checkForLongClick(0, x, y); 13047 } 13048 break; 13049 13050 case MotionEvent.ACTION_CANCEL: 13051 if (clickable) { 13052 setPressed(false); 13053 } 13054 removeTapCallback(); 13055 removeLongPressCallback(); 13056 mInContextButtonPress = false; 13057 mHasPerformedLongPress = false; 13058 mIgnoreNextUpEvent = false; 13059 mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN; 13060 break; 13061 13062 case MotionEvent.ACTION_MOVE: 13063 if (clickable) { 13064 drawableHotspotChanged(x, y); 13065 } 13066 13067 // Be lenient about moving outside of buttons 13068 if (!pointInView(x, y, mTouchSlop)) { 13069 // Outside button 13070 // Remove any future long press/tap checks 13071 removeTapCallback(); 13072 removeLongPressCallback(); 13073 if ((mPrivateFlags & PFLAG_PRESSED) != 0) { 13074 setPressed(false); 13075 } 13076 mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN; 13077 } 13078 break; 13079 } 13080 13081 return true; 13082 } 13083 13084 return false; 13085 } 13086 13087 /** 13088 * @hide 13089 */ 13090 public boolean isInScrollingContainer() { 13091 ViewParent p = getParent(); 13092 while (p != null && p instanceof ViewGroup) { 13093 if (((ViewGroup) p).shouldDelayChildPressedState()) { 13094 return true; 13095 } 13096 p = p.getParent(); 13097 } 13098 return false; 13099 } 13100 13101 /** 13102 * Remove the longpress detection timer. 13103 */ 13104 private void removeLongPressCallback() { 13105 if (mPendingCheckForLongPress != null) { 13106 removeCallbacks(mPendingCheckForLongPress); 13107 } 13108 } 13109 13110 /** 13111 * Remove the pending click action 13112 */ 13113 private void removePerformClickCallback() { 13114 if (mPerformClick != null) { 13115 removeCallbacks(mPerformClick); 13116 } 13117 } 13118 13119 /** 13120 * Remove the prepress detection timer. 13121 */ 13122 private void removeUnsetPressCallback() { 13123 if ((mPrivateFlags & PFLAG_PRESSED) != 0 && mUnsetPressedState != null) { 13124 setPressed(false); 13125 removeCallbacks(mUnsetPressedState); 13126 } 13127 } 13128 13129 /** 13130 * Remove the tap detection timer. 13131 */ 13132 private void removeTapCallback() { 13133 if (mPendingCheckForTap != null) { 13134 mPrivateFlags &= ~PFLAG_PREPRESSED; 13135 removeCallbacks(mPendingCheckForTap); 13136 } 13137 } 13138 13139 /** 13140 * Cancels a pending long press. Your subclass can use this if you 13141 * want the context menu to come up if the user presses and holds 13142 * at the same place, but you don't want it to come up if they press 13143 * and then move around enough to cause scrolling. 13144 */ 13145 public void cancelLongPress() { 13146 removeLongPressCallback(); 13147 13148 /* 13149 * The prepressed state handled by the tap callback is a display 13150 * construct, but the tap callback will post a long press callback 13151 * less its own timeout. Remove it here. 13152 */ 13153 removeTapCallback(); 13154 } 13155 13156 /** 13157 * Remove the pending callback for sending a 13158 * {@link AccessibilityEvent#TYPE_VIEW_SCROLLED} accessibility event. 13159 */ 13160 private void removeSendViewScrolledAccessibilityEventCallback() { 13161 if (mSendViewScrolledAccessibilityEvent != null) { 13162 removeCallbacks(mSendViewScrolledAccessibilityEvent); 13163 mSendViewScrolledAccessibilityEvent.mIsPending = false; 13164 } 13165 } 13166 13167 /** 13168 * Sets the TouchDelegate for this View. 13169 */ 13170 public void setTouchDelegate(TouchDelegate delegate) { 13171 mTouchDelegate = delegate; 13172 } 13173 13174 /** 13175 * Gets the TouchDelegate for this View. 13176 */ 13177 public TouchDelegate getTouchDelegate() { 13178 return mTouchDelegate; 13179 } 13180 13181 /** 13182 * Request unbuffered dispatch of the given stream of MotionEvents to this View. 13183 * 13184 * Until this View receives a corresponding {@link MotionEvent#ACTION_UP}, ask that the input 13185 * system not batch {@link MotionEvent}s but instead deliver them as soon as they're 13186 * available. This method should only be called for touch events. 13187 * 13188 * <p class="note">This api is not intended for most applications. Buffered dispatch 13189 * provides many of benefits, and just requesting unbuffered dispatch on most MotionEvent 13190 * streams will not improve your input latency. Side effects include: increased latency, 13191 * jittery scrolls and inability to take advantage of system resampling. Talk to your input 13192 * professional to see if {@link #requestUnbufferedDispatch(MotionEvent)} is right for 13193 * you.</p> 13194 */ 13195 public final void requestUnbufferedDispatch(MotionEvent event) { 13196 final int action = event.getAction(); 13197 if (mAttachInfo == null 13198 || action != MotionEvent.ACTION_DOWN && action != MotionEvent.ACTION_MOVE 13199 || !event.isTouchEvent()) { 13200 return; 13201 } 13202 mAttachInfo.mUnbufferedDispatchRequested = true; 13203 } 13204 13205 /** 13206 * Set flags controlling behavior of this view. 13207 * 13208 * @param flags Constant indicating the value which should be set 13209 * @param mask Constant indicating the bit range that should be changed 13210 */ 13211 void setFlags(int flags, int mask) { 13212 final boolean accessibilityEnabled = 13213 AccessibilityManager.getInstance(mContext).isEnabled(); 13214 final boolean oldIncludeForAccessibility = accessibilityEnabled && includeForAccessibility(); 13215 13216 int old = mViewFlags; 13217 mViewFlags = (mViewFlags & ~mask) | (flags & mask); 13218 13219 int changed = mViewFlags ^ old; 13220 if (changed == 0) { 13221 return; 13222 } 13223 int privateFlags = mPrivateFlags; 13224 13225 // If focusable is auto, update the FOCUSABLE bit. 13226 int focusableChangedByAuto = 0; 13227 if (((mViewFlags & FOCUSABLE_AUTO) != 0) 13228 && (changed & (FOCUSABLE_MASK | CLICKABLE)) != 0) { 13229 // Heuristic only takes into account whether view is clickable. 13230 final int newFocus; 13231 if ((mViewFlags & CLICKABLE) != 0) { 13232 newFocus = FOCUSABLE; 13233 } else { 13234 newFocus = NOT_FOCUSABLE; 13235 } 13236 mViewFlags = (mViewFlags & ~FOCUSABLE) | newFocus; 13237 focusableChangedByAuto = (old & FOCUSABLE) ^ (newFocus & FOCUSABLE); 13238 changed = (changed & ~FOCUSABLE) | focusableChangedByAuto; 13239 } 13240 13241 /* Check if the FOCUSABLE bit has changed */ 13242 if (((changed & FOCUSABLE) != 0) && ((privateFlags & PFLAG_HAS_BOUNDS) != 0)) { 13243 if (((old & FOCUSABLE) == FOCUSABLE) 13244 && ((privateFlags & PFLAG_FOCUSED) != 0)) { 13245 /* Give up focus if we are no longer focusable */ 13246 clearFocus(); 13247 } else if (((old & FOCUSABLE) == NOT_FOCUSABLE) 13248 && ((privateFlags & PFLAG_FOCUSED) == 0)) { 13249 /* 13250 * Tell the view system that we are now available to take focus 13251 * if no one else already has it. 13252 */ 13253 if (mParent != null) { 13254 ViewRootImpl viewRootImpl = getViewRootImpl(); 13255 if (!sAutoFocusableOffUIThreadWontNotifyParents 13256 || focusableChangedByAuto == 0 13257 || viewRootImpl == null 13258 || viewRootImpl.mThread == Thread.currentThread()) { 13259 mParent.focusableViewAvailable(this); 13260 } 13261 } 13262 } 13263 } 13264 13265 final int newVisibility = flags & VISIBILITY_MASK; 13266 if (newVisibility == VISIBLE) { 13267 if ((changed & VISIBILITY_MASK) != 0) { 13268 /* 13269 * If this view is becoming visible, invalidate it in case it changed while 13270 * it was not visible. Marking it drawn ensures that the invalidation will 13271 * go through. 13272 */ 13273 mPrivateFlags |= PFLAG_DRAWN; 13274 invalidate(true); 13275 13276 needGlobalAttributesUpdate(true); 13277 13278 // a view becoming visible is worth notifying the parent 13279 // about in case nothing has focus. even if this specific view 13280 // isn't focusable, it may contain something that is, so let 13281 // the root view try to give this focus if nothing else does. 13282 if ((mParent != null)) { 13283 mParent.focusableViewAvailable(this); 13284 } 13285 } 13286 } 13287 13288 /* Check if the GONE bit has changed */ 13289 if ((changed & GONE) != 0) { 13290 needGlobalAttributesUpdate(false); 13291 requestLayout(); 13292 13293 if (((mViewFlags & VISIBILITY_MASK) == GONE)) { 13294 if (hasFocus()) clearFocus(); 13295 clearAccessibilityFocus(); 13296 destroyDrawingCache(); 13297 if (mParent instanceof View) { 13298 // GONE views noop invalidation, so invalidate the parent 13299 ((View) mParent).invalidate(true); 13300 } 13301 // Mark the view drawn to ensure that it gets invalidated properly the next 13302 // time it is visible and gets invalidated 13303 mPrivateFlags |= PFLAG_DRAWN; 13304 } 13305 if (mAttachInfo != null) { 13306 mAttachInfo.mViewVisibilityChanged = true; 13307 } 13308 } 13309 13310 /* Check if the VISIBLE bit has changed */ 13311 if ((changed & INVISIBLE) != 0) { 13312 needGlobalAttributesUpdate(false); 13313 /* 13314 * If this view is becoming invisible, set the DRAWN flag so that 13315 * the next invalidate() will not be skipped. 13316 */ 13317 mPrivateFlags |= PFLAG_DRAWN; 13318 13319 if (((mViewFlags & VISIBILITY_MASK) == INVISIBLE)) { 13320 // root view becoming invisible shouldn't clear focus and accessibility focus 13321 if (getRootView() != this) { 13322 if (hasFocus()) clearFocus(); 13323 clearAccessibilityFocus(); 13324 } 13325 } 13326 if (mAttachInfo != null) { 13327 mAttachInfo.mViewVisibilityChanged = true; 13328 } 13329 } 13330 13331 if ((changed & VISIBILITY_MASK) != 0) { 13332 // If the view is invisible, cleanup its display list to free up resources 13333 if (newVisibility != VISIBLE && mAttachInfo != null) { 13334 cleanupDraw(); 13335 } 13336 13337 if (mParent instanceof ViewGroup) { 13338 ((ViewGroup) mParent).onChildVisibilityChanged(this, 13339 (changed & VISIBILITY_MASK), newVisibility); 13340 ((View) mParent).invalidate(true); 13341 } else if (mParent != null) { 13342 mParent.invalidateChild(this, null); 13343 } 13344 13345 if (mAttachInfo != null) { 13346 dispatchVisibilityChanged(this, newVisibility); 13347 13348 // Aggregated visibility changes are dispatched to attached views 13349 // in visible windows where the parent is currently shown/drawn 13350 // or the parent is not a ViewGroup (and therefore assumed to be a ViewRoot), 13351 // discounting clipping or overlapping. This makes it a good place 13352 // to change animation states. 13353 if (mParent != null && getWindowVisibility() == VISIBLE && 13354 ((!(mParent instanceof ViewGroup)) || ((ViewGroup) mParent).isShown())) { 13355 dispatchVisibilityAggregated(newVisibility == VISIBLE); 13356 } 13357 notifySubtreeAccessibilityStateChangedIfNeeded(); 13358 } 13359 } 13360 13361 if ((changed & WILL_NOT_CACHE_DRAWING) != 0) { 13362 destroyDrawingCache(); 13363 } 13364 13365 if ((changed & DRAWING_CACHE_ENABLED) != 0) { 13366 destroyDrawingCache(); 13367 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; 13368 invalidateParentCaches(); 13369 } 13370 13371 if ((changed & DRAWING_CACHE_QUALITY_MASK) != 0) { 13372 destroyDrawingCache(); 13373 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; 13374 } 13375 13376 if ((changed & DRAW_MASK) != 0) { 13377 if ((mViewFlags & WILL_NOT_DRAW) != 0) { 13378 if (mBackground != null 13379 || mDefaultFocusHighlight != null 13380 || (mForegroundInfo != null && mForegroundInfo.mDrawable != null)) { 13381 mPrivateFlags &= ~PFLAG_SKIP_DRAW; 13382 } else { 13383 mPrivateFlags |= PFLAG_SKIP_DRAW; 13384 } 13385 } else { 13386 mPrivateFlags &= ~PFLAG_SKIP_DRAW; 13387 } 13388 requestLayout(); 13389 invalidate(true); 13390 } 13391 13392 if ((changed & KEEP_SCREEN_ON) != 0) { 13393 if (mParent != null && mAttachInfo != null && !mAttachInfo.mRecomputeGlobalAttributes) { 13394 mParent.recomputeViewAttributes(this); 13395 } 13396 } 13397 13398 if (accessibilityEnabled) { 13399 if ((changed & FOCUSABLE) != 0 || (changed & VISIBILITY_MASK) != 0 13400 || (changed & CLICKABLE) != 0 || (changed & LONG_CLICKABLE) != 0 13401 || (changed & CONTEXT_CLICKABLE) != 0) { 13402 if (oldIncludeForAccessibility != includeForAccessibility()) { 13403 notifySubtreeAccessibilityStateChangedIfNeeded(); 13404 } else { 13405 notifyViewAccessibilityStateChangedIfNeeded( 13406 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 13407 } 13408 } else if ((changed & ENABLED_MASK) != 0) { 13409 notifyViewAccessibilityStateChangedIfNeeded( 13410 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 13411 } 13412 } 13413 } 13414 13415 /** 13416 * Change the view's z order in the tree, so it's on top of other sibling 13417 * views. This ordering change may affect layout, if the parent container 13418 * uses an order-dependent layout scheme (e.g., LinearLayout). Prior 13419 * to {@link android.os.Build.VERSION_CODES#KITKAT} this 13420 * method should be followed by calls to {@link #requestLayout()} and 13421 * {@link View#invalidate()} on the view's parent to force the parent to redraw 13422 * with the new child ordering. 13423 * 13424 * @see ViewGroup#bringChildToFront(View) 13425 */ 13426 public void bringToFront() { 13427 if (mParent != null) { 13428 mParent.bringChildToFront(this); 13429 } 13430 } 13431 13432 /** 13433 * This is called in response to an internal scroll in this view (i.e., the 13434 * view scrolled its own contents). This is typically as a result of 13435 * {@link #scrollBy(int, int)} or {@link #scrollTo(int, int)} having been 13436 * called. 13437 * 13438 * @param l Current horizontal scroll origin. 13439 * @param t Current vertical scroll origin. 13440 * @param oldl Previous horizontal scroll origin. 13441 * @param oldt Previous vertical scroll origin. 13442 */ 13443 protected void onScrollChanged(int l, int t, int oldl, int oldt) { 13444 notifySubtreeAccessibilityStateChangedIfNeeded(); 13445 13446 if (AccessibilityManager.getInstance(mContext).isEnabled()) { 13447 postSendViewScrolledAccessibilityEventCallback(); 13448 } 13449 13450 mBackgroundSizeChanged = true; 13451 mDefaultFocusHighlightSizeChanged = true; 13452 if (mForegroundInfo != null) { 13453 mForegroundInfo.mBoundsChanged = true; 13454 } 13455 13456 final AttachInfo ai = mAttachInfo; 13457 if (ai != null) { 13458 ai.mViewScrollChanged = true; 13459 } 13460 13461 if (mListenerInfo != null && mListenerInfo.mOnScrollChangeListener != null) { 13462 mListenerInfo.mOnScrollChangeListener.onScrollChange(this, l, t, oldl, oldt); 13463 } 13464 } 13465 13466 /** 13467 * Interface definition for a callback to be invoked when the scroll 13468 * X or Y positions of a view change. 13469 * <p> 13470 * <b>Note:</b> Some views handle scrolling independently from View and may 13471 * have their own separate listeners for scroll-type events. For example, 13472 * {@link android.widget.ListView ListView} allows clients to register an 13473 * {@link android.widget.ListView#setOnScrollListener(android.widget.AbsListView.OnScrollListener) AbsListView.OnScrollListener} 13474 * to listen for changes in list scroll position. 13475 * 13476 * @see #setOnScrollChangeListener(View.OnScrollChangeListener) 13477 */ 13478 public interface OnScrollChangeListener { 13479 /** 13480 * Called when the scroll position of a view changes. 13481 * 13482 * @param v The view whose scroll position has changed. 13483 * @param scrollX Current horizontal scroll origin. 13484 * @param scrollY Current vertical scroll origin. 13485 * @param oldScrollX Previous horizontal scroll origin. 13486 * @param oldScrollY Previous vertical scroll origin. 13487 */ 13488 void onScrollChange(View v, int scrollX, int scrollY, int oldScrollX, int oldScrollY); 13489 } 13490 13491 /** 13492 * Interface definition for a callback to be invoked when the layout bounds of a view 13493 * changes due to layout processing. 13494 */ 13495 public interface OnLayoutChangeListener { 13496 /** 13497 * Called when the layout bounds of a view changes due to layout processing. 13498 * 13499 * @param v The view whose bounds have changed. 13500 * @param left The new value of the view's left property. 13501 * @param top The new value of the view's top property. 13502 * @param right The new value of the view's right property. 13503 * @param bottom The new value of the view's bottom property. 13504 * @param oldLeft The previous value of the view's left property. 13505 * @param oldTop The previous value of the view's top property. 13506 * @param oldRight The previous value of the view's right property. 13507 * @param oldBottom The previous value of the view's bottom property. 13508 */ 13509 void onLayoutChange(View v, int left, int top, int right, int bottom, 13510 int oldLeft, int oldTop, int oldRight, int oldBottom); 13511 } 13512 13513 /** 13514 * This is called during layout when the size of this view has changed. If 13515 * you were just added to the view hierarchy, you're called with the old 13516 * values of 0. 13517 * 13518 * @param w Current width of this view. 13519 * @param h Current height of this view. 13520 * @param oldw Old width of this view. 13521 * @param oldh Old height of this view. 13522 */ 13523 protected void onSizeChanged(int w, int h, int oldw, int oldh) { 13524 } 13525 13526 /** 13527 * Called by draw to draw the child views. This may be overridden 13528 * by derived classes to gain control just before its children are drawn 13529 * (but after its own view has been drawn). 13530 * @param canvas the canvas on which to draw the view 13531 */ 13532 protected void dispatchDraw(Canvas canvas) { 13533 13534 } 13535 13536 /** 13537 * Gets the parent of this view. Note that the parent is a 13538 * ViewParent and not necessarily a View. 13539 * 13540 * @return Parent of this view. 13541 */ 13542 public final ViewParent getParent() { 13543 return mParent; 13544 } 13545 13546 /** 13547 * Set the horizontal scrolled position of your view. This will cause a call to 13548 * {@link #onScrollChanged(int, int, int, int)} and the view will be 13549 * invalidated. 13550 * @param value the x position to scroll to 13551 */ 13552 public void setScrollX(int value) { 13553 scrollTo(value, mScrollY); 13554 } 13555 13556 /** 13557 * Set the vertical scrolled position of your view. This will cause a call to 13558 * {@link #onScrollChanged(int, int, int, int)} and the view will be 13559 * invalidated. 13560 * @param value the y position to scroll to 13561 */ 13562 public void setScrollY(int value) { 13563 scrollTo(mScrollX, value); 13564 } 13565 13566 /** 13567 * Return the scrolled left position of this view. This is the left edge of 13568 * the displayed part of your view. You do not need to draw any pixels 13569 * farther left, since those are outside of the frame of your view on 13570 * screen. 13571 * 13572 * @return The left edge of the displayed part of your view, in pixels. 13573 */ 13574 public final int getScrollX() { 13575 return mScrollX; 13576 } 13577 13578 /** 13579 * Return the scrolled top position of this view. This is the top edge of 13580 * the displayed part of your view. You do not need to draw any pixels above 13581 * it, since those are outside of the frame of your view on screen. 13582 * 13583 * @return The top edge of the displayed part of your view, in pixels. 13584 */ 13585 public final int getScrollY() { 13586 return mScrollY; 13587 } 13588 13589 /** 13590 * Return the width of the your view. 13591 * 13592 * @return The width of your view, in pixels. 13593 */ 13594 @ViewDebug.ExportedProperty(category = "layout") 13595 public final int getWidth() { 13596 return mRight - mLeft; 13597 } 13598 13599 /** 13600 * Return the height of your view. 13601 * 13602 * @return The height of your view, in pixels. 13603 */ 13604 @ViewDebug.ExportedProperty(category = "layout") 13605 public final int getHeight() { 13606 return mBottom - mTop; 13607 } 13608 13609 /** 13610 * Return the visible drawing bounds of your view. Fills in the output 13611 * rectangle with the values from getScrollX(), getScrollY(), 13612 * getWidth(), and getHeight(). These bounds do not account for any 13613 * transformation properties currently set on the view, such as 13614 * {@link #setScaleX(float)} or {@link #setRotation(float)}. 13615 * 13616 * @param outRect The (scrolled) drawing bounds of the view. 13617 */ 13618 public void getDrawingRect(Rect outRect) { 13619 outRect.left = mScrollX; 13620 outRect.top = mScrollY; 13621 outRect.right = mScrollX + (mRight - mLeft); 13622 outRect.bottom = mScrollY + (mBottom - mTop); 13623 } 13624 13625 /** 13626 * Like {@link #getMeasuredWidthAndState()}, but only returns the 13627 * raw width component (that is the result is masked by 13628 * {@link #MEASURED_SIZE_MASK}). 13629 * 13630 * @return The raw measured width of this view. 13631 */ 13632 public final int getMeasuredWidth() { 13633 return mMeasuredWidth & MEASURED_SIZE_MASK; 13634 } 13635 13636 /** 13637 * Return the full width measurement information for this view as computed 13638 * by the most recent call to {@link #measure(int, int)}. This result is a bit mask 13639 * as defined by {@link #MEASURED_SIZE_MASK} and {@link #MEASURED_STATE_TOO_SMALL}. 13640 * This should be used during measurement and layout calculations only. Use 13641 * {@link #getWidth()} to see how wide a view is after layout. 13642 * 13643 * @return The measured width of this view as a bit mask. 13644 */ 13645 @ViewDebug.ExportedProperty(category = "measurement", flagMapping = { 13646 @ViewDebug.FlagToString(mask = MEASURED_STATE_MASK, equals = MEASURED_STATE_TOO_SMALL, 13647 name = "MEASURED_STATE_TOO_SMALL"), 13648 }) 13649 public final int getMeasuredWidthAndState() { 13650 return mMeasuredWidth; 13651 } 13652 13653 /** 13654 * Like {@link #getMeasuredHeightAndState()}, but only returns the 13655 * raw height component (that is the result is masked by 13656 * {@link #MEASURED_SIZE_MASK}). 13657 * 13658 * @return The raw measured height of this view. 13659 */ 13660 public final int getMeasuredHeight() { 13661 return mMeasuredHeight & MEASURED_SIZE_MASK; 13662 } 13663 13664 /** 13665 * Return the full height measurement information for this view as computed 13666 * by the most recent call to {@link #measure(int, int)}. This result is a bit mask 13667 * as defined by {@link #MEASURED_SIZE_MASK} and {@link #MEASURED_STATE_TOO_SMALL}. 13668 * This should be used during measurement and layout calculations only. Use 13669 * {@link #getHeight()} to see how wide a view is after layout. 13670 * 13671 * @return The measured height of this view as a bit mask. 13672 */ 13673 @ViewDebug.ExportedProperty(category = "measurement", flagMapping = { 13674 @ViewDebug.FlagToString(mask = MEASURED_STATE_MASK, equals = MEASURED_STATE_TOO_SMALL, 13675 name = "MEASURED_STATE_TOO_SMALL"), 13676 }) 13677 public final int getMeasuredHeightAndState() { 13678 return mMeasuredHeight; 13679 } 13680 13681 /** 13682 * Return only the state bits of {@link #getMeasuredWidthAndState()} 13683 * and {@link #getMeasuredHeightAndState()}, combined into one integer. 13684 * The width component is in the regular bits {@link #MEASURED_STATE_MASK} 13685 * and the height component is at the shifted bits 13686 * {@link #MEASURED_HEIGHT_STATE_SHIFT}>>{@link #MEASURED_STATE_MASK}. 13687 */ 13688 public final int getMeasuredState() { 13689 return (mMeasuredWidth&MEASURED_STATE_MASK) 13690 | ((mMeasuredHeight>>MEASURED_HEIGHT_STATE_SHIFT) 13691 & (MEASURED_STATE_MASK>>MEASURED_HEIGHT_STATE_SHIFT)); 13692 } 13693 13694 /** 13695 * The transform matrix of this view, which is calculated based on the current 13696 * rotation, scale, and pivot properties. 13697 * 13698 * @see #getRotation() 13699 * @see #getScaleX() 13700 * @see #getScaleY() 13701 * @see #getPivotX() 13702 * @see #getPivotY() 13703 * @return The current transform matrix for the view 13704 */ 13705 public Matrix getMatrix() { 13706 ensureTransformationInfo(); 13707 final Matrix matrix = mTransformationInfo.mMatrix; 13708 mRenderNode.getMatrix(matrix); 13709 return matrix; 13710 } 13711 13712 /** 13713 * Returns true if the transform matrix is the identity matrix. 13714 * Recomputes the matrix if necessary. 13715 * 13716 * @return True if the transform matrix is the identity matrix, false otherwise. 13717 */ 13718 final boolean hasIdentityMatrix() { 13719 return mRenderNode.hasIdentityMatrix(); 13720 } 13721 13722 void ensureTransformationInfo() { 13723 if (mTransformationInfo == null) { 13724 mTransformationInfo = new TransformationInfo(); 13725 } 13726 } 13727 13728 /** 13729 * Utility method to retrieve the inverse of the current mMatrix property. 13730 * We cache the matrix to avoid recalculating it when transform properties 13731 * have not changed. 13732 * 13733 * @return The inverse of the current matrix of this view. 13734 * @hide 13735 */ 13736 public final Matrix getInverseMatrix() { 13737 ensureTransformationInfo(); 13738 if (mTransformationInfo.mInverseMatrix == null) { 13739 mTransformationInfo.mInverseMatrix = new Matrix(); 13740 } 13741 final Matrix matrix = mTransformationInfo.mInverseMatrix; 13742 mRenderNode.getInverseMatrix(matrix); 13743 return matrix; 13744 } 13745 13746 /** 13747 * Gets the distance along the Z axis from the camera to this view. 13748 * 13749 * @see #setCameraDistance(float) 13750 * 13751 * @return The distance along the Z axis. 13752 */ 13753 public float getCameraDistance() { 13754 final float dpi = mResources.getDisplayMetrics().densityDpi; 13755 return -(mRenderNode.getCameraDistance() * dpi); 13756 } 13757 13758 /** 13759 * <p>Sets the distance along the Z axis (orthogonal to the X/Y plane on which 13760 * views are drawn) from the camera to this view. The camera's distance 13761 * affects 3D transformations, for instance rotations around the X and Y 13762 * axis. If the rotationX or rotationY properties are changed and this view is 13763 * large (more than half the size of the screen), it is recommended to always 13764 * use a camera distance that's greater than the height (X axis rotation) or 13765 * the width (Y axis rotation) of this view.</p> 13766 * 13767 * <p>The distance of the camera from the view plane can have an affect on the 13768 * perspective distortion of the view when it is rotated around the x or y axis. 13769 * For example, a large distance will result in a large viewing angle, and there 13770 * will not be much perspective distortion of the view as it rotates. A short 13771 * distance may cause much more perspective distortion upon rotation, and can 13772 * also result in some drawing artifacts if the rotated view ends up partially 13773 * behind the camera (which is why the recommendation is to use a distance at 13774 * least as far as the size of the view, if the view is to be rotated.)</p> 13775 * 13776 * <p>The distance is expressed in "depth pixels." The default distance depends 13777 * on the screen density. For instance, on a medium density display, the 13778 * default distance is 1280. On a high density display, the default distance 13779 * is 1920.</p> 13780 * 13781 * <p>If you want to specify a distance that leads to visually consistent 13782 * results across various densities, use the following formula:</p> 13783 * <pre> 13784 * float scale = context.getResources().getDisplayMetrics().density; 13785 * view.setCameraDistance(distance * scale); 13786 * </pre> 13787 * 13788 * <p>The density scale factor of a high density display is 1.5, 13789 * and 1920 = 1280 * 1.5.</p> 13790 * 13791 * @param distance The distance in "depth pixels", if negative the opposite 13792 * value is used 13793 * 13794 * @see #setRotationX(float) 13795 * @see #setRotationY(float) 13796 */ 13797 public void setCameraDistance(float distance) { 13798 final float dpi = mResources.getDisplayMetrics().densityDpi; 13799 13800 invalidateViewProperty(true, false); 13801 mRenderNode.setCameraDistance(-Math.abs(distance) / dpi); 13802 invalidateViewProperty(false, false); 13803 13804 invalidateParentIfNeededAndWasQuickRejected(); 13805 } 13806 13807 /** 13808 * The degrees that the view is rotated around the pivot point. 13809 * 13810 * @see #setRotation(float) 13811 * @see #getPivotX() 13812 * @see #getPivotY() 13813 * 13814 * @return The degrees of rotation. 13815 */ 13816 @ViewDebug.ExportedProperty(category = "drawing") 13817 public float getRotation() { 13818 return mRenderNode.getRotation(); 13819 } 13820 13821 /** 13822 * Sets the degrees that the view is rotated around the pivot point. Increasing values 13823 * result in clockwise rotation. 13824 * 13825 * @param rotation The degrees of rotation. 13826 * 13827 * @see #getRotation() 13828 * @see #getPivotX() 13829 * @see #getPivotY() 13830 * @see #setRotationX(float) 13831 * @see #setRotationY(float) 13832 * 13833 * @attr ref android.R.styleable#View_rotation 13834 */ 13835 public void setRotation(float rotation) { 13836 if (rotation != getRotation()) { 13837 // Double-invalidation is necessary to capture view's old and new areas 13838 invalidateViewProperty(true, false); 13839 mRenderNode.setRotation(rotation); 13840 invalidateViewProperty(false, true); 13841 13842 invalidateParentIfNeededAndWasQuickRejected(); 13843 notifySubtreeAccessibilityStateChangedIfNeeded(); 13844 } 13845 } 13846 13847 /** 13848 * The degrees that the view is rotated around the vertical axis through the pivot point. 13849 * 13850 * @see #getPivotX() 13851 * @see #getPivotY() 13852 * @see #setRotationY(float) 13853 * 13854 * @return The degrees of Y rotation. 13855 */ 13856 @ViewDebug.ExportedProperty(category = "drawing") 13857 public float getRotationY() { 13858 return mRenderNode.getRotationY(); 13859 } 13860 13861 /** 13862 * Sets the degrees that the view is rotated around the vertical axis through the pivot point. 13863 * Increasing values result in counter-clockwise rotation from the viewpoint of looking 13864 * down the y axis. 13865 * 13866 * When rotating large views, it is recommended to adjust the camera distance 13867 * accordingly. Refer to {@link #setCameraDistance(float)} for more information. 13868 * 13869 * @param rotationY The degrees of Y rotation. 13870 * 13871 * @see #getRotationY() 13872 * @see #getPivotX() 13873 * @see #getPivotY() 13874 * @see #setRotation(float) 13875 * @see #setRotationX(float) 13876 * @see #setCameraDistance(float) 13877 * 13878 * @attr ref android.R.styleable#View_rotationY 13879 */ 13880 public void setRotationY(float rotationY) { 13881 if (rotationY != getRotationY()) { 13882 invalidateViewProperty(true, false); 13883 mRenderNode.setRotationY(rotationY); 13884 invalidateViewProperty(false, true); 13885 13886 invalidateParentIfNeededAndWasQuickRejected(); 13887 notifySubtreeAccessibilityStateChangedIfNeeded(); 13888 } 13889 } 13890 13891 /** 13892 * The degrees that the view is rotated around the horizontal axis through the pivot point. 13893 * 13894 * @see #getPivotX() 13895 * @see #getPivotY() 13896 * @see #setRotationX(float) 13897 * 13898 * @return The degrees of X rotation. 13899 */ 13900 @ViewDebug.ExportedProperty(category = "drawing") 13901 public float getRotationX() { 13902 return mRenderNode.getRotationX(); 13903 } 13904 13905 /** 13906 * Sets the degrees that the view is rotated around the horizontal axis through the pivot point. 13907 * Increasing values result in clockwise rotation from the viewpoint of looking down the 13908 * x axis. 13909 * 13910 * When rotating large views, it is recommended to adjust the camera distance 13911 * accordingly. Refer to {@link #setCameraDistance(float)} for more information. 13912 * 13913 * @param rotationX The degrees of X rotation. 13914 * 13915 * @see #getRotationX() 13916 * @see #getPivotX() 13917 * @see #getPivotY() 13918 * @see #setRotation(float) 13919 * @see #setRotationY(float) 13920 * @see #setCameraDistance(float) 13921 * 13922 * @attr ref android.R.styleable#View_rotationX 13923 */ 13924 public void setRotationX(float rotationX) { 13925 if (rotationX != getRotationX()) { 13926 invalidateViewProperty(true, false); 13927 mRenderNode.setRotationX(rotationX); 13928 invalidateViewProperty(false, true); 13929 13930 invalidateParentIfNeededAndWasQuickRejected(); 13931 notifySubtreeAccessibilityStateChangedIfNeeded(); 13932 } 13933 } 13934 13935 /** 13936 * The amount that the view is scaled in x around the pivot point, as a proportion of 13937 * the view's unscaled width. A value of 1, the default, means that no scaling is applied. 13938 * 13939 * <p>By default, this is 1.0f. 13940 * 13941 * @see #getPivotX() 13942 * @see #getPivotY() 13943 * @return The scaling factor. 13944 */ 13945 @ViewDebug.ExportedProperty(category = "drawing") 13946 public float getScaleX() { 13947 return mRenderNode.getScaleX(); 13948 } 13949 13950 /** 13951 * Sets the amount that the view is scaled in x around the pivot point, as a proportion of 13952 * the view's unscaled width. A value of 1 means that no scaling is applied. 13953 * 13954 * @param scaleX The scaling factor. 13955 * @see #getPivotX() 13956 * @see #getPivotY() 13957 * 13958 * @attr ref android.R.styleable#View_scaleX 13959 */ 13960 public void setScaleX(float scaleX) { 13961 if (scaleX != getScaleX()) { 13962 invalidateViewProperty(true, false); 13963 mRenderNode.setScaleX(scaleX); 13964 invalidateViewProperty(false, true); 13965 13966 invalidateParentIfNeededAndWasQuickRejected(); 13967 notifySubtreeAccessibilityStateChangedIfNeeded(); 13968 } 13969 } 13970 13971 /** 13972 * The amount that the view is scaled in y around the pivot point, as a proportion of 13973 * the view's unscaled height. A value of 1, the default, means that no scaling is applied. 13974 * 13975 * <p>By default, this is 1.0f. 13976 * 13977 * @see #getPivotX() 13978 * @see #getPivotY() 13979 * @return The scaling factor. 13980 */ 13981 @ViewDebug.ExportedProperty(category = "drawing") 13982 public float getScaleY() { 13983 return mRenderNode.getScaleY(); 13984 } 13985 13986 /** 13987 * Sets the amount that the view is scaled in Y around the pivot point, as a proportion of 13988 * the view's unscaled width. A value of 1 means that no scaling is applied. 13989 * 13990 * @param scaleY The scaling factor. 13991 * @see #getPivotX() 13992 * @see #getPivotY() 13993 * 13994 * @attr ref android.R.styleable#View_scaleY 13995 */ 13996 public void setScaleY(float scaleY) { 13997 if (scaleY != getScaleY()) { 13998 invalidateViewProperty(true, false); 13999 mRenderNode.setScaleY(scaleY); 14000 invalidateViewProperty(false, true); 14001 14002 invalidateParentIfNeededAndWasQuickRejected(); 14003 notifySubtreeAccessibilityStateChangedIfNeeded(); 14004 } 14005 } 14006 14007 /** 14008 * The x location of the point around which the view is {@link #setRotation(float) rotated} 14009 * and {@link #setScaleX(float) scaled}. 14010 * 14011 * @see #getRotation() 14012 * @see #getScaleX() 14013 * @see #getScaleY() 14014 * @see #getPivotY() 14015 * @return The x location of the pivot point. 14016 * 14017 * @attr ref android.R.styleable#View_transformPivotX 14018 */ 14019 @ViewDebug.ExportedProperty(category = "drawing") 14020 public float getPivotX() { 14021 return mRenderNode.getPivotX(); 14022 } 14023 14024 /** 14025 * Sets the x location of the point around which the view is 14026 * {@link #setRotation(float) rotated} and {@link #setScaleX(float) scaled}. 14027 * By default, the pivot point is centered on the object. 14028 * Setting this property disables this behavior and causes the view to use only the 14029 * explicitly set pivotX and pivotY values. 14030 * 14031 * @param pivotX The x location of the pivot point. 14032 * @see #getRotation() 14033 * @see #getScaleX() 14034 * @see #getScaleY() 14035 * @see #getPivotY() 14036 * 14037 * @attr ref android.R.styleable#View_transformPivotX 14038 */ 14039 public void setPivotX(float pivotX) { 14040 if (!mRenderNode.isPivotExplicitlySet() || pivotX != getPivotX()) { 14041 invalidateViewProperty(true, false); 14042 mRenderNode.setPivotX(pivotX); 14043 invalidateViewProperty(false, true); 14044 14045 invalidateParentIfNeededAndWasQuickRejected(); 14046 } 14047 } 14048 14049 /** 14050 * The y location of the point around which the view is {@link #setRotation(float) rotated} 14051 * and {@link #setScaleY(float) scaled}. 14052 * 14053 * @see #getRotation() 14054 * @see #getScaleX() 14055 * @see #getScaleY() 14056 * @see #getPivotY() 14057 * @return The y location of the pivot point. 14058 * 14059 * @attr ref android.R.styleable#View_transformPivotY 14060 */ 14061 @ViewDebug.ExportedProperty(category = "drawing") 14062 public float getPivotY() { 14063 return mRenderNode.getPivotY(); 14064 } 14065 14066 /** 14067 * Sets the y location of the point around which the view is {@link #setRotation(float) rotated} 14068 * and {@link #setScaleY(float) scaled}. By default, the pivot point is centered on the object. 14069 * Setting this property disables this behavior and causes the view to use only the 14070 * explicitly set pivotX and pivotY values. 14071 * 14072 * @param pivotY The y location of the pivot point. 14073 * @see #getRotation() 14074 * @see #getScaleX() 14075 * @see #getScaleY() 14076 * @see #getPivotY() 14077 * 14078 * @attr ref android.R.styleable#View_transformPivotY 14079 */ 14080 public void setPivotY(float pivotY) { 14081 if (!mRenderNode.isPivotExplicitlySet() || pivotY != getPivotY()) { 14082 invalidateViewProperty(true, false); 14083 mRenderNode.setPivotY(pivotY); 14084 invalidateViewProperty(false, true); 14085 14086 invalidateParentIfNeededAndWasQuickRejected(); 14087 } 14088 } 14089 14090 /** 14091 * The opacity of the view. This is a value from 0 to 1, where 0 means the view is 14092 * completely transparent and 1 means the view is completely opaque. 14093 * 14094 * <p>By default this is 1.0f. 14095 * @return The opacity of the view. 14096 */ 14097 @ViewDebug.ExportedProperty(category = "drawing") 14098 public float getAlpha() { 14099 return mTransformationInfo != null ? mTransformationInfo.mAlpha : 1; 14100 } 14101 14102 /** 14103 * Sets the behavior for overlapping rendering for this view (see {@link 14104 * #hasOverlappingRendering()} for more details on this behavior). Calling this method 14105 * is an alternative to overriding {@link #hasOverlappingRendering()} in a subclass, 14106 * providing the value which is then used internally. That is, when {@link 14107 * #forceHasOverlappingRendering(boolean)} is called, the value of {@link 14108 * #hasOverlappingRendering()} is ignored and the value passed into this method is used 14109 * instead. 14110 * 14111 * @param hasOverlappingRendering The value for overlapping rendering to be used internally 14112 * instead of that returned by {@link #hasOverlappingRendering()}. 14113 * 14114 * @attr ref android.R.styleable#View_forceHasOverlappingRendering 14115 */ 14116 public void forceHasOverlappingRendering(boolean hasOverlappingRendering) { 14117 mPrivateFlags3 |= PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED; 14118 if (hasOverlappingRendering) { 14119 mPrivateFlags3 |= PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE; 14120 } else { 14121 mPrivateFlags3 &= ~PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE; 14122 } 14123 } 14124 14125 /** 14126 * Returns the value for overlapping rendering that is used internally. This is either 14127 * the value passed into {@link #forceHasOverlappingRendering(boolean)}, if called, or 14128 * the return value of {@link #hasOverlappingRendering()}, otherwise. 14129 * 14130 * @return The value for overlapping rendering being used internally. 14131 */ 14132 public final boolean getHasOverlappingRendering() { 14133 return (mPrivateFlags3 & PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED) != 0 ? 14134 (mPrivateFlags3 & PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE) != 0 : 14135 hasOverlappingRendering(); 14136 } 14137 14138 /** 14139 * Returns whether this View has content which overlaps. 14140 * 14141 * <p>This function, intended to be overridden by specific View types, is an optimization when 14142 * alpha is set on a view. If rendering overlaps in a view with alpha < 1, that view is drawn to 14143 * an offscreen buffer and then composited into place, which can be expensive. If the view has 14144 * no overlapping rendering, the view can draw each primitive with the appropriate alpha value 14145 * directly. An example of overlapping rendering is a TextView with a background image, such as 14146 * a Button. An example of non-overlapping rendering is a TextView with no background, or an 14147 * ImageView with only the foreground image. The default implementation returns true; subclasses 14148 * should override if they have cases which can be optimized.</p> 14149 * 14150 * <p>The current implementation of the saveLayer and saveLayerAlpha methods in {@link Canvas} 14151 * necessitates that a View return true if it uses the methods internally without passing the 14152 * {@link Canvas#CLIP_TO_LAYER_SAVE_FLAG}.</p> 14153 * 14154 * <p><strong>Note:</strong> The return value of this method is ignored if {@link 14155 * #forceHasOverlappingRendering(boolean)} has been called on this view.</p> 14156 * 14157 * @return true if the content in this view might overlap, false otherwise. 14158 */ 14159 @ViewDebug.ExportedProperty(category = "drawing") 14160 public boolean hasOverlappingRendering() { 14161 return true; 14162 } 14163 14164 /** 14165 * Sets the opacity of the view to a value from 0 to 1, where 0 means the view is 14166 * completely transparent and 1 means the view is completely opaque. 14167 * 14168 * <p class="note"><strong>Note:</strong> setting alpha to a translucent value (0 < alpha < 1) 14169 * can have significant performance implications, especially for large views. It is best to use 14170 * the alpha property sparingly and transiently, as in the case of fading animations.</p> 14171 * 14172 * <p>For a view with a frequently changing alpha, such as during a fading animation, it is 14173 * strongly recommended for performance reasons to either override 14174 * {@link #hasOverlappingRendering()} to return <code>false</code> if appropriate, or setting a 14175 * {@link #setLayerType(int, android.graphics.Paint) layer type} on the view for the duration 14176 * of the animation. On versions {@link android.os.Build.VERSION_CODES#M} and below, 14177 * the default path for rendering an unlayered View with alpha could add multiple milliseconds 14178 * of rendering cost, even for simple or small views. Starting with 14179 * {@link android.os.Build.VERSION_CODES#M}, {@link #LAYER_TYPE_HARDWARE} is automatically 14180 * applied to the view at the rendering level.</p> 14181 * 14182 * <p>If this view overrides {@link #onSetAlpha(int)} to return true, then this view is 14183 * responsible for applying the opacity itself.</p> 14184 * 14185 * <p>On versions {@link android.os.Build.VERSION_CODES#LOLLIPOP_MR1} and below, note that if 14186 * the view is backed by a {@link #setLayerType(int, android.graphics.Paint) layer} and is 14187 * associated with a {@link #setLayerPaint(android.graphics.Paint) layer paint}, setting an 14188 * alpha value less than 1.0 will supersede the alpha of the layer paint.</p> 14189 * 14190 * <p>Starting with {@link android.os.Build.VERSION_CODES#M}, setting a translucent alpha 14191 * value will clip a View to its bounds, unless the View returns <code>false</code> from 14192 * {@link #hasOverlappingRendering}.</p> 14193 * 14194 * @param alpha The opacity of the view. 14195 * 14196 * @see #hasOverlappingRendering() 14197 * @see #setLayerType(int, android.graphics.Paint) 14198 * 14199 * @attr ref android.R.styleable#View_alpha 14200 */ 14201 public void setAlpha(@FloatRange(from=0.0, to=1.0) float alpha) { 14202 ensureTransformationInfo(); 14203 if (mTransformationInfo.mAlpha != alpha) { 14204 // Report visibility changes, which can affect children, to accessibility 14205 if ((alpha == 0) ^ (mTransformationInfo.mAlpha == 0)) { 14206 notifySubtreeAccessibilityStateChangedIfNeeded(); 14207 } 14208 mTransformationInfo.mAlpha = alpha; 14209 if (onSetAlpha((int) (alpha * 255))) { 14210 mPrivateFlags |= PFLAG_ALPHA_SET; 14211 // subclass is handling alpha - don't optimize rendering cache invalidation 14212 invalidateParentCaches(); 14213 invalidate(true); 14214 } else { 14215 mPrivateFlags &= ~PFLAG_ALPHA_SET; 14216 invalidateViewProperty(true, false); 14217 mRenderNode.setAlpha(getFinalAlpha()); 14218 } 14219 } 14220 } 14221 14222 /** 14223 * Faster version of setAlpha() which performs the same steps except there are 14224 * no calls to invalidate(). The caller of this function should perform proper invalidation 14225 * on the parent and this object. The return value indicates whether the subclass handles 14226 * alpha (the return value for onSetAlpha()). 14227 * 14228 * @param alpha The new value for the alpha property 14229 * @return true if the View subclass handles alpha (the return value for onSetAlpha()) and 14230 * the new value for the alpha property is different from the old value 14231 */ 14232 boolean setAlphaNoInvalidation(float alpha) { 14233 ensureTransformationInfo(); 14234 if (mTransformationInfo.mAlpha != alpha) { 14235 mTransformationInfo.mAlpha = alpha; 14236 boolean subclassHandlesAlpha = onSetAlpha((int) (alpha * 255)); 14237 if (subclassHandlesAlpha) { 14238 mPrivateFlags |= PFLAG_ALPHA_SET; 14239 return true; 14240 } else { 14241 mPrivateFlags &= ~PFLAG_ALPHA_SET; 14242 mRenderNode.setAlpha(getFinalAlpha()); 14243 } 14244 } 14245 return false; 14246 } 14247 14248 /** 14249 * This property is hidden and intended only for use by the Fade transition, which 14250 * animates it to produce a visual translucency that does not side-effect (or get 14251 * affected by) the real alpha property. This value is composited with the other 14252 * alpha value (and the AlphaAnimation value, when that is present) to produce 14253 * a final visual translucency result, which is what is passed into the DisplayList. 14254 * 14255 * @hide 14256 */ 14257 public void setTransitionAlpha(float alpha) { 14258 ensureTransformationInfo(); 14259 if (mTransformationInfo.mTransitionAlpha != alpha) { 14260 mTransformationInfo.mTransitionAlpha = alpha; 14261 mPrivateFlags &= ~PFLAG_ALPHA_SET; 14262 invalidateViewProperty(true, false); 14263 mRenderNode.setAlpha(getFinalAlpha()); 14264 } 14265 } 14266 14267 /** 14268 * Calculates the visual alpha of this view, which is a combination of the actual 14269 * alpha value and the transitionAlpha value (if set). 14270 */ 14271 private float getFinalAlpha() { 14272 if (mTransformationInfo != null) { 14273 return mTransformationInfo.mAlpha * mTransformationInfo.mTransitionAlpha; 14274 } 14275 return 1; 14276 } 14277 14278 /** 14279 * This property is hidden and intended only for use by the Fade transition, which 14280 * animates it to produce a visual translucency that does not side-effect (or get 14281 * affected by) the real alpha property. This value is composited with the other 14282 * alpha value (and the AlphaAnimation value, when that is present) to produce 14283 * a final visual translucency result, which is what is passed into the DisplayList. 14284 * 14285 * @hide 14286 */ 14287 @ViewDebug.ExportedProperty(category = "drawing") 14288 public float getTransitionAlpha() { 14289 return mTransformationInfo != null ? mTransformationInfo.mTransitionAlpha : 1; 14290 } 14291 14292 /** 14293 * Top position of this view relative to its parent. 14294 * 14295 * @return The top of this view, in pixels. 14296 */ 14297 @ViewDebug.CapturedViewProperty 14298 public final int getTop() { 14299 return mTop; 14300 } 14301 14302 /** 14303 * Sets the top position of this view relative to its parent. This method is meant to be called 14304 * by the layout system and should not generally be called otherwise, because the property 14305 * may be changed at any time by the layout. 14306 * 14307 * @param top The top of this view, in pixels. 14308 */ 14309 public final void setTop(int top) { 14310 if (top != mTop) { 14311 final boolean matrixIsIdentity = hasIdentityMatrix(); 14312 if (matrixIsIdentity) { 14313 if (mAttachInfo != null) { 14314 int minTop; 14315 int yLoc; 14316 if (top < mTop) { 14317 minTop = top; 14318 yLoc = top - mTop; 14319 } else { 14320 minTop = mTop; 14321 yLoc = 0; 14322 } 14323 invalidate(0, yLoc, mRight - mLeft, mBottom - minTop); 14324 } 14325 } else { 14326 // Double-invalidation is necessary to capture view's old and new areas 14327 invalidate(true); 14328 } 14329 14330 int width = mRight - mLeft; 14331 int oldHeight = mBottom - mTop; 14332 14333 mTop = top; 14334 mRenderNode.setTop(mTop); 14335 14336 sizeChange(width, mBottom - mTop, width, oldHeight); 14337 14338 if (!matrixIsIdentity) { 14339 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 14340 invalidate(true); 14341 } 14342 mBackgroundSizeChanged = true; 14343 mDefaultFocusHighlightSizeChanged = true; 14344 if (mForegroundInfo != null) { 14345 mForegroundInfo.mBoundsChanged = true; 14346 } 14347 invalidateParentIfNeeded(); 14348 if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) { 14349 // View was rejected last time it was drawn by its parent; this may have changed 14350 invalidateParentIfNeeded(); 14351 } 14352 } 14353 } 14354 14355 /** 14356 * Bottom position of this view relative to its parent. 14357 * 14358 * @return The bottom of this view, in pixels. 14359 */ 14360 @ViewDebug.CapturedViewProperty 14361 public final int getBottom() { 14362 return mBottom; 14363 } 14364 14365 /** 14366 * True if this view has changed since the last time being drawn. 14367 * 14368 * @return The dirty state of this view. 14369 */ 14370 public boolean isDirty() { 14371 return (mPrivateFlags & PFLAG_DIRTY_MASK) != 0; 14372 } 14373 14374 /** 14375 * Sets the bottom position of this view relative to its parent. This method is meant to be 14376 * called by the layout system and should not generally be called otherwise, because the 14377 * property may be changed at any time by the layout. 14378 * 14379 * @param bottom The bottom of this view, in pixels. 14380 */ 14381 public final void setBottom(int bottom) { 14382 if (bottom != mBottom) { 14383 final boolean matrixIsIdentity = hasIdentityMatrix(); 14384 if (matrixIsIdentity) { 14385 if (mAttachInfo != null) { 14386 int maxBottom; 14387 if (bottom < mBottom) { 14388 maxBottom = mBottom; 14389 } else { 14390 maxBottom = bottom; 14391 } 14392 invalidate(0, 0, mRight - mLeft, maxBottom - mTop); 14393 } 14394 } else { 14395 // Double-invalidation is necessary to capture view's old and new areas 14396 invalidate(true); 14397 } 14398 14399 int width = mRight - mLeft; 14400 int oldHeight = mBottom - mTop; 14401 14402 mBottom = bottom; 14403 mRenderNode.setBottom(mBottom); 14404 14405 sizeChange(width, mBottom - mTop, width, oldHeight); 14406 14407 if (!matrixIsIdentity) { 14408 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 14409 invalidate(true); 14410 } 14411 mBackgroundSizeChanged = true; 14412 mDefaultFocusHighlightSizeChanged = true; 14413 if (mForegroundInfo != null) { 14414 mForegroundInfo.mBoundsChanged = true; 14415 } 14416 invalidateParentIfNeeded(); 14417 if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) { 14418 // View was rejected last time it was drawn by its parent; this may have changed 14419 invalidateParentIfNeeded(); 14420 } 14421 } 14422 } 14423 14424 /** 14425 * Left position of this view relative to its parent. 14426 * 14427 * @return The left edge of this view, in pixels. 14428 */ 14429 @ViewDebug.CapturedViewProperty 14430 public final int getLeft() { 14431 return mLeft; 14432 } 14433 14434 /** 14435 * Sets the left position of this view relative to its parent. This method is meant to be called 14436 * by the layout system and should not generally be called otherwise, because the property 14437 * may be changed at any time by the layout. 14438 * 14439 * @param left The left of this view, in pixels. 14440 */ 14441 public final void setLeft(int left) { 14442 if (left != mLeft) { 14443 final boolean matrixIsIdentity = hasIdentityMatrix(); 14444 if (matrixIsIdentity) { 14445 if (mAttachInfo != null) { 14446 int minLeft; 14447 int xLoc; 14448 if (left < mLeft) { 14449 minLeft = left; 14450 xLoc = left - mLeft; 14451 } else { 14452 minLeft = mLeft; 14453 xLoc = 0; 14454 } 14455 invalidate(xLoc, 0, mRight - minLeft, mBottom - mTop); 14456 } 14457 } else { 14458 // Double-invalidation is necessary to capture view's old and new areas 14459 invalidate(true); 14460 } 14461 14462 int oldWidth = mRight - mLeft; 14463 int height = mBottom - mTop; 14464 14465 mLeft = left; 14466 mRenderNode.setLeft(left); 14467 14468 sizeChange(mRight - mLeft, height, oldWidth, height); 14469 14470 if (!matrixIsIdentity) { 14471 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 14472 invalidate(true); 14473 } 14474 mBackgroundSizeChanged = true; 14475 mDefaultFocusHighlightSizeChanged = true; 14476 if (mForegroundInfo != null) { 14477 mForegroundInfo.mBoundsChanged = true; 14478 } 14479 invalidateParentIfNeeded(); 14480 if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) { 14481 // View was rejected last time it was drawn by its parent; this may have changed 14482 invalidateParentIfNeeded(); 14483 } 14484 } 14485 } 14486 14487 /** 14488 * Right position of this view relative to its parent. 14489 * 14490 * @return The right edge of this view, in pixels. 14491 */ 14492 @ViewDebug.CapturedViewProperty 14493 public final int getRight() { 14494 return mRight; 14495 } 14496 14497 /** 14498 * Sets the right position of this view relative to its parent. This method is meant to be called 14499 * by the layout system and should not generally be called otherwise, because the property 14500 * may be changed at any time by the layout. 14501 * 14502 * @param right The right of this view, in pixels. 14503 */ 14504 public final void setRight(int right) { 14505 if (right != mRight) { 14506 final boolean matrixIsIdentity = hasIdentityMatrix(); 14507 if (matrixIsIdentity) { 14508 if (mAttachInfo != null) { 14509 int maxRight; 14510 if (right < mRight) { 14511 maxRight = mRight; 14512 } else { 14513 maxRight = right; 14514 } 14515 invalidate(0, 0, maxRight - mLeft, mBottom - mTop); 14516 } 14517 } else { 14518 // Double-invalidation is necessary to capture view's old and new areas 14519 invalidate(true); 14520 } 14521 14522 int oldWidth = mRight - mLeft; 14523 int height = mBottom - mTop; 14524 14525 mRight = right; 14526 mRenderNode.setRight(mRight); 14527 14528 sizeChange(mRight - mLeft, height, oldWidth, height); 14529 14530 if (!matrixIsIdentity) { 14531 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 14532 invalidate(true); 14533 } 14534 mBackgroundSizeChanged = true; 14535 mDefaultFocusHighlightSizeChanged = true; 14536 if (mForegroundInfo != null) { 14537 mForegroundInfo.mBoundsChanged = true; 14538 } 14539 invalidateParentIfNeeded(); 14540 if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) { 14541 // View was rejected last time it was drawn by its parent; this may have changed 14542 invalidateParentIfNeeded(); 14543 } 14544 } 14545 } 14546 14547 /** 14548 * The visual x position of this view, in pixels. This is equivalent to the 14549 * {@link #setTranslationX(float) translationX} property plus the current 14550 * {@link #getLeft() left} property. 14551 * 14552 * @return The visual x position of this view, in pixels. 14553 */ 14554 @ViewDebug.ExportedProperty(category = "drawing") 14555 public float getX() { 14556 return mLeft + getTranslationX(); 14557 } 14558 14559 /** 14560 * Sets the visual x position of this view, in pixels. This is equivalent to setting the 14561 * {@link #setTranslationX(float) translationX} property to be the difference between 14562 * the x value passed in and the current {@link #getLeft() left} property. 14563 * 14564 * @param x The visual x position of this view, in pixels. 14565 */ 14566 public void setX(float x) { 14567 setTranslationX(x - mLeft); 14568 } 14569 14570 /** 14571 * The visual y position of this view, in pixels. This is equivalent to the 14572 * {@link #setTranslationY(float) translationY} property plus the current 14573 * {@link #getTop() top} property. 14574 * 14575 * @return The visual y position of this view, in pixels. 14576 */ 14577 @ViewDebug.ExportedProperty(category = "drawing") 14578 public float getY() { 14579 return mTop + getTranslationY(); 14580 } 14581 14582 /** 14583 * Sets the visual y position of this view, in pixels. This is equivalent to setting the 14584 * {@link #setTranslationY(float) translationY} property to be the difference between 14585 * the y value passed in and the current {@link #getTop() top} property. 14586 * 14587 * @param y The visual y position of this view, in pixels. 14588 */ 14589 public void setY(float y) { 14590 setTranslationY(y - mTop); 14591 } 14592 14593 /** 14594 * The visual z position of this view, in pixels. This is equivalent to the 14595 * {@link #setTranslationZ(float) translationZ} property plus the current 14596 * {@link #getElevation() elevation} property. 14597 * 14598 * @return The visual z position of this view, in pixels. 14599 */ 14600 @ViewDebug.ExportedProperty(category = "drawing") 14601 public float getZ() { 14602 return getElevation() + getTranslationZ(); 14603 } 14604 14605 /** 14606 * Sets the visual z position of this view, in pixels. This is equivalent to setting the 14607 * {@link #setTranslationZ(float) translationZ} property to be the difference between 14608 * the x value passed in and the current {@link #getElevation() elevation} property. 14609 * 14610 * @param z The visual z position of this view, in pixels. 14611 */ 14612 public void setZ(float z) { 14613 setTranslationZ(z - getElevation()); 14614 } 14615 14616 /** 14617 * The base elevation of this view relative to its parent, in pixels. 14618 * 14619 * @return The base depth position of the view, in pixels. 14620 */ 14621 @ViewDebug.ExportedProperty(category = "drawing") 14622 public float getElevation() { 14623 return mRenderNode.getElevation(); 14624 } 14625 14626 /** 14627 * Sets the base elevation of this view, in pixels. 14628 * 14629 * @attr ref android.R.styleable#View_elevation 14630 */ 14631 public void setElevation(float elevation) { 14632 if (elevation != getElevation()) { 14633 invalidateViewProperty(true, false); 14634 mRenderNode.setElevation(elevation); 14635 invalidateViewProperty(false, true); 14636 14637 invalidateParentIfNeededAndWasQuickRejected(); 14638 } 14639 } 14640 14641 /** 14642 * The horizontal location of this view relative to its {@link #getLeft() left} position. 14643 * This position is post-layout, in addition to wherever the object's 14644 * layout placed it. 14645 * 14646 * @return The horizontal position of this view relative to its left position, in pixels. 14647 */ 14648 @ViewDebug.ExportedProperty(category = "drawing") 14649 public float getTranslationX() { 14650 return mRenderNode.getTranslationX(); 14651 } 14652 14653 /** 14654 * Sets the horizontal location of this view relative to its {@link #getLeft() left} position. 14655 * This effectively positions the object post-layout, in addition to wherever the object's 14656 * layout placed it. 14657 * 14658 * @param translationX The horizontal position of this view relative to its left position, 14659 * in pixels. 14660 * 14661 * @attr ref android.R.styleable#View_translationX 14662 */ 14663 public void setTranslationX(float translationX) { 14664 if (translationX != getTranslationX()) { 14665 invalidateViewProperty(true, false); 14666 mRenderNode.setTranslationX(translationX); 14667 invalidateViewProperty(false, true); 14668 14669 invalidateParentIfNeededAndWasQuickRejected(); 14670 notifySubtreeAccessibilityStateChangedIfNeeded(); 14671 } 14672 } 14673 14674 /** 14675 * The vertical location of this view relative to its {@link #getTop() top} position. 14676 * This position is post-layout, in addition to wherever the object's 14677 * layout placed it. 14678 * 14679 * @return The vertical position of this view relative to its top position, 14680 * in pixels. 14681 */ 14682 @ViewDebug.ExportedProperty(category = "drawing") 14683 public float getTranslationY() { 14684 return mRenderNode.getTranslationY(); 14685 } 14686 14687 /** 14688 * Sets the vertical location of this view relative to its {@link #getTop() top} position. 14689 * This effectively positions the object post-layout, in addition to wherever the object's 14690 * layout placed it. 14691 * 14692 * @param translationY The vertical position of this view relative to its top position, 14693 * in pixels. 14694 * 14695 * @attr ref android.R.styleable#View_translationY 14696 */ 14697 public void setTranslationY(float translationY) { 14698 if (translationY != getTranslationY()) { 14699 invalidateViewProperty(true, false); 14700 mRenderNode.setTranslationY(translationY); 14701 invalidateViewProperty(false, true); 14702 14703 invalidateParentIfNeededAndWasQuickRejected(); 14704 notifySubtreeAccessibilityStateChangedIfNeeded(); 14705 } 14706 } 14707 14708 /** 14709 * The depth location of this view relative to its {@link #getElevation() elevation}. 14710 * 14711 * @return The depth of this view relative to its elevation. 14712 */ 14713 @ViewDebug.ExportedProperty(category = "drawing") 14714 public float getTranslationZ() { 14715 return mRenderNode.getTranslationZ(); 14716 } 14717 14718 /** 14719 * Sets the depth location of this view relative to its {@link #getElevation() elevation}. 14720 * 14721 * @attr ref android.R.styleable#View_translationZ 14722 */ 14723 public void setTranslationZ(float translationZ) { 14724 if (translationZ != getTranslationZ()) { 14725 invalidateViewProperty(true, false); 14726 mRenderNode.setTranslationZ(translationZ); 14727 invalidateViewProperty(false, true); 14728 14729 invalidateParentIfNeededAndWasQuickRejected(); 14730 } 14731 } 14732 14733 /** @hide */ 14734 public void setAnimationMatrix(Matrix matrix) { 14735 invalidateViewProperty(true, false); 14736 mRenderNode.setAnimationMatrix(matrix); 14737 invalidateViewProperty(false, true); 14738 14739 invalidateParentIfNeededAndWasQuickRejected(); 14740 } 14741 14742 /** 14743 * Returns the current StateListAnimator if exists. 14744 * 14745 * @return StateListAnimator or null if it does not exists 14746 * @see #setStateListAnimator(android.animation.StateListAnimator) 14747 */ 14748 public StateListAnimator getStateListAnimator() { 14749 return mStateListAnimator; 14750 } 14751 14752 /** 14753 * Attaches the provided StateListAnimator to this View. 14754 * <p> 14755 * Any previously attached StateListAnimator will be detached. 14756 * 14757 * @param stateListAnimator The StateListAnimator to update the view 14758 * @see android.animation.StateListAnimator 14759 */ 14760 public void setStateListAnimator(StateListAnimator stateListAnimator) { 14761 if (mStateListAnimator == stateListAnimator) { 14762 return; 14763 } 14764 if (mStateListAnimator != null) { 14765 mStateListAnimator.setTarget(null); 14766 } 14767 mStateListAnimator = stateListAnimator; 14768 if (stateListAnimator != null) { 14769 stateListAnimator.setTarget(this); 14770 if (isAttachedToWindow()) { 14771 stateListAnimator.setState(getDrawableState()); 14772 } 14773 } 14774 } 14775 14776 /** 14777 * Returns whether the Outline should be used to clip the contents of the View. 14778 * <p> 14779 * Note that this flag will only be respected if the View's Outline returns true from 14780 * {@link Outline#canClip()}. 14781 * 14782 * @see #setOutlineProvider(ViewOutlineProvider) 14783 * @see #setClipToOutline(boolean) 14784 */ 14785 public final boolean getClipToOutline() { 14786 return mRenderNode.getClipToOutline(); 14787 } 14788 14789 /** 14790 * Sets whether the View's Outline should be used to clip the contents of the View. 14791 * <p> 14792 * Only a single non-rectangular clip can be applied on a View at any time. 14793 * Circular clips from a {@link ViewAnimationUtils#createCircularReveal(View, int, int, float, float) 14794 * circular reveal} animation take priority over Outline clipping, and 14795 * child Outline clipping takes priority over Outline clipping done by a 14796 * parent. 14797 * <p> 14798 * Note that this flag will only be respected if the View's Outline returns true from 14799 * {@link Outline#canClip()}. 14800 * 14801 * @see #setOutlineProvider(ViewOutlineProvider) 14802 * @see #getClipToOutline() 14803 */ 14804 public void setClipToOutline(boolean clipToOutline) { 14805 damageInParent(); 14806 if (getClipToOutline() != clipToOutline) { 14807 mRenderNode.setClipToOutline(clipToOutline); 14808 } 14809 } 14810 14811 // correspond to the enum values of View_outlineProvider 14812 private static final int PROVIDER_BACKGROUND = 0; 14813 private static final int PROVIDER_NONE = 1; 14814 private static final int PROVIDER_BOUNDS = 2; 14815 private static final int PROVIDER_PADDED_BOUNDS = 3; 14816 private void setOutlineProviderFromAttribute(int providerInt) { 14817 switch (providerInt) { 14818 case PROVIDER_BACKGROUND: 14819 setOutlineProvider(ViewOutlineProvider.BACKGROUND); 14820 break; 14821 case PROVIDER_NONE: 14822 setOutlineProvider(null); 14823 break; 14824 case PROVIDER_BOUNDS: 14825 setOutlineProvider(ViewOutlineProvider.BOUNDS); 14826 break; 14827 case PROVIDER_PADDED_BOUNDS: 14828 setOutlineProvider(ViewOutlineProvider.PADDED_BOUNDS); 14829 break; 14830 } 14831 } 14832 14833 /** 14834 * Sets the {@link ViewOutlineProvider} of the view, which generates the Outline that defines 14835 * the shape of the shadow it casts, and enables outline clipping. 14836 * <p> 14837 * The default ViewOutlineProvider, {@link ViewOutlineProvider#BACKGROUND}, queries the Outline 14838 * from the View's background drawable, via {@link Drawable#getOutline(Outline)}. Changing the 14839 * outline provider with this method allows this behavior to be overridden. 14840 * <p> 14841 * If the ViewOutlineProvider is null, if querying it for an outline returns false, 14842 * or if the produced Outline is {@link Outline#isEmpty()}, shadows will not be cast. 14843 * <p> 14844 * Only outlines that return true from {@link Outline#canClip()} may be used for clipping. 14845 * 14846 * @see #setClipToOutline(boolean) 14847 * @see #getClipToOutline() 14848 * @see #getOutlineProvider() 14849 */ 14850 public void setOutlineProvider(ViewOutlineProvider provider) { 14851 mOutlineProvider = provider; 14852 invalidateOutline(); 14853 } 14854 14855 /** 14856 * Returns the current {@link ViewOutlineProvider} of the view, which generates the Outline 14857 * that defines the shape of the shadow it casts, and enables outline clipping. 14858 * 14859 * @see #setOutlineProvider(ViewOutlineProvider) 14860 */ 14861 public ViewOutlineProvider getOutlineProvider() { 14862 return mOutlineProvider; 14863 } 14864 14865 /** 14866 * Called to rebuild this View's Outline from its {@link ViewOutlineProvider outline provider} 14867 * 14868 * @see #setOutlineProvider(ViewOutlineProvider) 14869 */ 14870 public void invalidateOutline() { 14871 rebuildOutline(); 14872 14873 notifySubtreeAccessibilityStateChangedIfNeeded(); 14874 invalidateViewProperty(false, false); 14875 } 14876 14877 /** 14878 * Internal version of {@link #invalidateOutline()} which invalidates the 14879 * outline without invalidating the view itself. This is intended to be called from 14880 * within methods in the View class itself which are the result of the view being 14881 * invalidated already. For example, when we are drawing the background of a View, 14882 * we invalidate the outline in case it changed in the meantime, but we do not 14883 * need to invalidate the view because we're already drawing the background as part 14884 * of drawing the view in response to an earlier invalidation of the view. 14885 */ 14886 private void rebuildOutline() { 14887 // Unattached views ignore this signal, and outline is recomputed in onAttachedToWindow() 14888 if (mAttachInfo == null) return; 14889 14890 if (mOutlineProvider == null) { 14891 // no provider, remove outline 14892 mRenderNode.setOutline(null); 14893 } else { 14894 final Outline outline = mAttachInfo.mTmpOutline; 14895 outline.setEmpty(); 14896 outline.setAlpha(1.0f); 14897 14898 mOutlineProvider.getOutline(this, outline); 14899 mRenderNode.setOutline(outline); 14900 } 14901 } 14902 14903 /** 14904 * HierarchyViewer only 14905 * 14906 * @hide 14907 */ 14908 @ViewDebug.ExportedProperty(category = "drawing") 14909 public boolean hasShadow() { 14910 return mRenderNode.hasShadow(); 14911 } 14912 14913 14914 /** @hide */ 14915 public void setRevealClip(boolean shouldClip, float x, float y, float radius) { 14916 mRenderNode.setRevealClip(shouldClip, x, y, radius); 14917 invalidateViewProperty(false, false); 14918 } 14919 14920 /** 14921 * Hit rectangle in parent's coordinates 14922 * 14923 * @param outRect The hit rectangle of the view. 14924 */ 14925 public void getHitRect(Rect outRect) { 14926 if (hasIdentityMatrix() || mAttachInfo == null) { 14927 outRect.set(mLeft, mTop, mRight, mBottom); 14928 } else { 14929 final RectF tmpRect = mAttachInfo.mTmpTransformRect; 14930 tmpRect.set(0, 0, getWidth(), getHeight()); 14931 getMatrix().mapRect(tmpRect); // TODO: mRenderNode.mapRect(tmpRect) 14932 outRect.set((int) tmpRect.left + mLeft, (int) tmpRect.top + mTop, 14933 (int) tmpRect.right + mLeft, (int) tmpRect.bottom + mTop); 14934 } 14935 } 14936 14937 /** 14938 * Determines whether the given point, in local coordinates is inside the view. 14939 */ 14940 /*package*/ final boolean pointInView(float localX, float localY) { 14941 return pointInView(localX, localY, 0); 14942 } 14943 14944 /** 14945 * Utility method to determine whether the given point, in local coordinates, 14946 * is inside the view, where the area of the view is expanded by the slop factor. 14947 * This method is called while processing touch-move events to determine if the event 14948 * is still within the view. 14949 * 14950 * @hide 14951 */ 14952 public boolean pointInView(float localX, float localY, float slop) { 14953 return localX >= -slop && localY >= -slop && localX < ((mRight - mLeft) + slop) && 14954 localY < ((mBottom - mTop) + slop); 14955 } 14956 14957 /** 14958 * When a view has focus and the user navigates away from it, the next view is searched for 14959 * starting from the rectangle filled in by this method. 14960 * 14961 * By default, the rectangle is the {@link #getDrawingRect(android.graphics.Rect)}) 14962 * of the view. However, if your view maintains some idea of internal selection, 14963 * such as a cursor, or a selected row or column, you should override this method and 14964 * fill in a more specific rectangle. 14965 * 14966 * @param r The rectangle to fill in, in this view's coordinates. 14967 */ 14968 public void getFocusedRect(Rect r) { 14969 getDrawingRect(r); 14970 } 14971 14972 /** 14973 * If some part of this view is not clipped by any of its parents, then 14974 * return that area in r in global (root) coordinates. To convert r to local 14975 * coordinates (without taking possible View rotations into account), offset 14976 * it by -globalOffset (e.g. r.offset(-globalOffset.x, -globalOffset.y)). 14977 * If the view is completely clipped or translated out, return false. 14978 * 14979 * @param r If true is returned, r holds the global coordinates of the 14980 * visible portion of this view. 14981 * @param globalOffset If true is returned, globalOffset holds the dx,dy 14982 * between this view and its root. globalOffet may be null. 14983 * @return true if r is non-empty (i.e. part of the view is visible at the 14984 * root level. 14985 */ 14986 public boolean getGlobalVisibleRect(Rect r, Point globalOffset) { 14987 int width = mRight - mLeft; 14988 int height = mBottom - mTop; 14989 if (width > 0 && height > 0) { 14990 r.set(0, 0, width, height); 14991 if (globalOffset != null) { 14992 globalOffset.set(-mScrollX, -mScrollY); 14993 } 14994 return mParent == null || mParent.getChildVisibleRect(this, r, globalOffset); 14995 } 14996 return false; 14997 } 14998 14999 public final boolean getGlobalVisibleRect(Rect r) { 15000 return getGlobalVisibleRect(r, null); 15001 } 15002 15003 public final boolean getLocalVisibleRect(Rect r) { 15004 final Point offset = mAttachInfo != null ? mAttachInfo.mPoint : new Point(); 15005 if (getGlobalVisibleRect(r, offset)) { 15006 r.offset(-offset.x, -offset.y); // make r local 15007 return true; 15008 } 15009 return false; 15010 } 15011 15012 /** 15013 * Offset this view's vertical location by the specified number of pixels. 15014 * 15015 * @param offset the number of pixels to offset the view by 15016 */ 15017 public void offsetTopAndBottom(int offset) { 15018 if (offset != 0) { 15019 final boolean matrixIsIdentity = hasIdentityMatrix(); 15020 if (matrixIsIdentity) { 15021 if (isHardwareAccelerated()) { 15022 invalidateViewProperty(false, false); 15023 } else { 15024 final ViewParent p = mParent; 15025 if (p != null && mAttachInfo != null) { 15026 final Rect r = mAttachInfo.mTmpInvalRect; 15027 int minTop; 15028 int maxBottom; 15029 int yLoc; 15030 if (offset < 0) { 15031 minTop = mTop + offset; 15032 maxBottom = mBottom; 15033 yLoc = offset; 15034 } else { 15035 minTop = mTop; 15036 maxBottom = mBottom + offset; 15037 yLoc = 0; 15038 } 15039 r.set(0, yLoc, mRight - mLeft, maxBottom - minTop); 15040 p.invalidateChild(this, r); 15041 } 15042 } 15043 } else { 15044 invalidateViewProperty(false, false); 15045 } 15046 15047 mTop += offset; 15048 mBottom += offset; 15049 mRenderNode.offsetTopAndBottom(offset); 15050 if (isHardwareAccelerated()) { 15051 invalidateViewProperty(false, false); 15052 invalidateParentIfNeededAndWasQuickRejected(); 15053 } else { 15054 if (!matrixIsIdentity) { 15055 invalidateViewProperty(false, true); 15056 } 15057 invalidateParentIfNeeded(); 15058 } 15059 notifySubtreeAccessibilityStateChangedIfNeeded(); 15060 } 15061 } 15062 15063 /** 15064 * Offset this view's horizontal location by the specified amount of pixels. 15065 * 15066 * @param offset the number of pixels to offset the view by 15067 */ 15068 public void offsetLeftAndRight(int offset) { 15069 if (offset != 0) { 15070 final boolean matrixIsIdentity = hasIdentityMatrix(); 15071 if (matrixIsIdentity) { 15072 if (isHardwareAccelerated()) { 15073 invalidateViewProperty(false, false); 15074 } else { 15075 final ViewParent p = mParent; 15076 if (p != null && mAttachInfo != null) { 15077 final Rect r = mAttachInfo.mTmpInvalRect; 15078 int minLeft; 15079 int maxRight; 15080 if (offset < 0) { 15081 minLeft = mLeft + offset; 15082 maxRight = mRight; 15083 } else { 15084 minLeft = mLeft; 15085 maxRight = mRight + offset; 15086 } 15087 r.set(0, 0, maxRight - minLeft, mBottom - mTop); 15088 p.invalidateChild(this, r); 15089 } 15090 } 15091 } else { 15092 invalidateViewProperty(false, false); 15093 } 15094 15095 mLeft += offset; 15096 mRight += offset; 15097 mRenderNode.offsetLeftAndRight(offset); 15098 if (isHardwareAccelerated()) { 15099 invalidateViewProperty(false, false); 15100 invalidateParentIfNeededAndWasQuickRejected(); 15101 } else { 15102 if (!matrixIsIdentity) { 15103 invalidateViewProperty(false, true); 15104 } 15105 invalidateParentIfNeeded(); 15106 } 15107 notifySubtreeAccessibilityStateChangedIfNeeded(); 15108 } 15109 } 15110 15111 /** 15112 * Get the LayoutParams associated with this view. All views should have 15113 * layout parameters. These supply parameters to the <i>parent</i> of this 15114 * view specifying how it should be arranged. There are many subclasses of 15115 * ViewGroup.LayoutParams, and these correspond to the different subclasses 15116 * of ViewGroup that are responsible for arranging their children. 15117 * 15118 * This method may return null if this View is not attached to a parent 15119 * ViewGroup or {@link #setLayoutParams(android.view.ViewGroup.LayoutParams)} 15120 * was not invoked successfully. When a View is attached to a parent 15121 * ViewGroup, this method must not return null. 15122 * 15123 * @return The LayoutParams associated with this view, or null if no 15124 * parameters have been set yet 15125 */ 15126 @ViewDebug.ExportedProperty(deepExport = true, prefix = "layout_") 15127 public ViewGroup.LayoutParams getLayoutParams() { 15128 return mLayoutParams; 15129 } 15130 15131 /** 15132 * Set the layout parameters associated with this view. These supply 15133 * parameters to the <i>parent</i> of this view specifying how it should be 15134 * arranged. There are many subclasses of ViewGroup.LayoutParams, and these 15135 * correspond to the different subclasses of ViewGroup that are responsible 15136 * for arranging their children. 15137 * 15138 * @param params The layout parameters for this view, cannot be null 15139 */ 15140 public void setLayoutParams(ViewGroup.LayoutParams params) { 15141 if (params == null) { 15142 throw new NullPointerException("Layout parameters cannot be null"); 15143 } 15144 mLayoutParams = params; 15145 resolveLayoutParams(); 15146 if (mParent instanceof ViewGroup) { 15147 ((ViewGroup) mParent).onSetLayoutParams(this, params); 15148 } 15149 requestLayout(); 15150 } 15151 15152 /** 15153 * Resolve the layout parameters depending on the resolved layout direction 15154 * 15155 * @hide 15156 */ 15157 public void resolveLayoutParams() { 15158 if (mLayoutParams != null) { 15159 mLayoutParams.resolveLayoutDirection(getLayoutDirection()); 15160 } 15161 } 15162 15163 /** 15164 * Set the scrolled position of your view. This will cause a call to 15165 * {@link #onScrollChanged(int, int, int, int)} and the view will be 15166 * invalidated. 15167 * @param x the x position to scroll to 15168 * @param y the y position to scroll to 15169 */ 15170 public void scrollTo(int x, int y) { 15171 if (mScrollX != x || mScrollY != y) { 15172 int oldX = mScrollX; 15173 int oldY = mScrollY; 15174 mScrollX = x; 15175 mScrollY = y; 15176 invalidateParentCaches(); 15177 onScrollChanged(mScrollX, mScrollY, oldX, oldY); 15178 if (!awakenScrollBars()) { 15179 postInvalidateOnAnimation(); 15180 } 15181 } 15182 } 15183 15184 /** 15185 * Move the scrolled position of your view. This will cause a call to 15186 * {@link #onScrollChanged(int, int, int, int)} and the view will be 15187 * invalidated. 15188 * @param x the amount of pixels to scroll by horizontally 15189 * @param y the amount of pixels to scroll by vertically 15190 */ 15191 public void scrollBy(int x, int y) { 15192 scrollTo(mScrollX + x, mScrollY + y); 15193 } 15194 15195 /** 15196 * <p>Trigger the scrollbars to draw. When invoked this method starts an 15197 * animation to fade the scrollbars out after a default delay. If a subclass 15198 * provides animated scrolling, the start delay should equal the duration 15199 * of the scrolling animation.</p> 15200 * 15201 * <p>The animation starts only if at least one of the scrollbars is 15202 * enabled, as specified by {@link #isHorizontalScrollBarEnabled()} and 15203 * {@link #isVerticalScrollBarEnabled()}. When the animation is started, 15204 * this method returns true, and false otherwise. If the animation is 15205 * started, this method calls {@link #invalidate()}; in that case the 15206 * caller should not call {@link #invalidate()}.</p> 15207 * 15208 * <p>This method should be invoked every time a subclass directly updates 15209 * the scroll parameters.</p> 15210 * 15211 * <p>This method is automatically invoked by {@link #scrollBy(int, int)} 15212 * and {@link #scrollTo(int, int)}.</p> 15213 * 15214 * @return true if the animation is played, false otherwise 15215 * 15216 * @see #awakenScrollBars(int) 15217 * @see #scrollBy(int, int) 15218 * @see #scrollTo(int, int) 15219 * @see #isHorizontalScrollBarEnabled() 15220 * @see #isVerticalScrollBarEnabled() 15221 * @see #setHorizontalScrollBarEnabled(boolean) 15222 * @see #setVerticalScrollBarEnabled(boolean) 15223 */ 15224 protected boolean awakenScrollBars() { 15225 return mScrollCache != null && 15226 awakenScrollBars(mScrollCache.scrollBarDefaultDelayBeforeFade, true); 15227 } 15228 15229 /** 15230 * Trigger the scrollbars to draw. 15231 * This method differs from awakenScrollBars() only in its default duration. 15232 * initialAwakenScrollBars() will show the scroll bars for longer than 15233 * usual to give the user more of a chance to notice them. 15234 * 15235 * @return true if the animation is played, false otherwise. 15236 */ 15237 private boolean initialAwakenScrollBars() { 15238 return mScrollCache != null && 15239 awakenScrollBars(mScrollCache.scrollBarDefaultDelayBeforeFade * 4, true); 15240 } 15241 15242 /** 15243 * <p> 15244 * Trigger the scrollbars to draw. When invoked this method starts an 15245 * animation to fade the scrollbars out after a fixed delay. If a subclass 15246 * provides animated scrolling, the start delay should equal the duration of 15247 * the scrolling animation. 15248 * </p> 15249 * 15250 * <p> 15251 * The animation starts only if at least one of the scrollbars is enabled, 15252 * as specified by {@link #isHorizontalScrollBarEnabled()} and 15253 * {@link #isVerticalScrollBarEnabled()}. When the animation is started, 15254 * this method returns true, and false otherwise. If the animation is 15255 * started, this method calls {@link #invalidate()}; in that case the caller 15256 * should not call {@link #invalidate()}. 15257 * </p> 15258 * 15259 * <p> 15260 * This method should be invoked every time a subclass directly updates the 15261 * scroll parameters. 15262 * </p> 15263 * 15264 * @param startDelay the delay, in milliseconds, after which the animation 15265 * should start; when the delay is 0, the animation starts 15266 * immediately 15267 * @return true if the animation is played, false otherwise 15268 * 15269 * @see #scrollBy(int, int) 15270 * @see #scrollTo(int, int) 15271 * @see #isHorizontalScrollBarEnabled() 15272 * @see #isVerticalScrollBarEnabled() 15273 * @see #setHorizontalScrollBarEnabled(boolean) 15274 * @see #setVerticalScrollBarEnabled(boolean) 15275 */ 15276 protected boolean awakenScrollBars(int startDelay) { 15277 return awakenScrollBars(startDelay, true); 15278 } 15279 15280 /** 15281 * <p> 15282 * Trigger the scrollbars to draw. When invoked this method starts an 15283 * animation to fade the scrollbars out after a fixed delay. If a subclass 15284 * provides animated scrolling, the start delay should equal the duration of 15285 * the scrolling animation. 15286 * </p> 15287 * 15288 * <p> 15289 * The animation starts only if at least one of the scrollbars is enabled, 15290 * as specified by {@link #isHorizontalScrollBarEnabled()} and 15291 * {@link #isVerticalScrollBarEnabled()}. When the animation is started, 15292 * this method returns true, and false otherwise. If the animation is 15293 * started, this method calls {@link #invalidate()} if the invalidate parameter 15294 * is set to true; in that case the caller 15295 * should not call {@link #invalidate()}. 15296 * </p> 15297 * 15298 * <p> 15299 * This method should be invoked every time a subclass directly updates the 15300 * scroll parameters. 15301 * </p> 15302 * 15303 * @param startDelay the delay, in milliseconds, after which the animation 15304 * should start; when the delay is 0, the animation starts 15305 * immediately 15306 * 15307 * @param invalidate Whether this method should call invalidate 15308 * 15309 * @return true if the animation is played, false otherwise 15310 * 15311 * @see #scrollBy(int, int) 15312 * @see #scrollTo(int, int) 15313 * @see #isHorizontalScrollBarEnabled() 15314 * @see #isVerticalScrollBarEnabled() 15315 * @see #setHorizontalScrollBarEnabled(boolean) 15316 * @see #setVerticalScrollBarEnabled(boolean) 15317 */ 15318 protected boolean awakenScrollBars(int startDelay, boolean invalidate) { 15319 final ScrollabilityCache scrollCache = mScrollCache; 15320 15321 if (scrollCache == null || !scrollCache.fadeScrollBars) { 15322 return false; 15323 } 15324 15325 if (scrollCache.scrollBar == null) { 15326 scrollCache.scrollBar = new ScrollBarDrawable(); 15327 scrollCache.scrollBar.setState(getDrawableState()); 15328 scrollCache.scrollBar.setCallback(this); 15329 } 15330 15331 if (isHorizontalScrollBarEnabled() || isVerticalScrollBarEnabled()) { 15332 15333 if (invalidate) { 15334 // Invalidate to show the scrollbars 15335 postInvalidateOnAnimation(); 15336 } 15337 15338 if (scrollCache.state == ScrollabilityCache.OFF) { 15339 // FIXME: this is copied from WindowManagerService. 15340 // We should get this value from the system when it 15341 // is possible to do so. 15342 final int KEY_REPEAT_FIRST_DELAY = 750; 15343 startDelay = Math.max(KEY_REPEAT_FIRST_DELAY, startDelay); 15344 } 15345 15346 // Tell mScrollCache when we should start fading. This may 15347 // extend the fade start time if one was already scheduled 15348 long fadeStartTime = AnimationUtils.currentAnimationTimeMillis() + startDelay; 15349 scrollCache.fadeStartTime = fadeStartTime; 15350 scrollCache.state = ScrollabilityCache.ON; 15351 15352 // Schedule our fader to run, unscheduling any old ones first 15353 if (mAttachInfo != null) { 15354 mAttachInfo.mHandler.removeCallbacks(scrollCache); 15355 mAttachInfo.mHandler.postAtTime(scrollCache, fadeStartTime); 15356 } 15357 15358 return true; 15359 } 15360 15361 return false; 15362 } 15363 15364 /** 15365 * Do not invalidate views which are not visible and which are not running an animation. They 15366 * will not get drawn and they should not set dirty flags as if they will be drawn 15367 */ 15368 private boolean skipInvalidate() { 15369 return (mViewFlags & VISIBILITY_MASK) != VISIBLE && mCurrentAnimation == null && 15370 (!(mParent instanceof ViewGroup) || 15371 !((ViewGroup) mParent).isViewTransitioning(this)); 15372 } 15373 15374 /** 15375 * Mark the area defined by dirty as needing to be drawn. If the view is 15376 * visible, {@link #onDraw(android.graphics.Canvas)} will be called at some 15377 * point in the future. 15378 * <p> 15379 * This must be called from a UI thread. To call from a non-UI thread, call 15380 * {@link #postInvalidate()}. 15381 * <p> 15382 * <b>WARNING:</b> In API 19 and below, this method may be destructive to 15383 * {@code dirty}. 15384 * 15385 * @param dirty the rectangle representing the bounds of the dirty region 15386 */ 15387 public void invalidate(Rect dirty) { 15388 final int scrollX = mScrollX; 15389 final int scrollY = mScrollY; 15390 invalidateInternal(dirty.left - scrollX, dirty.top - scrollY, 15391 dirty.right - scrollX, dirty.bottom - scrollY, true, false); 15392 } 15393 15394 /** 15395 * Mark the area defined by the rect (l,t,r,b) as needing to be drawn. The 15396 * coordinates of the dirty rect are relative to the view. If the view is 15397 * visible, {@link #onDraw(android.graphics.Canvas)} will be called at some 15398 * point in the future. 15399 * <p> 15400 * This must be called from a UI thread. To call from a non-UI thread, call 15401 * {@link #postInvalidate()}. 15402 * 15403 * @param l the left position of the dirty region 15404 * @param t the top position of the dirty region 15405 * @param r the right position of the dirty region 15406 * @param b the bottom position of the dirty region 15407 */ 15408 public void invalidate(int l, int t, int r, int b) { 15409 final int scrollX = mScrollX; 15410 final int scrollY = mScrollY; 15411 invalidateInternal(l - scrollX, t - scrollY, r - scrollX, b - scrollY, true, false); 15412 } 15413 15414 /** 15415 * Invalidate the whole view. If the view is visible, 15416 * {@link #onDraw(android.graphics.Canvas)} will be called at some point in 15417 * the future. 15418 * <p> 15419 * This must be called from a UI thread. To call from a non-UI thread, call 15420 * {@link #postInvalidate()}. 15421 */ 15422 public void invalidate() { 15423 invalidate(true); 15424 } 15425 15426 /** 15427 * This is where the invalidate() work actually happens. A full invalidate() 15428 * causes the drawing cache to be invalidated, but this function can be 15429 * called with invalidateCache set to false to skip that invalidation step 15430 * for cases that do not need it (for example, a component that remains at 15431 * the same dimensions with the same content). 15432 * 15433 * @param invalidateCache Whether the drawing cache for this view should be 15434 * invalidated as well. This is usually true for a full 15435 * invalidate, but may be set to false if the View's contents or 15436 * dimensions have not changed. 15437 * @hide 15438 */ 15439 public void invalidate(boolean invalidateCache) { 15440 invalidateInternal(0, 0, mRight - mLeft, mBottom - mTop, invalidateCache, true); 15441 } 15442 15443 void invalidateInternal(int l, int t, int r, int b, boolean invalidateCache, 15444 boolean fullInvalidate) { 15445 if (mGhostView != null) { 15446 mGhostView.invalidate(true); 15447 return; 15448 } 15449 15450 if (skipInvalidate()) { 15451 return; 15452 } 15453 15454 if ((mPrivateFlags & (PFLAG_DRAWN | PFLAG_HAS_BOUNDS)) == (PFLAG_DRAWN | PFLAG_HAS_BOUNDS) 15455 || (invalidateCache && (mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == PFLAG_DRAWING_CACHE_VALID) 15456 || (mPrivateFlags & PFLAG_INVALIDATED) != PFLAG_INVALIDATED 15457 || (fullInvalidate && isOpaque() != mLastIsOpaque)) { 15458 if (fullInvalidate) { 15459 mLastIsOpaque = isOpaque(); 15460 mPrivateFlags &= ~PFLAG_DRAWN; 15461 } 15462 15463 mPrivateFlags |= PFLAG_DIRTY; 15464 15465 if (invalidateCache) { 15466 mPrivateFlags |= PFLAG_INVALIDATED; 15467 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; 15468 } 15469 15470 // Propagate the damage rectangle to the parent view. 15471 final AttachInfo ai = mAttachInfo; 15472 final ViewParent p = mParent; 15473 if (p != null && ai != null && l < r && t < b) { 15474 final Rect damage = ai.mTmpInvalRect; 15475 damage.set(l, t, r, b); 15476 p.invalidateChild(this, damage); 15477 } 15478 15479 // Damage the entire projection receiver, if necessary. 15480 if (mBackground != null && mBackground.isProjected()) { 15481 final View receiver = getProjectionReceiver(); 15482 if (receiver != null) { 15483 receiver.damageInParent(); 15484 } 15485 } 15486 } 15487 } 15488 15489 /** 15490 * @return this view's projection receiver, or {@code null} if none exists 15491 */ 15492 private View getProjectionReceiver() { 15493 ViewParent p = getParent(); 15494 while (p != null && p instanceof View) { 15495 final View v = (View) p; 15496 if (v.isProjectionReceiver()) { 15497 return v; 15498 } 15499 p = p.getParent(); 15500 } 15501 15502 return null; 15503 } 15504 15505 /** 15506 * @return whether the view is a projection receiver 15507 */ 15508 private boolean isProjectionReceiver() { 15509 return mBackground != null; 15510 } 15511 15512 /** 15513 * Quick invalidation for View property changes (alpha, translationXY, etc.). We don't want to 15514 * set any flags or handle all of the cases handled by the default invalidation methods. 15515 * Instead, we just want to schedule a traversal in ViewRootImpl with the appropriate 15516 * dirty rect. This method calls into fast invalidation methods in ViewGroup that 15517 * walk up the hierarchy, transforming the dirty rect as necessary. 15518 * 15519 * The method also handles normal invalidation logic if display list properties are not 15520 * being used in this view. The invalidateParent and forceRedraw flags are used by that 15521 * backup approach, to handle these cases used in the various property-setting methods. 15522 * 15523 * @param invalidateParent Force a call to invalidateParentCaches() if display list properties 15524 * are not being used in this view 15525 * @param forceRedraw Mark the view as DRAWN to force the invalidation to propagate, if display 15526 * list properties are not being used in this view 15527 */ 15528 void invalidateViewProperty(boolean invalidateParent, boolean forceRedraw) { 15529 if (!isHardwareAccelerated() 15530 || !mRenderNode.isValid() 15531 || (mPrivateFlags & PFLAG_DRAW_ANIMATION) != 0) { 15532 if (invalidateParent) { 15533 invalidateParentCaches(); 15534 } 15535 if (forceRedraw) { 15536 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 15537 } 15538 invalidate(false); 15539 } else { 15540 damageInParent(); 15541 } 15542 } 15543 15544 /** 15545 * Tells the parent view to damage this view's bounds. 15546 * 15547 * @hide 15548 */ 15549 protected void damageInParent() { 15550 if (mParent != null && mAttachInfo != null) { 15551 mParent.onDescendantInvalidated(this, this); 15552 } 15553 } 15554 15555 /** 15556 * Utility method to transform a given Rect by the current matrix of this view. 15557 */ 15558 void transformRect(final Rect rect) { 15559 if (!getMatrix().isIdentity()) { 15560 RectF boundingRect = mAttachInfo.mTmpTransformRect; 15561 boundingRect.set(rect); 15562 getMatrix().mapRect(boundingRect); 15563 rect.set((int) Math.floor(boundingRect.left), 15564 (int) Math.floor(boundingRect.top), 15565 (int) Math.ceil(boundingRect.right), 15566 (int) Math.ceil(boundingRect.bottom)); 15567 } 15568 } 15569 15570 /** 15571 * Used to indicate that the parent of this view should clear its caches. This functionality 15572 * is used to force the parent to rebuild its display list (when hardware-accelerated), 15573 * which is necessary when various parent-managed properties of the view change, such as 15574 * alpha, translationX/Y, scrollX/Y, scaleX/Y, and rotation/X/Y. This method only 15575 * clears the parent caches and does not causes an invalidate event. 15576 * 15577 * @hide 15578 */ 15579 protected void invalidateParentCaches() { 15580 if (mParent instanceof View) { 15581 ((View) mParent).mPrivateFlags |= PFLAG_INVALIDATED; 15582 } 15583 } 15584 15585 /** 15586 * Used to indicate that the parent of this view should be invalidated. This functionality 15587 * is used to force the parent to rebuild its display list (when hardware-accelerated), 15588 * which is necessary when various parent-managed properties of the view change, such as 15589 * alpha, translationX/Y, scrollX/Y, scaleX/Y, and rotation/X/Y. This method will propagate 15590 * an invalidation event to the parent. 15591 * 15592 * @hide 15593 */ 15594 protected void invalidateParentIfNeeded() { 15595 if (isHardwareAccelerated() && mParent instanceof View) { 15596 ((View) mParent).invalidate(true); 15597 } 15598 } 15599 15600 /** 15601 * @hide 15602 */ 15603 protected void invalidateParentIfNeededAndWasQuickRejected() { 15604 if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) != 0) { 15605 // View was rejected last time it was drawn by its parent; this may have changed 15606 invalidateParentIfNeeded(); 15607 } 15608 } 15609 15610 /** 15611 * Indicates whether this View is opaque. An opaque View guarantees that it will 15612 * draw all the pixels overlapping its bounds using a fully opaque color. 15613 * 15614 * Subclasses of View should override this method whenever possible to indicate 15615 * whether an instance is opaque. Opaque Views are treated in a special way by 15616 * the View hierarchy, possibly allowing it to perform optimizations during 15617 * invalidate/draw passes. 15618 * 15619 * @return True if this View is guaranteed to be fully opaque, false otherwise. 15620 */ 15621 @ViewDebug.ExportedProperty(category = "drawing") 15622 public boolean isOpaque() { 15623 return (mPrivateFlags & PFLAG_OPAQUE_MASK) == PFLAG_OPAQUE_MASK && 15624 getFinalAlpha() >= 1.0f; 15625 } 15626 15627 /** 15628 * @hide 15629 */ 15630 protected void computeOpaqueFlags() { 15631 // Opaque if: 15632 // - Has a background 15633 // - Background is opaque 15634 // - Doesn't have scrollbars or scrollbars overlay 15635 15636 if (mBackground != null && mBackground.getOpacity() == PixelFormat.OPAQUE) { 15637 mPrivateFlags |= PFLAG_OPAQUE_BACKGROUND; 15638 } else { 15639 mPrivateFlags &= ~PFLAG_OPAQUE_BACKGROUND; 15640 } 15641 15642 final int flags = mViewFlags; 15643 if (((flags & SCROLLBARS_VERTICAL) == 0 && (flags & SCROLLBARS_HORIZONTAL) == 0) || 15644 (flags & SCROLLBARS_STYLE_MASK) == SCROLLBARS_INSIDE_OVERLAY || 15645 (flags & SCROLLBARS_STYLE_MASK) == SCROLLBARS_OUTSIDE_OVERLAY) { 15646 mPrivateFlags |= PFLAG_OPAQUE_SCROLLBARS; 15647 } else { 15648 mPrivateFlags &= ~PFLAG_OPAQUE_SCROLLBARS; 15649 } 15650 } 15651 15652 /** 15653 * @hide 15654 */ 15655 protected boolean hasOpaqueScrollbars() { 15656 return (mPrivateFlags & PFLAG_OPAQUE_SCROLLBARS) == PFLAG_OPAQUE_SCROLLBARS; 15657 } 15658 15659 /** 15660 * @return A handler associated with the thread running the View. This 15661 * handler can be used to pump events in the UI events queue. 15662 */ 15663 public Handler getHandler() { 15664 final AttachInfo attachInfo = mAttachInfo; 15665 if (attachInfo != null) { 15666 return attachInfo.mHandler; 15667 } 15668 return null; 15669 } 15670 15671 /** 15672 * Returns the queue of runnable for this view. 15673 * 15674 * @return the queue of runnables for this view 15675 */ 15676 private HandlerActionQueue getRunQueue() { 15677 if (mRunQueue == null) { 15678 mRunQueue = new HandlerActionQueue(); 15679 } 15680 return mRunQueue; 15681 } 15682 15683 /** 15684 * Gets the view root associated with the View. 15685 * @return The view root, or null if none. 15686 * @hide 15687 */ 15688 public ViewRootImpl getViewRootImpl() { 15689 if (mAttachInfo != null) { 15690 return mAttachInfo.mViewRootImpl; 15691 } 15692 return null; 15693 } 15694 15695 /** 15696 * @hide 15697 */ 15698 public ThreadedRenderer getThreadedRenderer() { 15699 return mAttachInfo != null ? mAttachInfo.mThreadedRenderer : null; 15700 } 15701 15702 /** 15703 * <p>Causes the Runnable to be added to the message queue. 15704 * The runnable will be run on the user interface thread.</p> 15705 * 15706 * @param action The Runnable that will be executed. 15707 * 15708 * @return Returns true if the Runnable was successfully placed in to the 15709 * message queue. Returns false on failure, usually because the 15710 * looper processing the message queue is exiting. 15711 * 15712 * @see #postDelayed 15713 * @see #removeCallbacks 15714 */ 15715 public boolean post(Runnable action) { 15716 final AttachInfo attachInfo = mAttachInfo; 15717 if (attachInfo != null) { 15718 return attachInfo.mHandler.post(action); 15719 } 15720 15721 // Postpone the runnable until we know on which thread it needs to run. 15722 // Assume that the runnable will be successfully placed after attach. 15723 getRunQueue().post(action); 15724 return true; 15725 } 15726 15727 /** 15728 * <p>Causes the Runnable to be added to the message queue, to be run 15729 * after the specified amount of time elapses. 15730 * The runnable will be run on the user interface thread.</p> 15731 * 15732 * @param action The Runnable that will be executed. 15733 * @param delayMillis The delay (in milliseconds) until the Runnable 15734 * will be executed. 15735 * 15736 * @return true if the Runnable was successfully placed in to the 15737 * message queue. Returns false on failure, usually because the 15738 * looper processing the message queue is exiting. Note that a 15739 * result of true does not mean the Runnable will be processed -- 15740 * if the looper is quit before the delivery time of the message 15741 * occurs then the message will be dropped. 15742 * 15743 * @see #post 15744 * @see #removeCallbacks 15745 */ 15746 public boolean postDelayed(Runnable action, long delayMillis) { 15747 final AttachInfo attachInfo = mAttachInfo; 15748 if (attachInfo != null) { 15749 return attachInfo.mHandler.postDelayed(action, delayMillis); 15750 } 15751 15752 // Postpone the runnable until we know on which thread it needs to run. 15753 // Assume that the runnable will be successfully placed after attach. 15754 getRunQueue().postDelayed(action, delayMillis); 15755 return true; 15756 } 15757 15758 /** 15759 * <p>Causes the Runnable to execute on the next animation time step. 15760 * The runnable will be run on the user interface thread.</p> 15761 * 15762 * @param action The Runnable that will be executed. 15763 * 15764 * @see #postOnAnimationDelayed 15765 * @see #removeCallbacks 15766 */ 15767 public void postOnAnimation(Runnable action) { 15768 final AttachInfo attachInfo = mAttachInfo; 15769 if (attachInfo != null) { 15770 attachInfo.mViewRootImpl.mChoreographer.postCallback( 15771 Choreographer.CALLBACK_ANIMATION, action, null); 15772 } else { 15773 // Postpone the runnable until we know 15774 // on which thread it needs to run. 15775 getRunQueue().post(action); 15776 } 15777 } 15778 15779 /** 15780 * <p>Causes the Runnable to execute on the next animation time step, 15781 * after the specified amount of time elapses. 15782 * The runnable will be run on the user interface thread.</p> 15783 * 15784 * @param action The Runnable that will be executed. 15785 * @param delayMillis The delay (in milliseconds) until the Runnable 15786 * will be executed. 15787 * 15788 * @see #postOnAnimation 15789 * @see #removeCallbacks 15790 */ 15791 public void postOnAnimationDelayed(Runnable action, long delayMillis) { 15792 final AttachInfo attachInfo = mAttachInfo; 15793 if (attachInfo != null) { 15794 attachInfo.mViewRootImpl.mChoreographer.postCallbackDelayed( 15795 Choreographer.CALLBACK_ANIMATION, action, null, delayMillis); 15796 } else { 15797 // Postpone the runnable until we know 15798 // on which thread it needs to run. 15799 getRunQueue().postDelayed(action, delayMillis); 15800 } 15801 } 15802 15803 /** 15804 * <p>Removes the specified Runnable from the message queue.</p> 15805 * 15806 * @param action The Runnable to remove from the message handling queue 15807 * 15808 * @return true if this view could ask the Handler to remove the Runnable, 15809 * false otherwise. When the returned value is true, the Runnable 15810 * may or may not have been actually removed from the message queue 15811 * (for instance, if the Runnable was not in the queue already.) 15812 * 15813 * @see #post 15814 * @see #postDelayed 15815 * @see #postOnAnimation 15816 * @see #postOnAnimationDelayed 15817 */ 15818 public boolean removeCallbacks(Runnable action) { 15819 if (action != null) { 15820 final AttachInfo attachInfo = mAttachInfo; 15821 if (attachInfo != null) { 15822 attachInfo.mHandler.removeCallbacks(action); 15823 attachInfo.mViewRootImpl.mChoreographer.removeCallbacks( 15824 Choreographer.CALLBACK_ANIMATION, action, null); 15825 } 15826 getRunQueue().removeCallbacks(action); 15827 } 15828 return true; 15829 } 15830 15831 /** 15832 * <p>Cause an invalidate to happen on a subsequent cycle through the event loop. 15833 * Use this to invalidate the View from a non-UI thread.</p> 15834 * 15835 * <p>This method can be invoked from outside of the UI thread 15836 * only when this View is attached to a window.</p> 15837 * 15838 * @see #invalidate() 15839 * @see #postInvalidateDelayed(long) 15840 */ 15841 public void postInvalidate() { 15842 postInvalidateDelayed(0); 15843 } 15844 15845 /** 15846 * <p>Cause an invalidate of the specified area to happen on a subsequent cycle 15847 * through the event loop. Use this to invalidate the View from a non-UI thread.</p> 15848 * 15849 * <p>This method can be invoked from outside of the UI thread 15850 * only when this View is attached to a window.</p> 15851 * 15852 * @param left The left coordinate of the rectangle to invalidate. 15853 * @param top The top coordinate of the rectangle to invalidate. 15854 * @param right The right coordinate of the rectangle to invalidate. 15855 * @param bottom The bottom coordinate of the rectangle to invalidate. 15856 * 15857 * @see #invalidate(int, int, int, int) 15858 * @see #invalidate(Rect) 15859 * @see #postInvalidateDelayed(long, int, int, int, int) 15860 */ 15861 public void postInvalidate(int left, int top, int right, int bottom) { 15862 postInvalidateDelayed(0, left, top, right, bottom); 15863 } 15864 15865 /** 15866 * <p>Cause an invalidate to happen on a subsequent cycle through the event 15867 * loop. Waits for the specified amount of time.</p> 15868 * 15869 * <p>This method can be invoked from outside of the UI thread 15870 * only when this View is attached to a window.</p> 15871 * 15872 * @param delayMilliseconds the duration in milliseconds to delay the 15873 * invalidation by 15874 * 15875 * @see #invalidate() 15876 * @see #postInvalidate() 15877 */ 15878 public void postInvalidateDelayed(long delayMilliseconds) { 15879 // We try only with the AttachInfo because there's no point in invalidating 15880 // if we are not attached to our window 15881 final AttachInfo attachInfo = mAttachInfo; 15882 if (attachInfo != null) { 15883 attachInfo.mViewRootImpl.dispatchInvalidateDelayed(this, delayMilliseconds); 15884 } 15885 } 15886 15887 /** 15888 * <p>Cause an invalidate of the specified area to happen on a subsequent cycle 15889 * through the event loop. Waits for the specified amount of time.</p> 15890 * 15891 * <p>This method can be invoked from outside of the UI thread 15892 * only when this View is attached to a window.</p> 15893 * 15894 * @param delayMilliseconds the duration in milliseconds to delay the 15895 * invalidation by 15896 * @param left The left coordinate of the rectangle to invalidate. 15897 * @param top The top coordinate of the rectangle to invalidate. 15898 * @param right The right coordinate of the rectangle to invalidate. 15899 * @param bottom The bottom coordinate of the rectangle to invalidate. 15900 * 15901 * @see #invalidate(int, int, int, int) 15902 * @see #invalidate(Rect) 15903 * @see #postInvalidate(int, int, int, int) 15904 */ 15905 public void postInvalidateDelayed(long delayMilliseconds, int left, int top, 15906 int right, int bottom) { 15907 15908 // We try only with the AttachInfo because there's no point in invalidating 15909 // if we are not attached to our window 15910 final AttachInfo attachInfo = mAttachInfo; 15911 if (attachInfo != null) { 15912 final AttachInfo.InvalidateInfo info = AttachInfo.InvalidateInfo.obtain(); 15913 info.target = this; 15914 info.left = left; 15915 info.top = top; 15916 info.right = right; 15917 info.bottom = bottom; 15918 15919 attachInfo.mViewRootImpl.dispatchInvalidateRectDelayed(info, delayMilliseconds); 15920 } 15921 } 15922 15923 /** 15924 * <p>Cause an invalidate to happen on the next animation time step, typically the 15925 * next display frame.</p> 15926 * 15927 * <p>This method can be invoked from outside of the UI thread 15928 * only when this View is attached to a window.</p> 15929 * 15930 * @see #invalidate() 15931 */ 15932 public void postInvalidateOnAnimation() { 15933 // We try only with the AttachInfo because there's no point in invalidating 15934 // if we are not attached to our window 15935 final AttachInfo attachInfo = mAttachInfo; 15936 if (attachInfo != null) { 15937 attachInfo.mViewRootImpl.dispatchInvalidateOnAnimation(this); 15938 } 15939 } 15940 15941 /** 15942 * <p>Cause an invalidate of the specified area to happen on the next animation 15943 * time step, typically the next display frame.</p> 15944 * 15945 * <p>This method can be invoked from outside of the UI thread 15946 * only when this View is attached to a window.</p> 15947 * 15948 * @param left The left coordinate of the rectangle to invalidate. 15949 * @param top The top coordinate of the rectangle to invalidate. 15950 * @param right The right coordinate of the rectangle to invalidate. 15951 * @param bottom The bottom coordinate of the rectangle to invalidate. 15952 * 15953 * @see #invalidate(int, int, int, int) 15954 * @see #invalidate(Rect) 15955 */ 15956 public void postInvalidateOnAnimation(int left, int top, int right, int bottom) { 15957 // We try only with the AttachInfo because there's no point in invalidating 15958 // if we are not attached to our window 15959 final AttachInfo attachInfo = mAttachInfo; 15960 if (attachInfo != null) { 15961 final AttachInfo.InvalidateInfo info = AttachInfo.InvalidateInfo.obtain(); 15962 info.target = this; 15963 info.left = left; 15964 info.top = top; 15965 info.right = right; 15966 info.bottom = bottom; 15967 15968 attachInfo.mViewRootImpl.dispatchInvalidateRectOnAnimation(info); 15969 } 15970 } 15971 15972 /** 15973 * Post a callback to send a {@link AccessibilityEvent#TYPE_VIEW_SCROLLED} event. 15974 * This event is sent at most once every 15975 * {@link ViewConfiguration#getSendRecurringAccessibilityEventsInterval()}. 15976 */ 15977 private void postSendViewScrolledAccessibilityEventCallback() { 15978 if (mSendViewScrolledAccessibilityEvent == null) { 15979 mSendViewScrolledAccessibilityEvent = new SendViewScrolledAccessibilityEvent(); 15980 } 15981 if (!mSendViewScrolledAccessibilityEvent.mIsPending) { 15982 mSendViewScrolledAccessibilityEvent.mIsPending = true; 15983 postDelayed(mSendViewScrolledAccessibilityEvent, 15984 ViewConfiguration.getSendRecurringAccessibilityEventsInterval()); 15985 } 15986 } 15987 15988 /** 15989 * Called by a parent to request that a child update its values for mScrollX 15990 * and mScrollY if necessary. This will typically be done if the child is 15991 * animating a scroll using a {@link android.widget.Scroller Scroller} 15992 * object. 15993 */ 15994 public void computeScroll() { 15995 } 15996 15997 /** 15998 * <p>Indicate whether the horizontal edges are faded when the view is 15999 * scrolled horizontally.</p> 16000 * 16001 * @return true if the horizontal edges should are faded on scroll, false 16002 * otherwise 16003 * 16004 * @see #setHorizontalFadingEdgeEnabled(boolean) 16005 * 16006 * @attr ref android.R.styleable#View_requiresFadingEdge 16007 */ 16008 public boolean isHorizontalFadingEdgeEnabled() { 16009 return (mViewFlags & FADING_EDGE_HORIZONTAL) == FADING_EDGE_HORIZONTAL; 16010 } 16011 16012 /** 16013 * <p>Define whether the horizontal edges should be faded when this view 16014 * is scrolled horizontally.</p> 16015 * 16016 * @param horizontalFadingEdgeEnabled true if the horizontal edges should 16017 * be faded when the view is scrolled 16018 * horizontally 16019 * 16020 * @see #isHorizontalFadingEdgeEnabled() 16021 * 16022 * @attr ref android.R.styleable#View_requiresFadingEdge 16023 */ 16024 public void setHorizontalFadingEdgeEnabled(boolean horizontalFadingEdgeEnabled) { 16025 if (isHorizontalFadingEdgeEnabled() != horizontalFadingEdgeEnabled) { 16026 if (horizontalFadingEdgeEnabled) { 16027 initScrollCache(); 16028 } 16029 16030 mViewFlags ^= FADING_EDGE_HORIZONTAL; 16031 } 16032 } 16033 16034 /** 16035 * <p>Indicate whether the vertical edges are faded when the view is 16036 * scrolled horizontally.</p> 16037 * 16038 * @return true if the vertical edges should are faded on scroll, false 16039 * otherwise 16040 * 16041 * @see #setVerticalFadingEdgeEnabled(boolean) 16042 * 16043 * @attr ref android.R.styleable#View_requiresFadingEdge 16044 */ 16045 public boolean isVerticalFadingEdgeEnabled() { 16046 return (mViewFlags & FADING_EDGE_VERTICAL) == FADING_EDGE_VERTICAL; 16047 } 16048 16049 /** 16050 * <p>Define whether the vertical edges should be faded when this view 16051 * is scrolled vertically.</p> 16052 * 16053 * @param verticalFadingEdgeEnabled true if the vertical edges should 16054 * be faded when the view is scrolled 16055 * vertically 16056 * 16057 * @see #isVerticalFadingEdgeEnabled() 16058 * 16059 * @attr ref android.R.styleable#View_requiresFadingEdge 16060 */ 16061 public void setVerticalFadingEdgeEnabled(boolean verticalFadingEdgeEnabled) { 16062 if (isVerticalFadingEdgeEnabled() != verticalFadingEdgeEnabled) { 16063 if (verticalFadingEdgeEnabled) { 16064 initScrollCache(); 16065 } 16066 16067 mViewFlags ^= FADING_EDGE_VERTICAL; 16068 } 16069 } 16070 16071 /** 16072 * Returns the strength, or intensity, of the top faded edge. The strength is 16073 * a value between 0.0 (no fade) and 1.0 (full fade). The default implementation 16074 * returns 0.0 or 1.0 but no value in between. 16075 * 16076 * Subclasses should override this method to provide a smoother fade transition 16077 * when scrolling occurs. 16078 * 16079 * @return the intensity of the top fade as a float between 0.0f and 1.0f 16080 */ 16081 protected float getTopFadingEdgeStrength() { 16082 return computeVerticalScrollOffset() > 0 ? 1.0f : 0.0f; 16083 } 16084 16085 /** 16086 * Returns the strength, or intensity, of the bottom faded edge. The strength is 16087 * a value between 0.0 (no fade) and 1.0 (full fade). The default implementation 16088 * returns 0.0 or 1.0 but no value in between. 16089 * 16090 * Subclasses should override this method to provide a smoother fade transition 16091 * when scrolling occurs. 16092 * 16093 * @return the intensity of the bottom fade as a float between 0.0f and 1.0f 16094 */ 16095 protected float getBottomFadingEdgeStrength() { 16096 return computeVerticalScrollOffset() + computeVerticalScrollExtent() < 16097 computeVerticalScrollRange() ? 1.0f : 0.0f; 16098 } 16099 16100 /** 16101 * Returns the strength, or intensity, of the left faded edge. The strength is 16102 * a value between 0.0 (no fade) and 1.0 (full fade). The default implementation 16103 * returns 0.0 or 1.0 but no value in between. 16104 * 16105 * Subclasses should override this method to provide a smoother fade transition 16106 * when scrolling occurs. 16107 * 16108 * @return the intensity of the left fade as a float between 0.0f and 1.0f 16109 */ 16110 protected float getLeftFadingEdgeStrength() { 16111 return computeHorizontalScrollOffset() > 0 ? 1.0f : 0.0f; 16112 } 16113 16114 /** 16115 * Returns the strength, or intensity, of the right faded edge. The strength is 16116 * a value between 0.0 (no fade) and 1.0 (full fade). The default implementation 16117 * returns 0.0 or 1.0 but no value in between. 16118 * 16119 * Subclasses should override this method to provide a smoother fade transition 16120 * when scrolling occurs. 16121 * 16122 * @return the intensity of the right fade as a float between 0.0f and 1.0f 16123 */ 16124 protected float getRightFadingEdgeStrength() { 16125 return computeHorizontalScrollOffset() + computeHorizontalScrollExtent() < 16126 computeHorizontalScrollRange() ? 1.0f : 0.0f; 16127 } 16128 16129 /** 16130 * <p>Indicate whether the horizontal scrollbar should be drawn or not. The 16131 * scrollbar is not drawn by default.</p> 16132 * 16133 * @return true if the horizontal scrollbar should be painted, false 16134 * otherwise 16135 * 16136 * @see #setHorizontalScrollBarEnabled(boolean) 16137 */ 16138 public boolean isHorizontalScrollBarEnabled() { 16139 return (mViewFlags & SCROLLBARS_HORIZONTAL) == SCROLLBARS_HORIZONTAL; 16140 } 16141 16142 /** 16143 * <p>Define whether the horizontal scrollbar should be drawn or not. The 16144 * scrollbar is not drawn by default.</p> 16145 * 16146 * @param horizontalScrollBarEnabled true if the horizontal scrollbar should 16147 * be painted 16148 * 16149 * @see #isHorizontalScrollBarEnabled() 16150 */ 16151 public void setHorizontalScrollBarEnabled(boolean horizontalScrollBarEnabled) { 16152 if (isHorizontalScrollBarEnabled() != horizontalScrollBarEnabled) { 16153 mViewFlags ^= SCROLLBARS_HORIZONTAL; 16154 computeOpaqueFlags(); 16155 resolvePadding(); 16156 } 16157 } 16158 16159 /** 16160 * <p>Indicate whether the vertical scrollbar should be drawn or not. The 16161 * scrollbar is not drawn by default.</p> 16162 * 16163 * @return true if the vertical scrollbar should be painted, false 16164 * otherwise 16165 * 16166 * @see #setVerticalScrollBarEnabled(boolean) 16167 */ 16168 public boolean isVerticalScrollBarEnabled() { 16169 return (mViewFlags & SCROLLBARS_VERTICAL) == SCROLLBARS_VERTICAL; 16170 } 16171 16172 /** 16173 * <p>Define whether the vertical scrollbar should be drawn or not. The 16174 * scrollbar is not drawn by default.</p> 16175 * 16176 * @param verticalScrollBarEnabled true if the vertical scrollbar should 16177 * be painted 16178 * 16179 * @see #isVerticalScrollBarEnabled() 16180 */ 16181 public void setVerticalScrollBarEnabled(boolean verticalScrollBarEnabled) { 16182 if (isVerticalScrollBarEnabled() != verticalScrollBarEnabled) { 16183 mViewFlags ^= SCROLLBARS_VERTICAL; 16184 computeOpaqueFlags(); 16185 resolvePadding(); 16186 } 16187 } 16188 16189 /** 16190 * @hide 16191 */ 16192 protected void recomputePadding() { 16193 internalSetPadding(mUserPaddingLeft, mPaddingTop, mUserPaddingRight, mUserPaddingBottom); 16194 } 16195 16196 /** 16197 * Define whether scrollbars will fade when the view is not scrolling. 16198 * 16199 * @param fadeScrollbars whether to enable fading 16200 * 16201 * @attr ref android.R.styleable#View_fadeScrollbars 16202 */ 16203 public void setScrollbarFadingEnabled(boolean fadeScrollbars) { 16204 initScrollCache(); 16205 final ScrollabilityCache scrollabilityCache = mScrollCache; 16206 scrollabilityCache.fadeScrollBars = fadeScrollbars; 16207 if (fadeScrollbars) { 16208 scrollabilityCache.state = ScrollabilityCache.OFF; 16209 } else { 16210 scrollabilityCache.state = ScrollabilityCache.ON; 16211 } 16212 } 16213 16214 /** 16215 * 16216 * Returns true if scrollbars will fade when this view is not scrolling 16217 * 16218 * @return true if scrollbar fading is enabled 16219 * 16220 * @attr ref android.R.styleable#View_fadeScrollbars 16221 */ 16222 public boolean isScrollbarFadingEnabled() { 16223 return mScrollCache != null && mScrollCache.fadeScrollBars; 16224 } 16225 16226 /** 16227 * 16228 * Returns the delay before scrollbars fade. 16229 * 16230 * @return the delay before scrollbars fade 16231 * 16232 * @attr ref android.R.styleable#View_scrollbarDefaultDelayBeforeFade 16233 */ 16234 public int getScrollBarDefaultDelayBeforeFade() { 16235 return mScrollCache == null ? ViewConfiguration.getScrollDefaultDelay() : 16236 mScrollCache.scrollBarDefaultDelayBeforeFade; 16237 } 16238 16239 /** 16240 * Define the delay before scrollbars fade. 16241 * 16242 * @param scrollBarDefaultDelayBeforeFade - the delay before scrollbars fade 16243 * 16244 * @attr ref android.R.styleable#View_scrollbarDefaultDelayBeforeFade 16245 */ 16246 public void setScrollBarDefaultDelayBeforeFade(int scrollBarDefaultDelayBeforeFade) { 16247 getScrollCache().scrollBarDefaultDelayBeforeFade = scrollBarDefaultDelayBeforeFade; 16248 } 16249 16250 /** 16251 * 16252 * Returns the scrollbar fade duration. 16253 * 16254 * @return the scrollbar fade duration, in milliseconds 16255 * 16256 * @attr ref android.R.styleable#View_scrollbarFadeDuration 16257 */ 16258 public int getScrollBarFadeDuration() { 16259 return mScrollCache == null ? ViewConfiguration.getScrollBarFadeDuration() : 16260 mScrollCache.scrollBarFadeDuration; 16261 } 16262 16263 /** 16264 * Define the scrollbar fade duration. 16265 * 16266 * @param scrollBarFadeDuration - the scrollbar fade duration, in milliseconds 16267 * 16268 * @attr ref android.R.styleable#View_scrollbarFadeDuration 16269 */ 16270 public void setScrollBarFadeDuration(int scrollBarFadeDuration) { 16271 getScrollCache().scrollBarFadeDuration = scrollBarFadeDuration; 16272 } 16273 16274 /** 16275 * 16276 * Returns the scrollbar size. 16277 * 16278 * @return the scrollbar size 16279 * 16280 * @attr ref android.R.styleable#View_scrollbarSize 16281 */ 16282 public int getScrollBarSize() { 16283 return mScrollCache == null ? ViewConfiguration.get(mContext).getScaledScrollBarSize() : 16284 mScrollCache.scrollBarSize; 16285 } 16286 16287 /** 16288 * Define the scrollbar size. 16289 * 16290 * @param scrollBarSize - the scrollbar size 16291 * 16292 * @attr ref android.R.styleable#View_scrollbarSize 16293 */ 16294 public void setScrollBarSize(int scrollBarSize) { 16295 getScrollCache().scrollBarSize = scrollBarSize; 16296 } 16297 16298 /** 16299 * <p>Specify the style of the scrollbars. The scrollbars can be overlaid or 16300 * inset. When inset, they add to the padding of the view. And the scrollbars 16301 * can be drawn inside the padding area or on the edge of the view. For example, 16302 * if a view has a background drawable and you want to draw the scrollbars 16303 * inside the padding specified by the drawable, you can use 16304 * SCROLLBARS_INSIDE_OVERLAY or SCROLLBARS_INSIDE_INSET. If you want them to 16305 * appear at the edge of the view, ignoring the padding, then you can use 16306 * SCROLLBARS_OUTSIDE_OVERLAY or SCROLLBARS_OUTSIDE_INSET.</p> 16307 * @param style the style of the scrollbars. Should be one of 16308 * SCROLLBARS_INSIDE_OVERLAY, SCROLLBARS_INSIDE_INSET, 16309 * SCROLLBARS_OUTSIDE_OVERLAY or SCROLLBARS_OUTSIDE_INSET. 16310 * @see #SCROLLBARS_INSIDE_OVERLAY 16311 * @see #SCROLLBARS_INSIDE_INSET 16312 * @see #SCROLLBARS_OUTSIDE_OVERLAY 16313 * @see #SCROLLBARS_OUTSIDE_INSET 16314 * 16315 * @attr ref android.R.styleable#View_scrollbarStyle 16316 */ 16317 public void setScrollBarStyle(@ScrollBarStyle int style) { 16318 if (style != (mViewFlags & SCROLLBARS_STYLE_MASK)) { 16319 mViewFlags = (mViewFlags & ~SCROLLBARS_STYLE_MASK) | (style & SCROLLBARS_STYLE_MASK); 16320 computeOpaqueFlags(); 16321 resolvePadding(); 16322 } 16323 } 16324 16325 /** 16326 * <p>Returns the current scrollbar style.</p> 16327 * @return the current scrollbar style 16328 * @see #SCROLLBARS_INSIDE_OVERLAY 16329 * @see #SCROLLBARS_INSIDE_INSET 16330 * @see #SCROLLBARS_OUTSIDE_OVERLAY 16331 * @see #SCROLLBARS_OUTSIDE_INSET 16332 * 16333 * @attr ref android.R.styleable#View_scrollbarStyle 16334 */ 16335 @ViewDebug.ExportedProperty(mapping = { 16336 @ViewDebug.IntToString(from = SCROLLBARS_INSIDE_OVERLAY, to = "INSIDE_OVERLAY"), 16337 @ViewDebug.IntToString(from = SCROLLBARS_INSIDE_INSET, to = "INSIDE_INSET"), 16338 @ViewDebug.IntToString(from = SCROLLBARS_OUTSIDE_OVERLAY, to = "OUTSIDE_OVERLAY"), 16339 @ViewDebug.IntToString(from = SCROLLBARS_OUTSIDE_INSET, to = "OUTSIDE_INSET") 16340 }) 16341 @ScrollBarStyle 16342 public int getScrollBarStyle() { 16343 return mViewFlags & SCROLLBARS_STYLE_MASK; 16344 } 16345 16346 /** 16347 * <p>Compute the horizontal range that the horizontal scrollbar 16348 * represents.</p> 16349 * 16350 * <p>The range is expressed in arbitrary units that must be the same as the 16351 * units used by {@link #computeHorizontalScrollExtent()} and 16352 * {@link #computeHorizontalScrollOffset()}.</p> 16353 * 16354 * <p>The default range is the drawing width of this view.</p> 16355 * 16356 * @return the total horizontal range represented by the horizontal 16357 * scrollbar 16358 * 16359 * @see #computeHorizontalScrollExtent() 16360 * @see #computeHorizontalScrollOffset() 16361 * @see android.widget.ScrollBarDrawable 16362 */ 16363 protected int computeHorizontalScrollRange() { 16364 return getWidth(); 16365 } 16366 16367 /** 16368 * <p>Compute the horizontal offset of the horizontal scrollbar's thumb 16369 * within the horizontal range. This value is used to compute the position 16370 * of the thumb within the scrollbar's track.</p> 16371 * 16372 * <p>The range is expressed in arbitrary units that must be the same as the 16373 * units used by {@link #computeHorizontalScrollRange()} and 16374 * {@link #computeHorizontalScrollExtent()}.</p> 16375 * 16376 * <p>The default offset is the scroll offset of this view.</p> 16377 * 16378 * @return the horizontal offset of the scrollbar's thumb 16379 * 16380 * @see #computeHorizontalScrollRange() 16381 * @see #computeHorizontalScrollExtent() 16382 * @see android.widget.ScrollBarDrawable 16383 */ 16384 protected int computeHorizontalScrollOffset() { 16385 return mScrollX; 16386 } 16387 16388 /** 16389 * <p>Compute the horizontal extent of the horizontal scrollbar's thumb 16390 * within the horizontal range. This value is used to compute the length 16391 * of the thumb within the scrollbar's track.</p> 16392 * 16393 * <p>The range is expressed in arbitrary units that must be the same as the 16394 * units used by {@link #computeHorizontalScrollRange()} and 16395 * {@link #computeHorizontalScrollOffset()}.</p> 16396 * 16397 * <p>The default extent is the drawing width of this view.</p> 16398 * 16399 * @return the horizontal extent of the scrollbar's thumb 16400 * 16401 * @see #computeHorizontalScrollRange() 16402 * @see #computeHorizontalScrollOffset() 16403 * @see android.widget.ScrollBarDrawable 16404 */ 16405 protected int computeHorizontalScrollExtent() { 16406 return getWidth(); 16407 } 16408 16409 /** 16410 * <p>Compute the vertical range that the vertical scrollbar represents.</p> 16411 * 16412 * <p>The range is expressed in arbitrary units that must be the same as the 16413 * units used by {@link #computeVerticalScrollExtent()} and 16414 * {@link #computeVerticalScrollOffset()}.</p> 16415 * 16416 * @return the total vertical range represented by the vertical scrollbar 16417 * 16418 * <p>The default range is the drawing height of this view.</p> 16419 * 16420 * @see #computeVerticalScrollExtent() 16421 * @see #computeVerticalScrollOffset() 16422 * @see android.widget.ScrollBarDrawable 16423 */ 16424 protected int computeVerticalScrollRange() { 16425 return getHeight(); 16426 } 16427 16428 /** 16429 * <p>Compute the vertical offset of the vertical scrollbar's thumb 16430 * within the horizontal range. This value is used to compute the position 16431 * of the thumb within the scrollbar's track.</p> 16432 * 16433 * <p>The range is expressed in arbitrary units that must be the same as the 16434 * units used by {@link #computeVerticalScrollRange()} and 16435 * {@link #computeVerticalScrollExtent()}.</p> 16436 * 16437 * <p>The default offset is the scroll offset of this view.</p> 16438 * 16439 * @return the vertical offset of the scrollbar's thumb 16440 * 16441 * @see #computeVerticalScrollRange() 16442 * @see #computeVerticalScrollExtent() 16443 * @see android.widget.ScrollBarDrawable 16444 */ 16445 protected int computeVerticalScrollOffset() { 16446 return mScrollY; 16447 } 16448 16449 /** 16450 * <p>Compute the vertical extent of the vertical scrollbar's thumb 16451 * within the vertical range. This value is used to compute the length 16452 * of the thumb within the scrollbar's track.</p> 16453 * 16454 * <p>The range is expressed in arbitrary units that must be the same as the 16455 * units used by {@link #computeVerticalScrollRange()} and 16456 * {@link #computeVerticalScrollOffset()}.</p> 16457 * 16458 * <p>The default extent is the drawing height of this view.</p> 16459 * 16460 * @return the vertical extent of the scrollbar's thumb 16461 * 16462 * @see #computeVerticalScrollRange() 16463 * @see #computeVerticalScrollOffset() 16464 * @see android.widget.ScrollBarDrawable 16465 */ 16466 protected int computeVerticalScrollExtent() { 16467 return getHeight(); 16468 } 16469 16470 /** 16471 * Check if this view can be scrolled horizontally in a certain direction. 16472 * 16473 * @param direction Negative to check scrolling left, positive to check scrolling right. 16474 * @return true if this view can be scrolled in the specified direction, false otherwise. 16475 */ 16476 public boolean canScrollHorizontally(int direction) { 16477 final int offset = computeHorizontalScrollOffset(); 16478 final int range = computeHorizontalScrollRange() - computeHorizontalScrollExtent(); 16479 if (range == 0) return false; 16480 if (direction < 0) { 16481 return offset > 0; 16482 } else { 16483 return offset < range - 1; 16484 } 16485 } 16486 16487 /** 16488 * Check if this view can be scrolled vertically in a certain direction. 16489 * 16490 * @param direction Negative to check scrolling up, positive to check scrolling down. 16491 * @return true if this view can be scrolled in the specified direction, false otherwise. 16492 */ 16493 public boolean canScrollVertically(int direction) { 16494 final int offset = computeVerticalScrollOffset(); 16495 final int range = computeVerticalScrollRange() - computeVerticalScrollExtent(); 16496 if (range == 0) return false; 16497 if (direction < 0) { 16498 return offset > 0; 16499 } else { 16500 return offset < range - 1; 16501 } 16502 } 16503 16504 void getScrollIndicatorBounds(@NonNull Rect out) { 16505 out.left = mScrollX; 16506 out.right = mScrollX + mRight - mLeft; 16507 out.top = mScrollY; 16508 out.bottom = mScrollY + mBottom - mTop; 16509 } 16510 16511 private void onDrawScrollIndicators(Canvas c) { 16512 if ((mPrivateFlags3 & SCROLL_INDICATORS_PFLAG3_MASK) == 0) { 16513 // No scroll indicators enabled. 16514 return; 16515 } 16516 16517 final Drawable dr = mScrollIndicatorDrawable; 16518 if (dr == null) { 16519 // Scroll indicators aren't supported here. 16520 return; 16521 } 16522 16523 final int h = dr.getIntrinsicHeight(); 16524 final int w = dr.getIntrinsicWidth(); 16525 final Rect rect = mAttachInfo.mTmpInvalRect; 16526 getScrollIndicatorBounds(rect); 16527 16528 if ((mPrivateFlags3 & PFLAG3_SCROLL_INDICATOR_TOP) != 0) { 16529 final boolean canScrollUp = canScrollVertically(-1); 16530 if (canScrollUp) { 16531 dr.setBounds(rect.left, rect.top, rect.right, rect.top + h); 16532 dr.draw(c); 16533 } 16534 } 16535 16536 if ((mPrivateFlags3 & PFLAG3_SCROLL_INDICATOR_BOTTOM) != 0) { 16537 final boolean canScrollDown = canScrollVertically(1); 16538 if (canScrollDown) { 16539 dr.setBounds(rect.left, rect.bottom - h, rect.right, rect.bottom); 16540 dr.draw(c); 16541 } 16542 } 16543 16544 final int leftRtl; 16545 final int rightRtl; 16546 if (getLayoutDirection() == LAYOUT_DIRECTION_RTL) { 16547 leftRtl = PFLAG3_SCROLL_INDICATOR_END; 16548 rightRtl = PFLAG3_SCROLL_INDICATOR_START; 16549 } else { 16550 leftRtl = PFLAG3_SCROLL_INDICATOR_START; 16551 rightRtl = PFLAG3_SCROLL_INDICATOR_END; 16552 } 16553 16554 final int leftMask = PFLAG3_SCROLL_INDICATOR_LEFT | leftRtl; 16555 if ((mPrivateFlags3 & leftMask) != 0) { 16556 final boolean canScrollLeft = canScrollHorizontally(-1); 16557 if (canScrollLeft) { 16558 dr.setBounds(rect.left, rect.top, rect.left + w, rect.bottom); 16559 dr.draw(c); 16560 } 16561 } 16562 16563 final int rightMask = PFLAG3_SCROLL_INDICATOR_RIGHT | rightRtl; 16564 if ((mPrivateFlags3 & rightMask) != 0) { 16565 final boolean canScrollRight = canScrollHorizontally(1); 16566 if (canScrollRight) { 16567 dr.setBounds(rect.right - w, rect.top, rect.right, rect.bottom); 16568 dr.draw(c); 16569 } 16570 } 16571 } 16572 16573 private void getHorizontalScrollBarBounds(@Nullable Rect drawBounds, 16574 @Nullable Rect touchBounds) { 16575 final Rect bounds = drawBounds != null ? drawBounds : touchBounds; 16576 if (bounds == null) { 16577 return; 16578 } 16579 final int inside = (mViewFlags & SCROLLBARS_OUTSIDE_MASK) == 0 ? ~0 : 0; 16580 final boolean drawVerticalScrollBar = isVerticalScrollBarEnabled() 16581 && !isVerticalScrollBarHidden(); 16582 final int size = getHorizontalScrollbarHeight(); 16583 final int verticalScrollBarGap = drawVerticalScrollBar ? 16584 getVerticalScrollbarWidth() : 0; 16585 final int width = mRight - mLeft; 16586 final int height = mBottom - mTop; 16587 bounds.top = mScrollY + height - size - (mUserPaddingBottom & inside); 16588 bounds.left = mScrollX + (mPaddingLeft & inside); 16589 bounds.right = mScrollX + width - (mUserPaddingRight & inside) - verticalScrollBarGap; 16590 bounds.bottom = bounds.top + size; 16591 16592 if (touchBounds == null) { 16593 return; 16594 } 16595 if (touchBounds != bounds) { 16596 touchBounds.set(bounds); 16597 } 16598 final int minTouchTarget = mScrollCache.scrollBarMinTouchTarget; 16599 if (touchBounds.height() < minTouchTarget) { 16600 final int adjust = (minTouchTarget - touchBounds.height()) / 2; 16601 touchBounds.bottom = Math.min(touchBounds.bottom + adjust, mScrollY + height); 16602 touchBounds.top = touchBounds.bottom - minTouchTarget; 16603 } 16604 if (touchBounds.width() < minTouchTarget) { 16605 final int adjust = (minTouchTarget - touchBounds.width()) / 2; 16606 touchBounds.left -= adjust; 16607 touchBounds.right = touchBounds.left + minTouchTarget; 16608 } 16609 } 16610 16611 private void getVerticalScrollBarBounds(@Nullable Rect bounds, @Nullable Rect touchBounds) { 16612 if (mRoundScrollbarRenderer == null) { 16613 getStraightVerticalScrollBarBounds(bounds, touchBounds); 16614 } else { 16615 getRoundVerticalScrollBarBounds(bounds != null ? bounds : touchBounds); 16616 } 16617 } 16618 16619 private void getRoundVerticalScrollBarBounds(Rect bounds) { 16620 final int width = mRight - mLeft; 16621 final int height = mBottom - mTop; 16622 // Do not take padding into account as we always want the scrollbars 16623 // to hug the screen for round wearable devices. 16624 bounds.left = mScrollX; 16625 bounds.top = mScrollY; 16626 bounds.right = bounds.left + width; 16627 bounds.bottom = mScrollY + height; 16628 } 16629 16630 private void getStraightVerticalScrollBarBounds(@Nullable Rect drawBounds, 16631 @Nullable Rect touchBounds) { 16632 final Rect bounds = drawBounds != null ? drawBounds : touchBounds; 16633 if (bounds == null) { 16634 return; 16635 } 16636 final int inside = (mViewFlags & SCROLLBARS_OUTSIDE_MASK) == 0 ? ~0 : 0; 16637 final int size = getVerticalScrollbarWidth(); 16638 int verticalScrollbarPosition = mVerticalScrollbarPosition; 16639 if (verticalScrollbarPosition == SCROLLBAR_POSITION_DEFAULT) { 16640 verticalScrollbarPosition = isLayoutRtl() ? 16641 SCROLLBAR_POSITION_LEFT : SCROLLBAR_POSITION_RIGHT; 16642 } 16643 final int width = mRight - mLeft; 16644 final int height = mBottom - mTop; 16645 switch (verticalScrollbarPosition) { 16646 default: 16647 case SCROLLBAR_POSITION_RIGHT: 16648 bounds.left = mScrollX + width - size - (mUserPaddingRight & inside); 16649 break; 16650 case SCROLLBAR_POSITION_LEFT: 16651 bounds.left = mScrollX + (mUserPaddingLeft & inside); 16652 break; 16653 } 16654 bounds.top = mScrollY + (mPaddingTop & inside); 16655 bounds.right = bounds.left + size; 16656 bounds.bottom = mScrollY + height - (mUserPaddingBottom & inside); 16657 16658 if (touchBounds == null) { 16659 return; 16660 } 16661 if (touchBounds != bounds) { 16662 touchBounds.set(bounds); 16663 } 16664 final int minTouchTarget = mScrollCache.scrollBarMinTouchTarget; 16665 if (touchBounds.width() < minTouchTarget) { 16666 final int adjust = (minTouchTarget - touchBounds.width()) / 2; 16667 if (verticalScrollbarPosition == SCROLLBAR_POSITION_RIGHT) { 16668 touchBounds.right = Math.min(touchBounds.right + adjust, mScrollX + width); 16669 touchBounds.left = touchBounds.right - minTouchTarget; 16670 } else { 16671 touchBounds.left = Math.max(touchBounds.left + adjust, mScrollX); 16672 touchBounds.right = touchBounds.left + minTouchTarget; 16673 } 16674 } 16675 if (touchBounds.height() < minTouchTarget) { 16676 final int adjust = (minTouchTarget - touchBounds.height()) / 2; 16677 touchBounds.top -= adjust; 16678 touchBounds.bottom = touchBounds.top + minTouchTarget; 16679 } 16680 } 16681 16682 /** 16683 * <p>Request the drawing of the horizontal and the vertical scrollbar. The 16684 * scrollbars are painted only if they have been awakened first.</p> 16685 * 16686 * @param canvas the canvas on which to draw the scrollbars 16687 * 16688 * @see #awakenScrollBars(int) 16689 */ 16690 protected final void onDrawScrollBars(Canvas canvas) { 16691 // scrollbars are drawn only when the animation is running 16692 final ScrollabilityCache cache = mScrollCache; 16693 16694 if (cache != null) { 16695 16696 int state = cache.state; 16697 16698 if (state == ScrollabilityCache.OFF) { 16699 return; 16700 } 16701 16702 boolean invalidate = false; 16703 16704 if (state == ScrollabilityCache.FADING) { 16705 // We're fading -- get our fade interpolation 16706 if (cache.interpolatorValues == null) { 16707 cache.interpolatorValues = new float[1]; 16708 } 16709 16710 float[] values = cache.interpolatorValues; 16711 16712 // Stops the animation if we're done 16713 if (cache.scrollBarInterpolator.timeToValues(values) == 16714 Interpolator.Result.FREEZE_END) { 16715 cache.state = ScrollabilityCache.OFF; 16716 } else { 16717 cache.scrollBar.mutate().setAlpha(Math.round(values[0])); 16718 } 16719 16720 // This will make the scroll bars inval themselves after 16721 // drawing. We only want this when we're fading so that 16722 // we prevent excessive redraws 16723 invalidate = true; 16724 } else { 16725 // We're just on -- but we may have been fading before so 16726 // reset alpha 16727 cache.scrollBar.mutate().setAlpha(255); 16728 } 16729 16730 final boolean drawHorizontalScrollBar = isHorizontalScrollBarEnabled(); 16731 final boolean drawVerticalScrollBar = isVerticalScrollBarEnabled() 16732 && !isVerticalScrollBarHidden(); 16733 16734 // Fork out the scroll bar drawing for round wearable devices. 16735 if (mRoundScrollbarRenderer != null) { 16736 if (drawVerticalScrollBar) { 16737 final Rect bounds = cache.mScrollBarBounds; 16738 getVerticalScrollBarBounds(bounds, null); 16739 mRoundScrollbarRenderer.drawRoundScrollbars( 16740 canvas, (float) cache.scrollBar.getAlpha() / 255f, bounds); 16741 if (invalidate) { 16742 invalidate(); 16743 } 16744 } 16745 // Do not draw horizontal scroll bars for round wearable devices. 16746 } else if (drawVerticalScrollBar || drawHorizontalScrollBar) { 16747 final ScrollBarDrawable scrollBar = cache.scrollBar; 16748 16749 if (drawHorizontalScrollBar) { 16750 scrollBar.setParameters(computeHorizontalScrollRange(), 16751 computeHorizontalScrollOffset(), 16752 computeHorizontalScrollExtent(), false); 16753 final Rect bounds = cache.mScrollBarBounds; 16754 getHorizontalScrollBarBounds(bounds, null); 16755 onDrawHorizontalScrollBar(canvas, scrollBar, bounds.left, bounds.top, 16756 bounds.right, bounds.bottom); 16757 if (invalidate) { 16758 invalidate(bounds); 16759 } 16760 } 16761 16762 if (drawVerticalScrollBar) { 16763 scrollBar.setParameters(computeVerticalScrollRange(), 16764 computeVerticalScrollOffset(), 16765 computeVerticalScrollExtent(), true); 16766 final Rect bounds = cache.mScrollBarBounds; 16767 getVerticalScrollBarBounds(bounds, null); 16768 onDrawVerticalScrollBar(canvas, scrollBar, bounds.left, bounds.top, 16769 bounds.right, bounds.bottom); 16770 if (invalidate) { 16771 invalidate(bounds); 16772 } 16773 } 16774 } 16775 } 16776 } 16777 16778 /** 16779 * Override this if the vertical scrollbar needs to be hidden in a subclass, like when 16780 * FastScroller is visible. 16781 * @return whether to temporarily hide the vertical scrollbar 16782 * @hide 16783 */ 16784 protected boolean isVerticalScrollBarHidden() { 16785 return false; 16786 } 16787 16788 /** 16789 * <p>Draw the horizontal scrollbar if 16790 * {@link #isHorizontalScrollBarEnabled()} returns true.</p> 16791 * 16792 * @param canvas the canvas on which to draw the scrollbar 16793 * @param scrollBar the scrollbar's drawable 16794 * 16795 * @see #isHorizontalScrollBarEnabled() 16796 * @see #computeHorizontalScrollRange() 16797 * @see #computeHorizontalScrollExtent() 16798 * @see #computeHorizontalScrollOffset() 16799 * @see android.widget.ScrollBarDrawable 16800 * @hide 16801 */ 16802 protected void onDrawHorizontalScrollBar(Canvas canvas, Drawable scrollBar, 16803 int l, int t, int r, int b) { 16804 scrollBar.setBounds(l, t, r, b); 16805 scrollBar.draw(canvas); 16806 } 16807 16808 /** 16809 * <p>Draw the vertical scrollbar if {@link #isVerticalScrollBarEnabled()} 16810 * returns true.</p> 16811 * 16812 * @param canvas the canvas on which to draw the scrollbar 16813 * @param scrollBar the scrollbar's drawable 16814 * 16815 * @see #isVerticalScrollBarEnabled() 16816 * @see #computeVerticalScrollRange() 16817 * @see #computeVerticalScrollExtent() 16818 * @see #computeVerticalScrollOffset() 16819 * @see android.widget.ScrollBarDrawable 16820 * @hide 16821 */ 16822 protected void onDrawVerticalScrollBar(Canvas canvas, Drawable scrollBar, 16823 int l, int t, int r, int b) { 16824 scrollBar.setBounds(l, t, r, b); 16825 scrollBar.draw(canvas); 16826 } 16827 16828 /** 16829 * Implement this to do your drawing. 16830 * 16831 * @param canvas the canvas on which the background will be drawn 16832 */ 16833 protected void onDraw(Canvas canvas) { 16834 } 16835 16836 /* 16837 * Caller is responsible for calling requestLayout if necessary. 16838 * (This allows addViewInLayout to not request a new layout.) 16839 */ 16840 void assignParent(ViewParent parent) { 16841 if (mParent == null) { 16842 mParent = parent; 16843 } else if (parent == null) { 16844 mParent = null; 16845 } else { 16846 throw new RuntimeException("view " + this + " being added, but" 16847 + " it already has a parent"); 16848 } 16849 } 16850 16851 /** 16852 * This is called when the view is attached to a window. At this point it 16853 * has a Surface and will start drawing. Note that this function is 16854 * guaranteed to be called before {@link #onDraw(android.graphics.Canvas)}, 16855 * however it may be called any time before the first onDraw -- including 16856 * before or after {@link #onMeasure(int, int)}. 16857 * 16858 * @see #onDetachedFromWindow() 16859 */ 16860 @CallSuper 16861 protected void onAttachedToWindow() { 16862 if ((mPrivateFlags & PFLAG_REQUEST_TRANSPARENT_REGIONS) != 0) { 16863 mParent.requestTransparentRegion(this); 16864 } 16865 16866 mPrivateFlags3 &= ~PFLAG3_IS_LAID_OUT; 16867 16868 jumpDrawablesToCurrentState(); 16869 16870 resetSubtreeAccessibilityStateChanged(); 16871 16872 // rebuild, since Outline not maintained while View is detached 16873 rebuildOutline(); 16874 16875 if (isFocused()) { 16876 InputMethodManager imm = InputMethodManager.peekInstance(); 16877 if (imm != null) { 16878 imm.focusIn(this); 16879 } 16880 } 16881 } 16882 16883 /** 16884 * Resolve all RTL related properties. 16885 * 16886 * @return true if resolution of RTL properties has been done 16887 * 16888 * @hide 16889 */ 16890 public boolean resolveRtlPropertiesIfNeeded() { 16891 if (!needRtlPropertiesResolution()) return false; 16892 16893 // Order is important here: LayoutDirection MUST be resolved first 16894 if (!isLayoutDirectionResolved()) { 16895 resolveLayoutDirection(); 16896 resolveLayoutParams(); 16897 } 16898 // ... then we can resolve the others properties depending on the resolved LayoutDirection. 16899 if (!isTextDirectionResolved()) { 16900 resolveTextDirection(); 16901 } 16902 if (!isTextAlignmentResolved()) { 16903 resolveTextAlignment(); 16904 } 16905 // Should resolve Drawables before Padding because we need the layout direction of the 16906 // Drawable to correctly resolve Padding. 16907 if (!areDrawablesResolved()) { 16908 resolveDrawables(); 16909 } 16910 if (!isPaddingResolved()) { 16911 resolvePadding(); 16912 } 16913 onRtlPropertiesChanged(getLayoutDirection()); 16914 return true; 16915 } 16916 16917 /** 16918 * Reset resolution of all RTL related properties. 16919 * 16920 * @hide 16921 */ 16922 public void resetRtlProperties() { 16923 resetResolvedLayoutDirection(); 16924 resetResolvedTextDirection(); 16925 resetResolvedTextAlignment(); 16926 resetResolvedPadding(); 16927 resetResolvedDrawables(); 16928 } 16929 16930 /** 16931 * @see #onScreenStateChanged(int) 16932 */ 16933 void dispatchScreenStateChanged(int screenState) { 16934 onScreenStateChanged(screenState); 16935 } 16936 16937 /** 16938 * This method is called whenever the state of the screen this view is 16939 * attached to changes. A state change will usually occurs when the screen 16940 * turns on or off (whether it happens automatically or the user does it 16941 * manually.) 16942 * 16943 * @param screenState The new state of the screen. Can be either 16944 * {@link #SCREEN_STATE_ON} or {@link #SCREEN_STATE_OFF} 16945 */ 16946 public void onScreenStateChanged(int screenState) { 16947 } 16948 16949 /** 16950 * @see #onMovedToDisplay(int, Configuration) 16951 */ 16952 void dispatchMovedToDisplay(Display display, Configuration config) { 16953 mAttachInfo.mDisplay = display; 16954 mAttachInfo.mDisplayState = display.getState(); 16955 onMovedToDisplay(display.getDisplayId(), config); 16956 } 16957 16958 /** 16959 * Called by the system when the hosting activity is moved from one display to another without 16960 * recreation. This means that the activity is declared to handle all changes to configuration 16961 * that happened when it was switched to another display, so it wasn't destroyed and created 16962 * again. 16963 * 16964 * <p>This call will be followed by {@link #onConfigurationChanged(Configuration)} if the 16965 * applied configuration actually changed. It is up to app developer to choose whether to handle 16966 * the change in this method or in the following {@link #onConfigurationChanged(Configuration)} 16967 * call. 16968 * 16969 * <p>Use this callback to track changes to the displays if some functionality relies on an 16970 * association with some display properties. 16971 * 16972 * @param displayId The id of the display to which the view was moved. 16973 * @param config Configuration of the resources on new display after move. 16974 * 16975 * @see #onConfigurationChanged(Configuration) 16976 * @hide 16977 */ 16978 public void onMovedToDisplay(int displayId, Configuration config) { 16979 } 16980 16981 /** 16982 * Return true if the application tag in the AndroidManifest has set "supportRtl" to true 16983 */ 16984 private boolean hasRtlSupport() { 16985 return mContext.getApplicationInfo().hasRtlSupport(); 16986 } 16987 16988 /** 16989 * Return true if we are in RTL compatibility mode (either before Jelly Bean MR1 or 16990 * RTL not supported) 16991 */ 16992 private boolean isRtlCompatibilityMode() { 16993 final int targetSdkVersion = getContext().getApplicationInfo().targetSdkVersion; 16994 return targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR1 || !hasRtlSupport(); 16995 } 16996 16997 /** 16998 * @return true if RTL properties need resolution. 16999 * 17000 */ 17001 private boolean needRtlPropertiesResolution() { 17002 return (mPrivateFlags2 & ALL_RTL_PROPERTIES_RESOLVED) != ALL_RTL_PROPERTIES_RESOLVED; 17003 } 17004 17005 /** 17006 * Called when any RTL property (layout direction or text direction or text alignment) has 17007 * been changed. 17008 * 17009 * Subclasses need to override this method to take care of cached information that depends on the 17010 * resolved layout direction, or to inform child views that inherit their layout direction. 17011 * 17012 * The default implementation does nothing. 17013 * 17014 * @param layoutDirection the direction of the layout 17015 * 17016 * @see #LAYOUT_DIRECTION_LTR 17017 * @see #LAYOUT_DIRECTION_RTL 17018 */ 17019 public void onRtlPropertiesChanged(@ResolvedLayoutDir int layoutDirection) { 17020 } 17021 17022 /** 17023 * Resolve and cache the layout direction. LTR is set initially. This is implicitly supposing 17024 * that the parent directionality can and will be resolved before its children. 17025 * 17026 * @return true if resolution has been done, false otherwise. 17027 * 17028 * @hide 17029 */ 17030 public boolean resolveLayoutDirection() { 17031 // Clear any previous layout direction resolution 17032 mPrivateFlags2 &= ~PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK; 17033 17034 if (hasRtlSupport()) { 17035 // Set resolved depending on layout direction 17036 switch ((mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_MASK) >> 17037 PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT) { 17038 case LAYOUT_DIRECTION_INHERIT: 17039 // We cannot resolve yet. LTR is by default and let the resolution happen again 17040 // later to get the correct resolved value 17041 if (!canResolveLayoutDirection()) return false; 17042 17043 // Parent has not yet resolved, LTR is still the default 17044 try { 17045 if (!mParent.isLayoutDirectionResolved()) return false; 17046 17047 if (mParent.getLayoutDirection() == LAYOUT_DIRECTION_RTL) { 17048 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL; 17049 } 17050 } catch (AbstractMethodError e) { 17051 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 17052 " does not fully implement ViewParent", e); 17053 } 17054 break; 17055 case LAYOUT_DIRECTION_RTL: 17056 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL; 17057 break; 17058 case LAYOUT_DIRECTION_LOCALE: 17059 if((LAYOUT_DIRECTION_RTL == 17060 TextUtils.getLayoutDirectionFromLocale(Locale.getDefault()))) { 17061 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL; 17062 } 17063 break; 17064 default: 17065 // Nothing to do, LTR by default 17066 } 17067 } 17068 17069 // Set to resolved 17070 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED; 17071 return true; 17072 } 17073 17074 /** 17075 * Check if layout direction resolution can be done. 17076 * 17077 * @return true if layout direction resolution can be done otherwise return false. 17078 */ 17079 public boolean canResolveLayoutDirection() { 17080 switch (getRawLayoutDirection()) { 17081 case LAYOUT_DIRECTION_INHERIT: 17082 if (mParent != null) { 17083 try { 17084 return mParent.canResolveLayoutDirection(); 17085 } catch (AbstractMethodError e) { 17086 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 17087 " does not fully implement ViewParent", e); 17088 } 17089 } 17090 return false; 17091 17092 default: 17093 return true; 17094 } 17095 } 17096 17097 /** 17098 * Reset the resolved layout direction. Layout direction will be resolved during a call to 17099 * {@link #onMeasure(int, int)}. 17100 * 17101 * @hide 17102 */ 17103 public void resetResolvedLayoutDirection() { 17104 // Reset the current resolved bits 17105 mPrivateFlags2 &= ~PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK; 17106 } 17107 17108 /** 17109 * @return true if the layout direction is inherited. 17110 * 17111 * @hide 17112 */ 17113 public boolean isLayoutDirectionInherited() { 17114 return (getRawLayoutDirection() == LAYOUT_DIRECTION_INHERIT); 17115 } 17116 17117 /** 17118 * @return true if layout direction has been resolved. 17119 */ 17120 public boolean isLayoutDirectionResolved() { 17121 return (mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_RESOLVED) == PFLAG2_LAYOUT_DIRECTION_RESOLVED; 17122 } 17123 17124 /** 17125 * Return if padding has been resolved 17126 * 17127 * @hide 17128 */ 17129 boolean isPaddingResolved() { 17130 return (mPrivateFlags2 & PFLAG2_PADDING_RESOLVED) == PFLAG2_PADDING_RESOLVED; 17131 } 17132 17133 /** 17134 * Resolves padding depending on layout direction, if applicable, and 17135 * recomputes internal padding values to adjust for scroll bars. 17136 * 17137 * @hide 17138 */ 17139 public void resolvePadding() { 17140 final int resolvedLayoutDirection = getLayoutDirection(); 17141 17142 if (!isRtlCompatibilityMode()) { 17143 // Post Jelly Bean MR1 case: we need to take the resolved layout direction into account. 17144 // If start / end padding are defined, they will be resolved (hence overriding) to 17145 // left / right or right / left depending on the resolved layout direction. 17146 // If start / end padding are not defined, use the left / right ones. 17147 if (mBackground != null && (!mLeftPaddingDefined || !mRightPaddingDefined)) { 17148 Rect padding = sThreadLocal.get(); 17149 if (padding == null) { 17150 padding = new Rect(); 17151 sThreadLocal.set(padding); 17152 } 17153 mBackground.getPadding(padding); 17154 if (!mLeftPaddingDefined) { 17155 mUserPaddingLeftInitial = padding.left; 17156 } 17157 if (!mRightPaddingDefined) { 17158 mUserPaddingRightInitial = padding.right; 17159 } 17160 } 17161 switch (resolvedLayoutDirection) { 17162 case LAYOUT_DIRECTION_RTL: 17163 if (mUserPaddingStart != UNDEFINED_PADDING) { 17164 mUserPaddingRight = mUserPaddingStart; 17165 } else { 17166 mUserPaddingRight = mUserPaddingRightInitial; 17167 } 17168 if (mUserPaddingEnd != UNDEFINED_PADDING) { 17169 mUserPaddingLeft = mUserPaddingEnd; 17170 } else { 17171 mUserPaddingLeft = mUserPaddingLeftInitial; 17172 } 17173 break; 17174 case LAYOUT_DIRECTION_LTR: 17175 default: 17176 if (mUserPaddingStart != UNDEFINED_PADDING) { 17177 mUserPaddingLeft = mUserPaddingStart; 17178 } else { 17179 mUserPaddingLeft = mUserPaddingLeftInitial; 17180 } 17181 if (mUserPaddingEnd != UNDEFINED_PADDING) { 17182 mUserPaddingRight = mUserPaddingEnd; 17183 } else { 17184 mUserPaddingRight = mUserPaddingRightInitial; 17185 } 17186 } 17187 17188 mUserPaddingBottom = (mUserPaddingBottom >= 0) ? mUserPaddingBottom : mPaddingBottom; 17189 } 17190 17191 internalSetPadding(mUserPaddingLeft, mPaddingTop, mUserPaddingRight, mUserPaddingBottom); 17192 onRtlPropertiesChanged(resolvedLayoutDirection); 17193 17194 mPrivateFlags2 |= PFLAG2_PADDING_RESOLVED; 17195 } 17196 17197 /** 17198 * Reset the resolved layout direction. 17199 * 17200 * @hide 17201 */ 17202 public void resetResolvedPadding() { 17203 resetResolvedPaddingInternal(); 17204 } 17205 17206 /** 17207 * Used when we only want to reset *this* view's padding and not trigger overrides 17208 * in ViewGroup that reset children too. 17209 */ 17210 void resetResolvedPaddingInternal() { 17211 mPrivateFlags2 &= ~PFLAG2_PADDING_RESOLVED; 17212 } 17213 17214 /** 17215 * This is called when the view is detached from a window. At this point it 17216 * no longer has a surface for drawing. 17217 * 17218 * @see #onAttachedToWindow() 17219 */ 17220 @CallSuper 17221 protected void onDetachedFromWindow() { 17222 } 17223 17224 /** 17225 * This is a framework-internal mirror of onDetachedFromWindow() that's called 17226 * after onDetachedFromWindow(). 17227 * 17228 * If you override this you *MUST* call super.onDetachedFromWindowInternal()! 17229 * The super method should be called at the end of the overridden method to ensure 17230 * subclasses are destroyed first 17231 * 17232 * @hide 17233 */ 17234 @CallSuper 17235 protected void onDetachedFromWindowInternal() { 17236 mPrivateFlags &= ~PFLAG_CANCEL_NEXT_UP_EVENT; 17237 mPrivateFlags3 &= ~PFLAG3_IS_LAID_OUT; 17238 mPrivateFlags3 &= ~PFLAG3_TEMPORARY_DETACH; 17239 17240 removeUnsetPressCallback(); 17241 removeLongPressCallback(); 17242 removePerformClickCallback(); 17243 removeSendViewScrolledAccessibilityEventCallback(); 17244 stopNestedScroll(); 17245 17246 // Anything that started animating right before detach should already 17247 // be in its final state when re-attached. 17248 jumpDrawablesToCurrentState(); 17249 17250 destroyDrawingCache(); 17251 17252 cleanupDraw(); 17253 mCurrentAnimation = null; 17254 17255 if ((mViewFlags & TOOLTIP) == TOOLTIP) { 17256 hideTooltip(); 17257 } 17258 } 17259 17260 private void cleanupDraw() { 17261 resetDisplayList(); 17262 if (mAttachInfo != null) { 17263 mAttachInfo.mViewRootImpl.cancelInvalidate(this); 17264 } 17265 } 17266 17267 void invalidateInheritedLayoutMode(int layoutModeOfRoot) { 17268 } 17269 17270 /** 17271 * @return The number of times this view has been attached to a window 17272 */ 17273 protected int getWindowAttachCount() { 17274 return mWindowAttachCount; 17275 } 17276 17277 /** 17278 * Retrieve a unique token identifying the window this view is attached to. 17279 * @return Return the window's token for use in 17280 * {@link WindowManager.LayoutParams#token WindowManager.LayoutParams.token}. 17281 */ 17282 public IBinder getWindowToken() { 17283 return mAttachInfo != null ? mAttachInfo.mWindowToken : null; 17284 } 17285 17286 /** 17287 * Retrieve the {@link WindowId} for the window this view is 17288 * currently attached to. 17289 */ 17290 public WindowId getWindowId() { 17291 if (mAttachInfo == null) { 17292 return null; 17293 } 17294 if (mAttachInfo.mWindowId == null) { 17295 try { 17296 mAttachInfo.mIWindowId = mAttachInfo.mSession.getWindowId( 17297 mAttachInfo.mWindowToken); 17298 mAttachInfo.mWindowId = new WindowId( 17299 mAttachInfo.mIWindowId); 17300 } catch (RemoteException e) { 17301 } 17302 } 17303 return mAttachInfo.mWindowId; 17304 } 17305 17306 /** 17307 * Retrieve a unique token identifying the top-level "real" window of 17308 * the window that this view is attached to. That is, this is like 17309 * {@link #getWindowToken}, except if the window this view in is a panel 17310 * window (attached to another containing window), then the token of 17311 * the containing window is returned instead. 17312 * 17313 * @return Returns the associated window token, either 17314 * {@link #getWindowToken()} or the containing window's token. 17315 */ 17316 public IBinder getApplicationWindowToken() { 17317 AttachInfo ai = mAttachInfo; 17318 if (ai != null) { 17319 IBinder appWindowToken = ai.mPanelParentWindowToken; 17320 if (appWindowToken == null) { 17321 appWindowToken = ai.mWindowToken; 17322 } 17323 return appWindowToken; 17324 } 17325 return null; 17326 } 17327 17328 /** 17329 * Gets the logical display to which the view's window has been attached. 17330 * 17331 * @return The logical display, or null if the view is not currently attached to a window. 17332 */ 17333 public Display getDisplay() { 17334 return mAttachInfo != null ? mAttachInfo.mDisplay : null; 17335 } 17336 17337 /** 17338 * Retrieve private session object this view hierarchy is using to 17339 * communicate with the window manager. 17340 * @return the session object to communicate with the window manager 17341 */ 17342 /*package*/ IWindowSession getWindowSession() { 17343 return mAttachInfo != null ? mAttachInfo.mSession : null; 17344 } 17345 17346 /** 17347 * Return the visibility value of the least visible component passed. 17348 */ 17349 int combineVisibility(int vis1, int vis2) { 17350 // This works because VISIBLE < INVISIBLE < GONE. 17351 return Math.max(vis1, vis2); 17352 } 17353 17354 /** 17355 * @param info the {@link android.view.View.AttachInfo} to associated with 17356 * this view 17357 */ 17358 void dispatchAttachedToWindow(AttachInfo info, int visibility) { 17359 mAttachInfo = info; 17360 if (mOverlay != null) { 17361 mOverlay.getOverlayView().dispatchAttachedToWindow(info, visibility); 17362 } 17363 mWindowAttachCount++; 17364 // We will need to evaluate the drawable state at least once. 17365 mPrivateFlags |= PFLAG_DRAWABLE_STATE_DIRTY; 17366 if (mFloatingTreeObserver != null) { 17367 info.mTreeObserver.merge(mFloatingTreeObserver); 17368 mFloatingTreeObserver = null; 17369 } 17370 17371 registerPendingFrameMetricsObservers(); 17372 17373 if ((mPrivateFlags&PFLAG_SCROLL_CONTAINER) != 0) { 17374 mAttachInfo.mScrollContainers.add(this); 17375 mPrivateFlags |= PFLAG_SCROLL_CONTAINER_ADDED; 17376 } 17377 // Transfer all pending runnables. 17378 if (mRunQueue != null) { 17379 mRunQueue.executeActions(info.mHandler); 17380 mRunQueue = null; 17381 } 17382 performCollectViewAttributes(mAttachInfo, visibility); 17383 onAttachedToWindow(); 17384 17385 ListenerInfo li = mListenerInfo; 17386 final CopyOnWriteArrayList<OnAttachStateChangeListener> listeners = 17387 li != null ? li.mOnAttachStateChangeListeners : null; 17388 if (listeners != null && listeners.size() > 0) { 17389 // NOTE: because of the use of CopyOnWriteArrayList, we *must* use an iterator to 17390 // perform the dispatching. The iterator is a safe guard against listeners that 17391 // could mutate the list by calling the various add/remove methods. This prevents 17392 // the array from being modified while we iterate it. 17393 for (OnAttachStateChangeListener listener : listeners) { 17394 listener.onViewAttachedToWindow(this); 17395 } 17396 } 17397 17398 int vis = info.mWindowVisibility; 17399 if (vis != GONE) { 17400 onWindowVisibilityChanged(vis); 17401 if (isShown()) { 17402 // Calling onVisibilityAggregated directly here since the subtree will also 17403 // receive dispatchAttachedToWindow and this same call 17404 onVisibilityAggregated(vis == VISIBLE); 17405 } 17406 } 17407 17408 // Send onVisibilityChanged directly instead of dispatchVisibilityChanged. 17409 // As all views in the subtree will already receive dispatchAttachedToWindow 17410 // traversing the subtree again here is not desired. 17411 onVisibilityChanged(this, visibility); 17412 17413 if ((mPrivateFlags&PFLAG_DRAWABLE_STATE_DIRTY) != 0) { 17414 // If nobody has evaluated the drawable state yet, then do it now. 17415 refreshDrawableState(); 17416 } 17417 needGlobalAttributesUpdate(false); 17418 17419 notifyEnterOrExitForAutoFillIfNeeded(true); 17420 } 17421 17422 void dispatchDetachedFromWindow() { 17423 AttachInfo info = mAttachInfo; 17424 if (info != null) { 17425 int vis = info.mWindowVisibility; 17426 if (vis != GONE) { 17427 onWindowVisibilityChanged(GONE); 17428 if (isShown()) { 17429 // Invoking onVisibilityAggregated directly here since the subtree 17430 // will also receive detached from window 17431 onVisibilityAggregated(false); 17432 } 17433 } 17434 } 17435 17436 onDetachedFromWindow(); 17437 onDetachedFromWindowInternal(); 17438 17439 InputMethodManager imm = InputMethodManager.peekInstance(); 17440 if (imm != null) { 17441 imm.onViewDetachedFromWindow(this); 17442 } 17443 17444 ListenerInfo li = mListenerInfo; 17445 final CopyOnWriteArrayList<OnAttachStateChangeListener> listeners = 17446 li != null ? li.mOnAttachStateChangeListeners : null; 17447 if (listeners != null && listeners.size() > 0) { 17448 // NOTE: because of the use of CopyOnWriteArrayList, we *must* use an iterator to 17449 // perform the dispatching. The iterator is a safe guard against listeners that 17450 // could mutate the list by calling the various add/remove methods. This prevents 17451 // the array from being modified while we iterate it. 17452 for (OnAttachStateChangeListener listener : listeners) { 17453 listener.onViewDetachedFromWindow(this); 17454 } 17455 } 17456 17457 if ((mPrivateFlags & PFLAG_SCROLL_CONTAINER_ADDED) != 0) { 17458 mAttachInfo.mScrollContainers.remove(this); 17459 mPrivateFlags &= ~PFLAG_SCROLL_CONTAINER_ADDED; 17460 } 17461 17462 mAttachInfo = null; 17463 if (mOverlay != null) { 17464 mOverlay.getOverlayView().dispatchDetachedFromWindow(); 17465 } 17466 17467 notifyEnterOrExitForAutoFillIfNeeded(false); 17468 } 17469 17470 /** 17471 * Cancel any deferred high-level input events that were previously posted to the event queue. 17472 * 17473 * <p>Many views post high-level events such as click handlers to the event queue 17474 * to run deferred in order to preserve a desired user experience - clearing visible 17475 * pressed states before executing, etc. This method will abort any events of this nature 17476 * that are currently in flight.</p> 17477 * 17478 * <p>Custom views that generate their own high-level deferred input events should override 17479 * {@link #onCancelPendingInputEvents()} and remove those pending events from the queue.</p> 17480 * 17481 * <p>This will also cancel pending input events for any child views.</p> 17482 * 17483 * <p>Note that this may not be sufficient as a debouncing strategy for clicks in all cases. 17484 * This will not impact newer events posted after this call that may occur as a result of 17485 * lower-level input events still waiting in the queue. If you are trying to prevent 17486 * double-submitted events for the duration of some sort of asynchronous transaction 17487 * you should also take other steps to protect against unexpected double inputs e.g. calling 17488 * {@link #setEnabled(boolean) setEnabled(false)} and re-enabling the view when 17489 * the transaction completes, tracking already submitted transaction IDs, etc.</p> 17490 */ 17491 public final void cancelPendingInputEvents() { 17492 dispatchCancelPendingInputEvents(); 17493 } 17494 17495 /** 17496 * Called by {@link #cancelPendingInputEvents()} to cancel input events in flight. 17497 * Overridden by ViewGroup to dispatch. Package scoped to prevent app-side meddling. 17498 */ 17499 void dispatchCancelPendingInputEvents() { 17500 mPrivateFlags3 &= ~PFLAG3_CALLED_SUPER; 17501 onCancelPendingInputEvents(); 17502 if ((mPrivateFlags3 & PFLAG3_CALLED_SUPER) != PFLAG3_CALLED_SUPER) { 17503 throw new SuperNotCalledException("View " + getClass().getSimpleName() + 17504 " did not call through to super.onCancelPendingInputEvents()"); 17505 } 17506 } 17507 17508 /** 17509 * Called as the result of a call to {@link #cancelPendingInputEvents()} on this view or 17510 * a parent view. 17511 * 17512 * <p>This method is responsible for removing any pending high-level input events that were 17513 * posted to the event queue to run later. Custom view classes that post their own deferred 17514 * high-level events via {@link #post(Runnable)}, {@link #postDelayed(Runnable, long)} or 17515 * {@link android.os.Handler} should override this method, call 17516 * <code>super.onCancelPendingInputEvents()</code> and remove those callbacks as appropriate. 17517 * </p> 17518 */ 17519 public void onCancelPendingInputEvents() { 17520 removePerformClickCallback(); 17521 cancelLongPress(); 17522 mPrivateFlags3 |= PFLAG3_CALLED_SUPER; 17523 } 17524 17525 /** 17526 * Store this view hierarchy's frozen state into the given container. 17527 * 17528 * @param container The SparseArray in which to save the view's state. 17529 * 17530 * @see #restoreHierarchyState(android.util.SparseArray) 17531 * @see #dispatchSaveInstanceState(android.util.SparseArray) 17532 * @see #onSaveInstanceState() 17533 */ 17534 public void saveHierarchyState(SparseArray<Parcelable> container) { 17535 dispatchSaveInstanceState(container); 17536 } 17537 17538 /** 17539 * Called by {@link #saveHierarchyState(android.util.SparseArray)} to store the state for 17540 * this view and its children. May be overridden to modify how freezing happens to a 17541 * view's children; for example, some views may want to not store state for their children. 17542 * 17543 * @param container The SparseArray in which to save the view's state. 17544 * 17545 * @see #dispatchRestoreInstanceState(android.util.SparseArray) 17546 * @see #saveHierarchyState(android.util.SparseArray) 17547 * @see #onSaveInstanceState() 17548 */ 17549 protected void dispatchSaveInstanceState(SparseArray<Parcelable> container) { 17550 if (mID != NO_ID && (mViewFlags & SAVE_DISABLED_MASK) == 0) { 17551 mPrivateFlags &= ~PFLAG_SAVE_STATE_CALLED; 17552 Parcelable state = onSaveInstanceState(); 17553 if ((mPrivateFlags & PFLAG_SAVE_STATE_CALLED) == 0) { 17554 throw new IllegalStateException( 17555 "Derived class did not call super.onSaveInstanceState()"); 17556 } 17557 if (state != null) { 17558 // Log.i("View", "Freezing #" + Integer.toHexString(mID) 17559 // + ": " + state); 17560 container.put(mID, state); 17561 } 17562 } 17563 } 17564 17565 /** 17566 * Hook allowing a view to generate a representation of its internal state 17567 * that can later be used to create a new instance with that same state. 17568 * This state should only contain information that is not persistent or can 17569 * not be reconstructed later. For example, you will never store your 17570 * current position on screen because that will be computed again when a 17571 * new instance of the view is placed in its view hierarchy. 17572 * <p> 17573 * Some examples of things you may store here: the current cursor position 17574 * in a text view (but usually not the text itself since that is stored in a 17575 * content provider or other persistent storage), the currently selected 17576 * item in a list view. 17577 * 17578 * @return Returns a Parcelable object containing the view's current dynamic 17579 * state, or null if there is nothing interesting to save. 17580 * @see #onRestoreInstanceState(Parcelable) 17581 * @see #saveHierarchyState(SparseArray) 17582 * @see #dispatchSaveInstanceState(SparseArray) 17583 * @see #setSaveEnabled(boolean) 17584 */ 17585 @CallSuper 17586 @Nullable protected Parcelable onSaveInstanceState() { 17587 mPrivateFlags |= PFLAG_SAVE_STATE_CALLED; 17588 if (mStartActivityRequestWho != null || isAutofilled() 17589 || mAutofillViewId > LAST_APP_AUTOFILL_ID) { 17590 BaseSavedState state = new BaseSavedState(AbsSavedState.EMPTY_STATE); 17591 17592 if (mStartActivityRequestWho != null) { 17593 state.mSavedData |= BaseSavedState.START_ACTIVITY_REQUESTED_WHO_SAVED; 17594 } 17595 17596 if (isAutofilled()) { 17597 state.mSavedData |= BaseSavedState.IS_AUTOFILLED; 17598 } 17599 17600 if (mAutofillViewId > LAST_APP_AUTOFILL_ID) { 17601 state.mSavedData |= BaseSavedState.AUTOFILL_ID; 17602 } 17603 17604 state.mStartActivityRequestWhoSaved = mStartActivityRequestWho; 17605 state.mIsAutofilled = isAutofilled(); 17606 state.mAutofillViewId = mAutofillViewId; 17607 return state; 17608 } 17609 return BaseSavedState.EMPTY_STATE; 17610 } 17611 17612 /** 17613 * Restore this view hierarchy's frozen state from the given container. 17614 * 17615 * @param container The SparseArray which holds previously frozen states. 17616 * 17617 * @see #saveHierarchyState(android.util.SparseArray) 17618 * @see #dispatchRestoreInstanceState(android.util.SparseArray) 17619 * @see #onRestoreInstanceState(android.os.Parcelable) 17620 */ 17621 public void restoreHierarchyState(SparseArray<Parcelable> container) { 17622 dispatchRestoreInstanceState(container); 17623 } 17624 17625 /** 17626 * Called by {@link #restoreHierarchyState(android.util.SparseArray)} to retrieve the 17627 * state for this view and its children. May be overridden to modify how restoring 17628 * happens to a view's children; for example, some views may want to not store state 17629 * for their children. 17630 * 17631 * @param container The SparseArray which holds previously saved state. 17632 * 17633 * @see #dispatchSaveInstanceState(android.util.SparseArray) 17634 * @see #restoreHierarchyState(android.util.SparseArray) 17635 * @see #onRestoreInstanceState(android.os.Parcelable) 17636 */ 17637 protected void dispatchRestoreInstanceState(SparseArray<Parcelable> container) { 17638 if (mID != NO_ID) { 17639 Parcelable state = container.get(mID); 17640 if (state != null) { 17641 // Log.i("View", "Restoreing #" + Integer.toHexString(mID) 17642 // + ": " + state); 17643 mPrivateFlags &= ~PFLAG_SAVE_STATE_CALLED; 17644 onRestoreInstanceState(state); 17645 if ((mPrivateFlags & PFLAG_SAVE_STATE_CALLED) == 0) { 17646 throw new IllegalStateException( 17647 "Derived class did not call super.onRestoreInstanceState()"); 17648 } 17649 } 17650 } 17651 } 17652 17653 /** 17654 * Hook allowing a view to re-apply a representation of its internal state that had previously 17655 * been generated by {@link #onSaveInstanceState}. This function will never be called with a 17656 * null state. 17657 * 17658 * @param state The frozen state that had previously been returned by 17659 * {@link #onSaveInstanceState}. 17660 * 17661 * @see #onSaveInstanceState() 17662 * @see #restoreHierarchyState(android.util.SparseArray) 17663 * @see #dispatchRestoreInstanceState(android.util.SparseArray) 17664 */ 17665 @CallSuper 17666 protected void onRestoreInstanceState(Parcelable state) { 17667 mPrivateFlags |= PFLAG_SAVE_STATE_CALLED; 17668 if (state != null && !(state instanceof AbsSavedState)) { 17669 throw new IllegalArgumentException("Wrong state class, expecting View State but " 17670 + "received " + state.getClass().toString() + " instead. This usually happens " 17671 + "when two views of different type have the same id in the same hierarchy. " 17672 + "This view's id is " + ViewDebug.resolveId(mContext, getId()) + ". Make sure " 17673 + "other views do not use the same id."); 17674 } 17675 if (state != null && state instanceof BaseSavedState) { 17676 BaseSavedState baseState = (BaseSavedState) state; 17677 17678 if ((baseState.mSavedData & BaseSavedState.START_ACTIVITY_REQUESTED_WHO_SAVED) != 0) { 17679 mStartActivityRequestWho = baseState.mStartActivityRequestWhoSaved; 17680 } 17681 if ((baseState.mSavedData & BaseSavedState.IS_AUTOFILLED) != 0) { 17682 setAutofilled(baseState.mIsAutofilled); 17683 } 17684 if ((baseState.mSavedData & BaseSavedState.AUTOFILL_ID) != 0) { 17685 mAutofillViewId = baseState.mAutofillViewId; 17686 } 17687 } 17688 } 17689 17690 /** 17691 * <p>Return the time at which the drawing of the view hierarchy started.</p> 17692 * 17693 * @return the drawing start time in milliseconds 17694 */ 17695 public long getDrawingTime() { 17696 return mAttachInfo != null ? mAttachInfo.mDrawingTime : 0; 17697 } 17698 17699 /** 17700 * <p>Enables or disables the duplication of the parent's state into this view. When 17701 * duplication is enabled, this view gets its drawable state from its parent rather 17702 * than from its own internal properties.</p> 17703 * 17704 * <p>Note: in the current implementation, setting this property to true after the 17705 * view was added to a ViewGroup might have no effect at all. This property should 17706 * always be used from XML or set to true before adding this view to a ViewGroup.</p> 17707 * 17708 * <p>Note: if this view's parent addStateFromChildren property is enabled and this 17709 * property is enabled, an exception will be thrown.</p> 17710 * 17711 * <p>Note: if the child view uses and updates additional states which are unknown to the 17712 * parent, these states should not be affected by this method.</p> 17713 * 17714 * @param enabled True to enable duplication of the parent's drawable state, false 17715 * to disable it. 17716 * 17717 * @see #getDrawableState() 17718 * @see #isDuplicateParentStateEnabled() 17719 */ 17720 public void setDuplicateParentStateEnabled(boolean enabled) { 17721 setFlags(enabled ? DUPLICATE_PARENT_STATE : 0, DUPLICATE_PARENT_STATE); 17722 } 17723 17724 /** 17725 * <p>Indicates whether this duplicates its drawable state from its parent.</p> 17726 * 17727 * @return True if this view's drawable state is duplicated from the parent, 17728 * false otherwise 17729 * 17730 * @see #getDrawableState() 17731 * @see #setDuplicateParentStateEnabled(boolean) 17732 */ 17733 public boolean isDuplicateParentStateEnabled() { 17734 return (mViewFlags & DUPLICATE_PARENT_STATE) == DUPLICATE_PARENT_STATE; 17735 } 17736 17737 /** 17738 * <p>Specifies the type of layer backing this view. The layer can be 17739 * {@link #LAYER_TYPE_NONE}, {@link #LAYER_TYPE_SOFTWARE} or 17740 * {@link #LAYER_TYPE_HARDWARE}.</p> 17741 * 17742 * <p>A layer is associated with an optional {@link android.graphics.Paint} 17743 * instance that controls how the layer is composed on screen. The following 17744 * properties of the paint are taken into account when composing the layer:</p> 17745 * <ul> 17746 * <li>{@link android.graphics.Paint#getAlpha() Translucency (alpha)}</li> 17747 * <li>{@link android.graphics.Paint#getXfermode() Blending mode}</li> 17748 * <li>{@link android.graphics.Paint#getColorFilter() Color filter}</li> 17749 * </ul> 17750 * 17751 * <p>If this view has an alpha value set to < 1.0 by calling 17752 * {@link #setAlpha(float)}, the alpha value of the layer's paint is superseded 17753 * by this view's alpha value.</p> 17754 * 17755 * <p>Refer to the documentation of {@link #LAYER_TYPE_NONE}, 17756 * {@link #LAYER_TYPE_SOFTWARE} and {@link #LAYER_TYPE_HARDWARE} 17757 * for more information on when and how to use layers.</p> 17758 * 17759 * @param layerType The type of layer to use with this view, must be one of 17760 * {@link #LAYER_TYPE_NONE}, {@link #LAYER_TYPE_SOFTWARE} or 17761 * {@link #LAYER_TYPE_HARDWARE} 17762 * @param paint The paint used to compose the layer. This argument is optional 17763 * and can be null. It is ignored when the layer type is 17764 * {@link #LAYER_TYPE_NONE} 17765 * 17766 * @see #getLayerType() 17767 * @see #LAYER_TYPE_NONE 17768 * @see #LAYER_TYPE_SOFTWARE 17769 * @see #LAYER_TYPE_HARDWARE 17770 * @see #setAlpha(float) 17771 * 17772 * @attr ref android.R.styleable#View_layerType 17773 */ 17774 public void setLayerType(int layerType, @Nullable Paint paint) { 17775 if (layerType < LAYER_TYPE_NONE || layerType > LAYER_TYPE_HARDWARE) { 17776 throw new IllegalArgumentException("Layer type can only be one of: LAYER_TYPE_NONE, " 17777 + "LAYER_TYPE_SOFTWARE or LAYER_TYPE_HARDWARE"); 17778 } 17779 17780 boolean typeChanged = mRenderNode.setLayerType(layerType); 17781 17782 if (!typeChanged) { 17783 setLayerPaint(paint); 17784 return; 17785 } 17786 17787 if (layerType != LAYER_TYPE_SOFTWARE) { 17788 // Destroy any previous software drawing cache if present 17789 // NOTE: even if previous layer type is HW, we do this to ensure we've cleaned up 17790 // drawing cache created in View#draw when drawing to a SW canvas. 17791 destroyDrawingCache(); 17792 } 17793 17794 mLayerType = layerType; 17795 mLayerPaint = mLayerType == LAYER_TYPE_NONE ? null : paint; 17796 mRenderNode.setLayerPaint(mLayerPaint); 17797 17798 // draw() behaves differently if we are on a layer, so we need to 17799 // invalidate() here 17800 invalidateParentCaches(); 17801 invalidate(true); 17802 } 17803 17804 /** 17805 * Updates the {@link Paint} object used with the current layer (used only if the current 17806 * layer type is not set to {@link #LAYER_TYPE_NONE}). Changed properties of the Paint 17807 * provided to {@link #setLayerType(int, android.graphics.Paint)} will be used the next time 17808 * the View is redrawn, but {@link #setLayerPaint(android.graphics.Paint)} must be called to 17809 * ensure that the view gets redrawn immediately. 17810 * 17811 * <p>A layer is associated with an optional {@link android.graphics.Paint} 17812 * instance that controls how the layer is composed on screen. The following 17813 * properties of the paint are taken into account when composing the layer:</p> 17814 * <ul> 17815 * <li>{@link android.graphics.Paint#getAlpha() Translucency (alpha)}</li> 17816 * <li>{@link android.graphics.Paint#getXfermode() Blending mode}</li> 17817 * <li>{@link android.graphics.Paint#getColorFilter() Color filter}</li> 17818 * </ul> 17819 * 17820 * <p>If this view has an alpha value set to < 1.0 by calling {@link #setAlpha(float)}, the 17821 * alpha value of the layer's paint is superseded by this view's alpha value.</p> 17822 * 17823 * @param paint The paint used to compose the layer. This argument is optional 17824 * and can be null. It is ignored when the layer type is 17825 * {@link #LAYER_TYPE_NONE} 17826 * 17827 * @see #setLayerType(int, android.graphics.Paint) 17828 */ 17829 public void setLayerPaint(@Nullable Paint paint) { 17830 int layerType = getLayerType(); 17831 if (layerType != LAYER_TYPE_NONE) { 17832 mLayerPaint = paint; 17833 if (layerType == LAYER_TYPE_HARDWARE) { 17834 if (mRenderNode.setLayerPaint(paint)) { 17835 invalidateViewProperty(false, false); 17836 } 17837 } else { 17838 invalidate(); 17839 } 17840 } 17841 } 17842 17843 /** 17844 * Indicates what type of layer is currently associated with this view. By default 17845 * a view does not have a layer, and the layer type is {@link #LAYER_TYPE_NONE}. 17846 * Refer to the documentation of {@link #setLayerType(int, android.graphics.Paint)} 17847 * for more information on the different types of layers. 17848 * 17849 * @return {@link #LAYER_TYPE_NONE}, {@link #LAYER_TYPE_SOFTWARE} or 17850 * {@link #LAYER_TYPE_HARDWARE} 17851 * 17852 * @see #setLayerType(int, android.graphics.Paint) 17853 * @see #buildLayer() 17854 * @see #LAYER_TYPE_NONE 17855 * @see #LAYER_TYPE_SOFTWARE 17856 * @see #LAYER_TYPE_HARDWARE 17857 */ 17858 public int getLayerType() { 17859 return mLayerType; 17860 } 17861 17862 /** 17863 * Forces this view's layer to be created and this view to be rendered 17864 * into its layer. If this view's layer type is set to {@link #LAYER_TYPE_NONE}, 17865 * invoking this method will have no effect. 17866 * 17867 * This method can for instance be used to render a view into its layer before 17868 * starting an animation. If this view is complex, rendering into the layer 17869 * before starting the animation will avoid skipping frames. 17870 * 17871 * @throws IllegalStateException If this view is not attached to a window 17872 * 17873 * @see #setLayerType(int, android.graphics.Paint) 17874 */ 17875 public void buildLayer() { 17876 if (mLayerType == LAYER_TYPE_NONE) return; 17877 17878 final AttachInfo attachInfo = mAttachInfo; 17879 if (attachInfo == null) { 17880 throw new IllegalStateException("This view must be attached to a window first"); 17881 } 17882 17883 if (getWidth() == 0 || getHeight() == 0) { 17884 return; 17885 } 17886 17887 switch (mLayerType) { 17888 case LAYER_TYPE_HARDWARE: 17889 updateDisplayListIfDirty(); 17890 if (attachInfo.mThreadedRenderer != null && mRenderNode.isValid()) { 17891 attachInfo.mThreadedRenderer.buildLayer(mRenderNode); 17892 } 17893 break; 17894 case LAYER_TYPE_SOFTWARE: 17895 buildDrawingCache(true); 17896 break; 17897 } 17898 } 17899 17900 /** 17901 * Destroys all hardware rendering resources. This method is invoked 17902 * when the system needs to reclaim resources. Upon execution of this 17903 * method, you should free any OpenGL resources created by the view. 17904 * 17905 * Note: you <strong>must</strong> call 17906 * <code>super.destroyHardwareResources()</code> when overriding 17907 * this method. 17908 * 17909 * @hide 17910 */ 17911 @CallSuper 17912 protected void destroyHardwareResources() { 17913 if (mOverlay != null) { 17914 mOverlay.getOverlayView().destroyHardwareResources(); 17915 } 17916 if (mGhostView != null) { 17917 mGhostView.destroyHardwareResources(); 17918 } 17919 } 17920 17921 /** 17922 * <p>Enables or disables the drawing cache. When the drawing cache is enabled, the next call 17923 * to {@link #getDrawingCache()} or {@link #buildDrawingCache()} will draw the view in a 17924 * bitmap. Calling {@link #draw(android.graphics.Canvas)} will not draw from the cache when 17925 * the cache is enabled. To benefit from the cache, you must request the drawing cache by 17926 * calling {@link #getDrawingCache()} and draw it on screen if the returned bitmap is not 17927 * null.</p> 17928 * 17929 * <p>Enabling the drawing cache is similar to 17930 * {@link #setLayerType(int, android.graphics.Paint) setting a layer} when hardware 17931 * acceleration is turned off. When hardware acceleration is turned on, enabling the 17932 * drawing cache has no effect on rendering because the system uses a different mechanism 17933 * for acceleration which ignores the flag. If you want to use a Bitmap for the view, even 17934 * when hardware acceleration is enabled, see {@link #setLayerType(int, android.graphics.Paint)} 17935 * for information on how to enable software and hardware layers.</p> 17936 * 17937 * <p>This API can be used to manually generate 17938 * a bitmap copy of this view, by setting the flag to <code>true</code> and calling 17939 * {@link #getDrawingCache()}.</p> 17940 * 17941 * @param enabled true to enable the drawing cache, false otherwise 17942 * 17943 * @see #isDrawingCacheEnabled() 17944 * @see #getDrawingCache() 17945 * @see #buildDrawingCache() 17946 * @see #setLayerType(int, android.graphics.Paint) 17947 */ 17948 public void setDrawingCacheEnabled(boolean enabled) { 17949 mCachingFailed = false; 17950 setFlags(enabled ? DRAWING_CACHE_ENABLED : 0, DRAWING_CACHE_ENABLED); 17951 } 17952 17953 /** 17954 * <p>Indicates whether the drawing cache is enabled for this view.</p> 17955 * 17956 * @return true if the drawing cache is enabled 17957 * 17958 * @see #setDrawingCacheEnabled(boolean) 17959 * @see #getDrawingCache() 17960 */ 17961 @ViewDebug.ExportedProperty(category = "drawing") 17962 public boolean isDrawingCacheEnabled() { 17963 return (mViewFlags & DRAWING_CACHE_ENABLED) == DRAWING_CACHE_ENABLED; 17964 } 17965 17966 /** 17967 * Debugging utility which recursively outputs the dirty state of a view and its 17968 * descendants. 17969 * 17970 * @hide 17971 */ 17972 @SuppressWarnings({"UnusedDeclaration"}) 17973 public void outputDirtyFlags(String indent, boolean clear, int clearMask) { 17974 Log.d("View", indent + this + " DIRTY(" + (mPrivateFlags & View.PFLAG_DIRTY_MASK) + 17975 ") DRAWN(" + (mPrivateFlags & PFLAG_DRAWN) + ")" + " CACHE_VALID(" + 17976 (mPrivateFlags & View.PFLAG_DRAWING_CACHE_VALID) + 17977 ") INVALIDATED(" + (mPrivateFlags & PFLAG_INVALIDATED) + ")"); 17978 if (clear) { 17979 mPrivateFlags &= clearMask; 17980 } 17981 if (this instanceof ViewGroup) { 17982 ViewGroup parent = (ViewGroup) this; 17983 final int count = parent.getChildCount(); 17984 for (int i = 0; i < count; i++) { 17985 final View child = parent.getChildAt(i); 17986 child.outputDirtyFlags(indent + " ", clear, clearMask); 17987 } 17988 } 17989 } 17990 17991 /** 17992 * This method is used by ViewGroup to cause its children to restore or recreate their 17993 * display lists. It is called by getDisplayList() when the parent ViewGroup does not need 17994 * to recreate its own display list, which would happen if it went through the normal 17995 * draw/dispatchDraw mechanisms. 17996 * 17997 * @hide 17998 */ 17999 protected void dispatchGetDisplayList() {} 18000 18001 /** 18002 * A view that is not attached or hardware accelerated cannot create a display list. 18003 * This method checks these conditions and returns the appropriate result. 18004 * 18005 * @return true if view has the ability to create a display list, false otherwise. 18006 * 18007 * @hide 18008 */ 18009 public boolean canHaveDisplayList() { 18010 return !(mAttachInfo == null || mAttachInfo.mThreadedRenderer == null); 18011 } 18012 18013 /** 18014 * Gets the RenderNode for the view, and updates its DisplayList (if needed and supported) 18015 * @hide 18016 */ 18017 @NonNull 18018 public RenderNode updateDisplayListIfDirty() { 18019 final RenderNode renderNode = mRenderNode; 18020 if (!canHaveDisplayList()) { 18021 // can't populate RenderNode, don't try 18022 return renderNode; 18023 } 18024 18025 if ((mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == 0 18026 || !renderNode.isValid() 18027 || (mRecreateDisplayList)) { 18028 // Don't need to recreate the display list, just need to tell our 18029 // children to restore/recreate theirs 18030 if (renderNode.isValid() 18031 && !mRecreateDisplayList) { 18032 mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID; 18033 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 18034 dispatchGetDisplayList(); 18035 18036 return renderNode; // no work needed 18037 } 18038 18039 // If we got here, we're recreating it. Mark it as such to ensure that 18040 // we copy in child display lists into ours in drawChild() 18041 mRecreateDisplayList = true; 18042 18043 int width = mRight - mLeft; 18044 int height = mBottom - mTop; 18045 int layerType = getLayerType(); 18046 18047 final DisplayListCanvas canvas = renderNode.start(width, height); 18048 canvas.setHighContrastText(mAttachInfo.mHighContrastText); 18049 18050 try { 18051 if (layerType == LAYER_TYPE_SOFTWARE) { 18052 buildDrawingCache(true); 18053 Bitmap cache = getDrawingCache(true); 18054 if (cache != null) { 18055 canvas.drawBitmap(cache, 0, 0, mLayerPaint); 18056 } 18057 } else { 18058 computeScroll(); 18059 18060 canvas.translate(-mScrollX, -mScrollY); 18061 mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID; 18062 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 18063 18064 // Fast path for layouts with no backgrounds 18065 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { 18066 dispatchDraw(canvas); 18067 drawAutofilledHighlight(canvas); 18068 if (mOverlay != null && !mOverlay.isEmpty()) { 18069 mOverlay.getOverlayView().draw(canvas); 18070 } 18071 if (debugDraw()) { 18072 debugDrawFocus(canvas); 18073 } 18074 } else { 18075 draw(canvas); 18076 } 18077 } 18078 } finally { 18079 renderNode.end(canvas); 18080 setDisplayListProperties(renderNode); 18081 } 18082 } else { 18083 mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID; 18084 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 18085 } 18086 return renderNode; 18087 } 18088 18089 private void resetDisplayList() { 18090 mRenderNode.discardDisplayList(); 18091 if (mBackgroundRenderNode != null) { 18092 mBackgroundRenderNode.discardDisplayList(); 18093 } 18094 } 18095 18096 /** 18097 * <p>Calling this method is equivalent to calling <code>getDrawingCache(false)</code>.</p> 18098 * 18099 * @return A non-scaled bitmap representing this view or null if cache is disabled. 18100 * 18101 * @see #getDrawingCache(boolean) 18102 */ 18103 public Bitmap getDrawingCache() { 18104 return getDrawingCache(false); 18105 } 18106 18107 /** 18108 * <p>Returns the bitmap in which this view drawing is cached. The returned bitmap 18109 * is null when caching is disabled. If caching is enabled and the cache is not ready, 18110 * this method will create it. Calling {@link #draw(android.graphics.Canvas)} will not 18111 * draw from the cache when the cache is enabled. To benefit from the cache, you must 18112 * request the drawing cache by calling this method and draw it on screen if the 18113 * returned bitmap is not null.</p> 18114 * 18115 * <p>Note about auto scaling in compatibility mode: When auto scaling is not enabled, 18116 * this method will create a bitmap of the same size as this view. Because this bitmap 18117 * will be drawn scaled by the parent ViewGroup, the result on screen might show 18118 * scaling artifacts. To avoid such artifacts, you should call this method by setting 18119 * the auto scaling to true. Doing so, however, will generate a bitmap of a different 18120 * size than the view. This implies that your application must be able to handle this 18121 * size.</p> 18122 * 18123 * @param autoScale Indicates whether the generated bitmap should be scaled based on 18124 * the current density of the screen when the application is in compatibility 18125 * mode. 18126 * 18127 * @return A bitmap representing this view or null if cache is disabled. 18128 * 18129 * @see #setDrawingCacheEnabled(boolean) 18130 * @see #isDrawingCacheEnabled() 18131 * @see #buildDrawingCache(boolean) 18132 * @see #destroyDrawingCache() 18133 */ 18134 public Bitmap getDrawingCache(boolean autoScale) { 18135 if ((mViewFlags & WILL_NOT_CACHE_DRAWING) == WILL_NOT_CACHE_DRAWING) { 18136 return null; 18137 } 18138 if ((mViewFlags & DRAWING_CACHE_ENABLED) == DRAWING_CACHE_ENABLED) { 18139 buildDrawingCache(autoScale); 18140 } 18141 return autoScale ? mDrawingCache : mUnscaledDrawingCache; 18142 } 18143 18144 /** 18145 * <p>Frees the resources used by the drawing cache. If you call 18146 * {@link #buildDrawingCache()} manually without calling 18147 * {@link #setDrawingCacheEnabled(boolean) setDrawingCacheEnabled(true)}, you 18148 * should cleanup the cache with this method afterwards.</p> 18149 * 18150 * @see #setDrawingCacheEnabled(boolean) 18151 * @see #buildDrawingCache() 18152 * @see #getDrawingCache() 18153 */ 18154 public void destroyDrawingCache() { 18155 if (mDrawingCache != null) { 18156 mDrawingCache.recycle(); 18157 mDrawingCache = null; 18158 } 18159 if (mUnscaledDrawingCache != null) { 18160 mUnscaledDrawingCache.recycle(); 18161 mUnscaledDrawingCache = null; 18162 } 18163 } 18164 18165 /** 18166 * Setting a solid background color for the drawing cache's bitmaps will improve 18167 * performance and memory usage. Note, though that this should only be used if this 18168 * view will always be drawn on top of a solid color. 18169 * 18170 * @param color The background color to use for the drawing cache's bitmap 18171 * 18172 * @see #setDrawingCacheEnabled(boolean) 18173 * @see #buildDrawingCache() 18174 * @see #getDrawingCache() 18175 */ 18176 public void setDrawingCacheBackgroundColor(@ColorInt int color) { 18177 if (color != mDrawingCacheBackgroundColor) { 18178 mDrawingCacheBackgroundColor = color; 18179 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; 18180 } 18181 } 18182 18183 /** 18184 * @see #setDrawingCacheBackgroundColor(int) 18185 * 18186 * @return The background color to used for the drawing cache's bitmap 18187 */ 18188 @ColorInt 18189 public int getDrawingCacheBackgroundColor() { 18190 return mDrawingCacheBackgroundColor; 18191 } 18192 18193 /** 18194 * <p>Calling this method is equivalent to calling <code>buildDrawingCache(false)</code>.</p> 18195 * 18196 * @see #buildDrawingCache(boolean) 18197 */ 18198 public void buildDrawingCache() { 18199 buildDrawingCache(false); 18200 } 18201 18202 /** 18203 * <p>Forces the drawing cache to be built if the drawing cache is invalid.</p> 18204 * 18205 * <p>If you call {@link #buildDrawingCache()} manually without calling 18206 * {@link #setDrawingCacheEnabled(boolean) setDrawingCacheEnabled(true)}, you 18207 * should cleanup the cache by calling {@link #destroyDrawingCache()} afterwards.</p> 18208 * 18209 * <p>Note about auto scaling in compatibility mode: When auto scaling is not enabled, 18210 * this method will create a bitmap of the same size as this view. Because this bitmap 18211 * will be drawn scaled by the parent ViewGroup, the result on screen might show 18212 * scaling artifacts. To avoid such artifacts, you should call this method by setting 18213 * the auto scaling to true. Doing so, however, will generate a bitmap of a different 18214 * size than the view. This implies that your application must be able to handle this 18215 * size.</p> 18216 * 18217 * <p>You should avoid calling this method when hardware acceleration is enabled. If 18218 * you do not need the drawing cache bitmap, calling this method will increase memory 18219 * usage and cause the view to be rendered in software once, thus negatively impacting 18220 * performance.</p> 18221 * 18222 * @see #getDrawingCache() 18223 * @see #destroyDrawingCache() 18224 */ 18225 public void buildDrawingCache(boolean autoScale) { 18226 if ((mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == 0 || (autoScale ? 18227 mDrawingCache == null : mUnscaledDrawingCache == null)) { 18228 if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) { 18229 Trace.traceBegin(Trace.TRACE_TAG_VIEW, 18230 "buildDrawingCache/SW Layer for " + getClass().getSimpleName()); 18231 } 18232 try { 18233 buildDrawingCacheImpl(autoScale); 18234 } finally { 18235 Trace.traceEnd(Trace.TRACE_TAG_VIEW); 18236 } 18237 } 18238 } 18239 18240 /** 18241 * private, internal implementation of buildDrawingCache, used to enable tracing 18242 */ 18243 private void buildDrawingCacheImpl(boolean autoScale) { 18244 mCachingFailed = false; 18245 18246 int width = mRight - mLeft; 18247 int height = mBottom - mTop; 18248 18249 final AttachInfo attachInfo = mAttachInfo; 18250 final boolean scalingRequired = attachInfo != null && attachInfo.mScalingRequired; 18251 18252 if (autoScale && scalingRequired) { 18253 width = (int) ((width * attachInfo.mApplicationScale) + 0.5f); 18254 height = (int) ((height * attachInfo.mApplicationScale) + 0.5f); 18255 } 18256 18257 final int drawingCacheBackgroundColor = mDrawingCacheBackgroundColor; 18258 final boolean opaque = drawingCacheBackgroundColor != 0 || isOpaque(); 18259 final boolean use32BitCache = attachInfo != null && attachInfo.mUse32BitDrawingCache; 18260 18261 final long projectedBitmapSize = width * height * (opaque && !use32BitCache ? 2 : 4); 18262 final long drawingCacheSize = 18263 ViewConfiguration.get(mContext).getScaledMaximumDrawingCacheSize(); 18264 if (width <= 0 || height <= 0 || projectedBitmapSize > drawingCacheSize) { 18265 if (width > 0 && height > 0) { 18266 Log.w(VIEW_LOG_TAG, getClass().getSimpleName() + " not displayed because it is" 18267 + " too large to fit into a software layer (or drawing cache), needs " 18268 + projectedBitmapSize + " bytes, only " 18269 + drawingCacheSize + " available"); 18270 } 18271 destroyDrawingCache(); 18272 mCachingFailed = true; 18273 return; 18274 } 18275 18276 boolean clear = true; 18277 Bitmap bitmap = autoScale ? mDrawingCache : mUnscaledDrawingCache; 18278 18279 if (bitmap == null || bitmap.getWidth() != width || bitmap.getHeight() != height) { 18280 Bitmap.Config quality; 18281 if (!opaque) { 18282 // Never pick ARGB_4444 because it looks awful 18283 // Keep the DRAWING_CACHE_QUALITY_LOW flag just in case 18284 switch (mViewFlags & DRAWING_CACHE_QUALITY_MASK) { 18285 case DRAWING_CACHE_QUALITY_AUTO: 18286 case DRAWING_CACHE_QUALITY_LOW: 18287 case DRAWING_CACHE_QUALITY_HIGH: 18288 default: 18289 quality = Bitmap.Config.ARGB_8888; 18290 break; 18291 } 18292 } else { 18293 // Optimization for translucent windows 18294 // If the window is translucent, use a 32 bits bitmap to benefit from memcpy() 18295 quality = use32BitCache ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565; 18296 } 18297 18298 // Try to cleanup memory 18299 if (bitmap != null) bitmap.recycle(); 18300 18301 try { 18302 bitmap = Bitmap.createBitmap(mResources.getDisplayMetrics(), 18303 width, height, quality); 18304 bitmap.setDensity(getResources().getDisplayMetrics().densityDpi); 18305 if (autoScale) { 18306 mDrawingCache = bitmap; 18307 } else { 18308 mUnscaledDrawingCache = bitmap; 18309 } 18310 if (opaque && use32BitCache) bitmap.setHasAlpha(false); 18311 } catch (OutOfMemoryError e) { 18312 // If there is not enough memory to create the bitmap cache, just 18313 // ignore the issue as bitmap caches are not required to draw the 18314 // view hierarchy 18315 if (autoScale) { 18316 mDrawingCache = null; 18317 } else { 18318 mUnscaledDrawingCache = null; 18319 } 18320 mCachingFailed = true; 18321 return; 18322 } 18323 18324 clear = drawingCacheBackgroundColor != 0; 18325 } 18326 18327 Canvas canvas; 18328 if (attachInfo != null) { 18329 canvas = attachInfo.mCanvas; 18330 if (canvas == null) { 18331 canvas = new Canvas(); 18332 } 18333 canvas.setBitmap(bitmap); 18334 // Temporarily clobber the cached Canvas in case one of our children 18335 // is also using a drawing cache. Without this, the children would 18336 // steal the canvas by attaching their own bitmap to it and bad, bad 18337 // thing would happen (invisible views, corrupted drawings, etc.) 18338 attachInfo.mCanvas = null; 18339 } else { 18340 // This case should hopefully never or seldom happen 18341 canvas = new Canvas(bitmap); 18342 } 18343 18344 if (clear) { 18345 bitmap.eraseColor(drawingCacheBackgroundColor); 18346 } 18347 18348 computeScroll(); 18349 final int restoreCount = canvas.save(); 18350 18351 if (autoScale && scalingRequired) { 18352 final float scale = attachInfo.mApplicationScale; 18353 canvas.scale(scale, scale); 18354 } 18355 18356 canvas.translate(-mScrollX, -mScrollY); 18357 18358 mPrivateFlags |= PFLAG_DRAWN; 18359 if (mAttachInfo == null || !mAttachInfo.mHardwareAccelerated || 18360 mLayerType != LAYER_TYPE_NONE) { 18361 mPrivateFlags |= PFLAG_DRAWING_CACHE_VALID; 18362 } 18363 18364 // Fast path for layouts with no backgrounds 18365 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { 18366 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 18367 dispatchDraw(canvas); 18368 drawAutofilledHighlight(canvas); 18369 if (mOverlay != null && !mOverlay.isEmpty()) { 18370 mOverlay.getOverlayView().draw(canvas); 18371 } 18372 } else { 18373 draw(canvas); 18374 } 18375 18376 canvas.restoreToCount(restoreCount); 18377 canvas.setBitmap(null); 18378 18379 if (attachInfo != null) { 18380 // Restore the cached Canvas for our siblings 18381 attachInfo.mCanvas = canvas; 18382 } 18383 } 18384 18385 /** 18386 * Create a snapshot of the view into a bitmap. We should probably make 18387 * some form of this public, but should think about the API. 18388 * 18389 * @hide 18390 */ 18391 public Bitmap createSnapshot(Bitmap.Config quality, int backgroundColor, boolean skipChildren) { 18392 int width = mRight - mLeft; 18393 int height = mBottom - mTop; 18394 18395 final AttachInfo attachInfo = mAttachInfo; 18396 final float scale = attachInfo != null ? attachInfo.mApplicationScale : 1.0f; 18397 width = (int) ((width * scale) + 0.5f); 18398 height = (int) ((height * scale) + 0.5f); 18399 18400 Bitmap bitmap = Bitmap.createBitmap(mResources.getDisplayMetrics(), 18401 width > 0 ? width : 1, height > 0 ? height : 1, quality); 18402 if (bitmap == null) { 18403 throw new OutOfMemoryError(); 18404 } 18405 18406 Resources resources = getResources(); 18407 if (resources != null) { 18408 bitmap.setDensity(resources.getDisplayMetrics().densityDpi); 18409 } 18410 18411 Canvas canvas; 18412 if (attachInfo != null) { 18413 canvas = attachInfo.mCanvas; 18414 if (canvas == null) { 18415 canvas = new Canvas(); 18416 } 18417 canvas.setBitmap(bitmap); 18418 // Temporarily clobber the cached Canvas in case one of our children 18419 // is also using a drawing cache. Without this, the children would 18420 // steal the canvas by attaching their own bitmap to it and bad, bad 18421 // things would happen (invisible views, corrupted drawings, etc.) 18422 attachInfo.mCanvas = null; 18423 } else { 18424 // This case should hopefully never or seldom happen 18425 canvas = new Canvas(bitmap); 18426 } 18427 boolean enabledHwBitmapsInSwMode = canvas.isHwBitmapsInSwModeEnabled(); 18428 canvas.setHwBitmapsInSwModeEnabled(true); 18429 if ((backgroundColor & 0xff000000) != 0) { 18430 bitmap.eraseColor(backgroundColor); 18431 } 18432 18433 computeScroll(); 18434 final int restoreCount = canvas.save(); 18435 canvas.scale(scale, scale); 18436 canvas.translate(-mScrollX, -mScrollY); 18437 18438 // Temporarily remove the dirty mask 18439 int flags = mPrivateFlags; 18440 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 18441 18442 // Fast path for layouts with no backgrounds 18443 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { 18444 dispatchDraw(canvas); 18445 drawAutofilledHighlight(canvas); 18446 if (mOverlay != null && !mOverlay.isEmpty()) { 18447 mOverlay.getOverlayView().draw(canvas); 18448 } 18449 } else { 18450 draw(canvas); 18451 } 18452 18453 mPrivateFlags = flags; 18454 18455 canvas.restoreToCount(restoreCount); 18456 canvas.setBitmap(null); 18457 canvas.setHwBitmapsInSwModeEnabled(enabledHwBitmapsInSwMode); 18458 18459 if (attachInfo != null) { 18460 // Restore the cached Canvas for our siblings 18461 attachInfo.mCanvas = canvas; 18462 } 18463 18464 return bitmap; 18465 } 18466 18467 /** 18468 * Indicates whether this View is currently in edit mode. A View is usually 18469 * in edit mode when displayed within a developer tool. For instance, if 18470 * this View is being drawn by a visual user interface builder, this method 18471 * should return true. 18472 * 18473 * Subclasses should check the return value of this method to provide 18474 * different behaviors if their normal behavior might interfere with the 18475 * host environment. For instance: the class spawns a thread in its 18476 * constructor, the drawing code relies on device-specific features, etc. 18477 * 18478 * This method is usually checked in the drawing code of custom widgets. 18479 * 18480 * @return True if this View is in edit mode, false otherwise. 18481 */ 18482 public boolean isInEditMode() { 18483 return false; 18484 } 18485 18486 /** 18487 * If the View draws content inside its padding and enables fading edges, 18488 * it needs to support padding offsets. Padding offsets are added to the 18489 * fading edges to extend the length of the fade so that it covers pixels 18490 * drawn inside the padding. 18491 * 18492 * Subclasses of this class should override this method if they need 18493 * to draw content inside the padding. 18494 * 18495 * @return True if padding offset must be applied, false otherwise. 18496 * 18497 * @see #getLeftPaddingOffset() 18498 * @see #getRightPaddingOffset() 18499 * @see #getTopPaddingOffset() 18500 * @see #getBottomPaddingOffset() 18501 * 18502 * @since CURRENT 18503 */ 18504 protected boolean isPaddingOffsetRequired() { 18505 return false; 18506 } 18507 18508 /** 18509 * Amount by which to extend the left fading region. Called only when 18510 * {@link #isPaddingOffsetRequired()} returns true. 18511 * 18512 * @return The left padding offset in pixels. 18513 * 18514 * @see #isPaddingOffsetRequired() 18515 * 18516 * @since CURRENT 18517 */ 18518 protected int getLeftPaddingOffset() { 18519 return 0; 18520 } 18521 18522 /** 18523 * Amount by which to extend the right fading region. Called only when 18524 * {@link #isPaddingOffsetRequired()} returns true. 18525 * 18526 * @return The right padding offset in pixels. 18527 * 18528 * @see #isPaddingOffsetRequired() 18529 * 18530 * @since CURRENT 18531 */ 18532 protected int getRightPaddingOffset() { 18533 return 0; 18534 } 18535 18536 /** 18537 * Amount by which to extend the top fading region. Called only when 18538 * {@link #isPaddingOffsetRequired()} returns true. 18539 * 18540 * @return The top padding offset in pixels. 18541 * 18542 * @see #isPaddingOffsetRequired() 18543 * 18544 * @since CURRENT 18545 */ 18546 protected int getTopPaddingOffset() { 18547 return 0; 18548 } 18549 18550 /** 18551 * Amount by which to extend the bottom fading region. Called only when 18552 * {@link #isPaddingOffsetRequired()} returns true. 18553 * 18554 * @return The bottom padding offset in pixels. 18555 * 18556 * @see #isPaddingOffsetRequired() 18557 * 18558 * @since CURRENT 18559 */ 18560 protected int getBottomPaddingOffset() { 18561 return 0; 18562 } 18563 18564 /** 18565 * @hide 18566 * @param offsetRequired 18567 */ 18568 protected int getFadeTop(boolean offsetRequired) { 18569 int top = mPaddingTop; 18570 if (offsetRequired) top += getTopPaddingOffset(); 18571 return top; 18572 } 18573 18574 /** 18575 * @hide 18576 * @param offsetRequired 18577 */ 18578 protected int getFadeHeight(boolean offsetRequired) { 18579 int padding = mPaddingTop; 18580 if (offsetRequired) padding += getTopPaddingOffset(); 18581 return mBottom - mTop - mPaddingBottom - padding; 18582 } 18583 18584 /** 18585 * <p>Indicates whether this view is attached to a hardware accelerated 18586 * window or not.</p> 18587 * 18588 * <p>Even if this method returns true, it does not mean that every call 18589 * to {@link #draw(android.graphics.Canvas)} will be made with an hardware 18590 * accelerated {@link android.graphics.Canvas}. For instance, if this view 18591 * is drawn onto an offscreen {@link android.graphics.Bitmap} and its 18592 * window is hardware accelerated, 18593 * {@link android.graphics.Canvas#isHardwareAccelerated()} will likely 18594 * return false, and this method will return true.</p> 18595 * 18596 * @return True if the view is attached to a window and the window is 18597 * hardware accelerated; false in any other case. 18598 */ 18599 @ViewDebug.ExportedProperty(category = "drawing") 18600 public boolean isHardwareAccelerated() { 18601 return mAttachInfo != null && mAttachInfo.mHardwareAccelerated; 18602 } 18603 18604 /** 18605 * Sets a rectangular area on this view to which the view will be clipped 18606 * when it is drawn. Setting the value to null will remove the clip bounds 18607 * and the view will draw normally, using its full bounds. 18608 * 18609 * @param clipBounds The rectangular area, in the local coordinates of 18610 * this view, to which future drawing operations will be clipped. 18611 */ 18612 public void setClipBounds(Rect clipBounds) { 18613 if (clipBounds == mClipBounds 18614 || (clipBounds != null && clipBounds.equals(mClipBounds))) { 18615 return; 18616 } 18617 if (clipBounds != null) { 18618 if (mClipBounds == null) { 18619 mClipBounds = new Rect(clipBounds); 18620 } else { 18621 mClipBounds.set(clipBounds); 18622 } 18623 } else { 18624 mClipBounds = null; 18625 } 18626 mRenderNode.setClipBounds(mClipBounds); 18627 invalidateViewProperty(false, false); 18628 } 18629 18630 /** 18631 * Returns a copy of the current {@link #setClipBounds(Rect) clipBounds}. 18632 * 18633 * @return A copy of the current clip bounds if clip bounds are set, 18634 * otherwise null. 18635 */ 18636 public Rect getClipBounds() { 18637 return (mClipBounds != null) ? new Rect(mClipBounds) : null; 18638 } 18639 18640 18641 /** 18642 * Populates an output rectangle with the clip bounds of the view, 18643 * returning {@code true} if successful or {@code false} if the view's 18644 * clip bounds are {@code null}. 18645 * 18646 * @param outRect rectangle in which to place the clip bounds of the view 18647 * @return {@code true} if successful or {@code false} if the view's 18648 * clip bounds are {@code null} 18649 */ 18650 public boolean getClipBounds(Rect outRect) { 18651 if (mClipBounds != null) { 18652 outRect.set(mClipBounds); 18653 return true; 18654 } 18655 return false; 18656 } 18657 18658 /** 18659 * Utility function, called by draw(canvas, parent, drawingTime) to handle the less common 18660 * case of an active Animation being run on the view. 18661 */ 18662 private boolean applyLegacyAnimation(ViewGroup parent, long drawingTime, 18663 Animation a, boolean scalingRequired) { 18664 Transformation invalidationTransform; 18665 final int flags = parent.mGroupFlags; 18666 final boolean initialized = a.isInitialized(); 18667 if (!initialized) { 18668 a.initialize(mRight - mLeft, mBottom - mTop, parent.getWidth(), parent.getHeight()); 18669 a.initializeInvalidateRegion(0, 0, mRight - mLeft, mBottom - mTop); 18670 if (mAttachInfo != null) a.setListenerHandler(mAttachInfo.mHandler); 18671 onAnimationStart(); 18672 } 18673 18674 final Transformation t = parent.getChildTransformation(); 18675 boolean more = a.getTransformation(drawingTime, t, 1f); 18676 if (scalingRequired && mAttachInfo.mApplicationScale != 1f) { 18677 if (parent.mInvalidationTransformation == null) { 18678 parent.mInvalidationTransformation = new Transformation(); 18679 } 18680 invalidationTransform = parent.mInvalidationTransformation; 18681 a.getTransformation(drawingTime, invalidationTransform, 1f); 18682 } else { 18683 invalidationTransform = t; 18684 } 18685 18686 if (more) { 18687 if (!a.willChangeBounds()) { 18688 if ((flags & (ViewGroup.FLAG_OPTIMIZE_INVALIDATE | ViewGroup.FLAG_ANIMATION_DONE)) == 18689 ViewGroup.FLAG_OPTIMIZE_INVALIDATE) { 18690 parent.mGroupFlags |= ViewGroup.FLAG_INVALIDATE_REQUIRED; 18691 } else if ((flags & ViewGroup.FLAG_INVALIDATE_REQUIRED) == 0) { 18692 // The child need to draw an animation, potentially offscreen, so 18693 // make sure we do not cancel invalidate requests 18694 parent.mPrivateFlags |= PFLAG_DRAW_ANIMATION; 18695 parent.invalidate(mLeft, mTop, mRight, mBottom); 18696 } 18697 } else { 18698 if (parent.mInvalidateRegion == null) { 18699 parent.mInvalidateRegion = new RectF(); 18700 } 18701 final RectF region = parent.mInvalidateRegion; 18702 a.getInvalidateRegion(0, 0, mRight - mLeft, mBottom - mTop, region, 18703 invalidationTransform); 18704 18705 // The child need to draw an animation, potentially offscreen, so 18706 // make sure we do not cancel invalidate requests 18707 parent.mPrivateFlags |= PFLAG_DRAW_ANIMATION; 18708 18709 final int left = mLeft + (int) region.left; 18710 final int top = mTop + (int) region.top; 18711 parent.invalidate(left, top, left + (int) (region.width() + .5f), 18712 top + (int) (region.height() + .5f)); 18713 } 18714 } 18715 return more; 18716 } 18717 18718 /** 18719 * This method is called by getDisplayList() when a display list is recorded for a View. 18720 * It pushes any properties to the RenderNode that aren't managed by the RenderNode. 18721 */ 18722 void setDisplayListProperties(RenderNode renderNode) { 18723 if (renderNode != null) { 18724 renderNode.setHasOverlappingRendering(getHasOverlappingRendering()); 18725 renderNode.setClipToBounds(mParent instanceof ViewGroup 18726 && ((ViewGroup) mParent).getClipChildren()); 18727 18728 float alpha = 1; 18729 if (mParent instanceof ViewGroup && (((ViewGroup) mParent).mGroupFlags & 18730 ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) != 0) { 18731 ViewGroup parentVG = (ViewGroup) mParent; 18732 final Transformation t = parentVG.getChildTransformation(); 18733 if (parentVG.getChildStaticTransformation(this, t)) { 18734 final int transformType = t.getTransformationType(); 18735 if (transformType != Transformation.TYPE_IDENTITY) { 18736 if ((transformType & Transformation.TYPE_ALPHA) != 0) { 18737 alpha = t.getAlpha(); 18738 } 18739 if ((transformType & Transformation.TYPE_MATRIX) != 0) { 18740 renderNode.setStaticMatrix(t.getMatrix()); 18741 } 18742 } 18743 } 18744 } 18745 if (mTransformationInfo != null) { 18746 alpha *= getFinalAlpha(); 18747 if (alpha < 1) { 18748 final int multipliedAlpha = (int) (255 * alpha); 18749 if (onSetAlpha(multipliedAlpha)) { 18750 alpha = 1; 18751 } 18752 } 18753 renderNode.setAlpha(alpha); 18754 } else if (alpha < 1) { 18755 renderNode.setAlpha(alpha); 18756 } 18757 } 18758 } 18759 18760 /** 18761 * This method is called by ViewGroup.drawChild() to have each child view draw itself. 18762 * 18763 * This is where the View specializes rendering behavior based on layer type, 18764 * and hardware acceleration. 18765 */ 18766 boolean draw(Canvas canvas, ViewGroup parent, long drawingTime) { 18767 final boolean hardwareAcceleratedCanvas = canvas.isHardwareAccelerated(); 18768 /* If an attached view draws to a HW canvas, it may use its RenderNode + DisplayList. 18769 * 18770 * If a view is dettached, its DisplayList shouldn't exist. If the canvas isn't 18771 * HW accelerated, it can't handle drawing RenderNodes. 18772 */ 18773 boolean drawingWithRenderNode = mAttachInfo != null 18774 && mAttachInfo.mHardwareAccelerated 18775 && hardwareAcceleratedCanvas; 18776 18777 boolean more = false; 18778 final boolean childHasIdentityMatrix = hasIdentityMatrix(); 18779 final int parentFlags = parent.mGroupFlags; 18780 18781 if ((parentFlags & ViewGroup.FLAG_CLEAR_TRANSFORMATION) != 0) { 18782 parent.getChildTransformation().clear(); 18783 parent.mGroupFlags &= ~ViewGroup.FLAG_CLEAR_TRANSFORMATION; 18784 } 18785 18786 Transformation transformToApply = null; 18787 boolean concatMatrix = false; 18788 final boolean scalingRequired = mAttachInfo != null && mAttachInfo.mScalingRequired; 18789 final Animation a = getAnimation(); 18790 if (a != null) { 18791 more = applyLegacyAnimation(parent, drawingTime, a, scalingRequired); 18792 concatMatrix = a.willChangeTransformationMatrix(); 18793 if (concatMatrix) { 18794 mPrivateFlags3 |= PFLAG3_VIEW_IS_ANIMATING_TRANSFORM; 18795 } 18796 transformToApply = parent.getChildTransformation(); 18797 } else { 18798 if ((mPrivateFlags3 & PFLAG3_VIEW_IS_ANIMATING_TRANSFORM) != 0) { 18799 // No longer animating: clear out old animation matrix 18800 mRenderNode.setAnimationMatrix(null); 18801 mPrivateFlags3 &= ~PFLAG3_VIEW_IS_ANIMATING_TRANSFORM; 18802 } 18803 if (!drawingWithRenderNode 18804 && (parentFlags & ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) != 0) { 18805 final Transformation t = parent.getChildTransformation(); 18806 final boolean hasTransform = parent.getChildStaticTransformation(this, t); 18807 if (hasTransform) { 18808 final int transformType = t.getTransformationType(); 18809 transformToApply = transformType != Transformation.TYPE_IDENTITY ? t : null; 18810 concatMatrix = (transformType & Transformation.TYPE_MATRIX) != 0; 18811 } 18812 } 18813 } 18814 18815 concatMatrix |= !childHasIdentityMatrix; 18816 18817 // Sets the flag as early as possible to allow draw() implementations 18818 // to call invalidate() successfully when doing animations 18819 mPrivateFlags |= PFLAG_DRAWN; 18820 18821 if (!concatMatrix && 18822 (parentFlags & (ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS | 18823 ViewGroup.FLAG_CLIP_CHILDREN)) == ViewGroup.FLAG_CLIP_CHILDREN && 18824 canvas.quickReject(mLeft, mTop, mRight, mBottom, Canvas.EdgeType.BW) && 18825 (mPrivateFlags & PFLAG_DRAW_ANIMATION) == 0) { 18826 mPrivateFlags2 |= PFLAG2_VIEW_QUICK_REJECTED; 18827 return more; 18828 } 18829 mPrivateFlags2 &= ~PFLAG2_VIEW_QUICK_REJECTED; 18830 18831 if (hardwareAcceleratedCanvas) { 18832 // Clear INVALIDATED flag to allow invalidation to occur during rendering, but 18833 // retain the flag's value temporarily in the mRecreateDisplayList flag 18834 mRecreateDisplayList = (mPrivateFlags & PFLAG_INVALIDATED) != 0; 18835 mPrivateFlags &= ~PFLAG_INVALIDATED; 18836 } 18837 18838 RenderNode renderNode = null; 18839 Bitmap cache = null; 18840 int layerType = getLayerType(); // TODO: signify cache state with just 'cache' local 18841 if (layerType == LAYER_TYPE_SOFTWARE || !drawingWithRenderNode) { 18842 if (layerType != LAYER_TYPE_NONE) { 18843 // If not drawing with RenderNode, treat HW layers as SW 18844 layerType = LAYER_TYPE_SOFTWARE; 18845 buildDrawingCache(true); 18846 } 18847 cache = getDrawingCache(true); 18848 } 18849 18850 if (drawingWithRenderNode) { 18851 // Delay getting the display list until animation-driven alpha values are 18852 // set up and possibly passed on to the view 18853 renderNode = updateDisplayListIfDirty(); 18854 if (!renderNode.isValid()) { 18855 // Uncommon, but possible. If a view is removed from the hierarchy during the call 18856 // to getDisplayList(), the display list will be marked invalid and we should not 18857 // try to use it again. 18858 renderNode = null; 18859 drawingWithRenderNode = false; 18860 } 18861 } 18862 18863 int sx = 0; 18864 int sy = 0; 18865 if (!drawingWithRenderNode) { 18866 computeScroll(); 18867 sx = mScrollX; 18868 sy = mScrollY; 18869 } 18870 18871 final boolean drawingWithDrawingCache = cache != null && !drawingWithRenderNode; 18872 final boolean offsetForScroll = cache == null && !drawingWithRenderNode; 18873 18874 int restoreTo = -1; 18875 if (!drawingWithRenderNode || transformToApply != null) { 18876 restoreTo = canvas.save(); 18877 } 18878 if (offsetForScroll) { 18879 canvas.translate(mLeft - sx, mTop - sy); 18880 } else { 18881 if (!drawingWithRenderNode) { 18882 canvas.translate(mLeft, mTop); 18883 } 18884 if (scalingRequired) { 18885 if (drawingWithRenderNode) { 18886 // TODO: Might not need this if we put everything inside the DL 18887 restoreTo = canvas.save(); 18888 } 18889 // mAttachInfo cannot be null, otherwise scalingRequired == false 18890 final float scale = 1.0f / mAttachInfo.mApplicationScale; 18891 canvas.scale(scale, scale); 18892 } 18893 } 18894 18895 float alpha = drawingWithRenderNode ? 1 : (getAlpha() * getTransitionAlpha()); 18896 if (transformToApply != null 18897 || alpha < 1 18898 || !hasIdentityMatrix() 18899 || (mPrivateFlags3 & PFLAG3_VIEW_IS_ANIMATING_ALPHA) != 0) { 18900 if (transformToApply != null || !childHasIdentityMatrix) { 18901 int transX = 0; 18902 int transY = 0; 18903 18904 if (offsetForScroll) { 18905 transX = -sx; 18906 transY = -sy; 18907 } 18908 18909 if (transformToApply != null) { 18910 if (concatMatrix) { 18911 if (drawingWithRenderNode) { 18912 renderNode.setAnimationMatrix(transformToApply.getMatrix()); 18913 } else { 18914 // Undo the scroll translation, apply the transformation matrix, 18915 // then redo the scroll translate to get the correct result. 18916 canvas.translate(-transX, -transY); 18917 canvas.concat(transformToApply.getMatrix()); 18918 canvas.translate(transX, transY); 18919 } 18920 parent.mGroupFlags |= ViewGroup.FLAG_CLEAR_TRANSFORMATION; 18921 } 18922 18923 float transformAlpha = transformToApply.getAlpha(); 18924 if (transformAlpha < 1) { 18925 alpha *= transformAlpha; 18926 parent.mGroupFlags |= ViewGroup.FLAG_CLEAR_TRANSFORMATION; 18927 } 18928 } 18929 18930 if (!childHasIdentityMatrix && !drawingWithRenderNode) { 18931 canvas.translate(-transX, -transY); 18932 canvas.concat(getMatrix()); 18933 canvas.translate(transX, transY); 18934 } 18935 } 18936 18937 // Deal with alpha if it is or used to be <1 18938 if (alpha < 1 || (mPrivateFlags3 & PFLAG3_VIEW_IS_ANIMATING_ALPHA) != 0) { 18939 if (alpha < 1) { 18940 mPrivateFlags3 |= PFLAG3_VIEW_IS_ANIMATING_ALPHA; 18941 } else { 18942 mPrivateFlags3 &= ~PFLAG3_VIEW_IS_ANIMATING_ALPHA; 18943 } 18944 parent.mGroupFlags |= ViewGroup.FLAG_CLEAR_TRANSFORMATION; 18945 if (!drawingWithDrawingCache) { 18946 final int multipliedAlpha = (int) (255 * alpha); 18947 if (!onSetAlpha(multipliedAlpha)) { 18948 if (drawingWithRenderNode) { 18949 renderNode.setAlpha(alpha * getAlpha() * getTransitionAlpha()); 18950 } else if (layerType == LAYER_TYPE_NONE) { 18951 canvas.saveLayerAlpha(sx, sy, sx + getWidth(), sy + getHeight(), 18952 multipliedAlpha); 18953 } 18954 } else { 18955 // Alpha is handled by the child directly, clobber the layer's alpha 18956 mPrivateFlags |= PFLAG_ALPHA_SET; 18957 } 18958 } 18959 } 18960 } else if ((mPrivateFlags & PFLAG_ALPHA_SET) == PFLAG_ALPHA_SET) { 18961 onSetAlpha(255); 18962 mPrivateFlags &= ~PFLAG_ALPHA_SET; 18963 } 18964 18965 if (!drawingWithRenderNode) { 18966 // apply clips directly, since RenderNode won't do it for this draw 18967 if ((parentFlags & ViewGroup.FLAG_CLIP_CHILDREN) != 0 && cache == null) { 18968 if (offsetForScroll) { 18969 canvas.clipRect(sx, sy, sx + getWidth(), sy + getHeight()); 18970 } else { 18971 if (!scalingRequired || cache == null) { 18972 canvas.clipRect(0, 0, getWidth(), getHeight()); 18973 } else { 18974 canvas.clipRect(0, 0, cache.getWidth(), cache.getHeight()); 18975 } 18976 } 18977 } 18978 18979 if (mClipBounds != null) { 18980 // clip bounds ignore scroll 18981 canvas.clipRect(mClipBounds); 18982 } 18983 } 18984 18985 if (!drawingWithDrawingCache) { 18986 if (drawingWithRenderNode) { 18987 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 18988 ((DisplayListCanvas) canvas).drawRenderNode(renderNode); 18989 } else { 18990 // Fast path for layouts with no backgrounds 18991 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { 18992 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 18993 dispatchDraw(canvas); 18994 } else { 18995 draw(canvas); 18996 } 18997 } 18998 } else if (cache != null) { 18999 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 19000 if (layerType == LAYER_TYPE_NONE || mLayerPaint == null) { 19001 // no layer paint, use temporary paint to draw bitmap 19002 Paint cachePaint = parent.mCachePaint; 19003 if (cachePaint == null) { 19004 cachePaint = new Paint(); 19005 cachePaint.setDither(false); 19006 parent.mCachePaint = cachePaint; 19007 } 19008 cachePaint.setAlpha((int) (alpha * 255)); 19009 canvas.drawBitmap(cache, 0.0f, 0.0f, cachePaint); 19010 } else { 19011 // use layer paint to draw the bitmap, merging the two alphas, but also restore 19012 int layerPaintAlpha = mLayerPaint.getAlpha(); 19013 if (alpha < 1) { 19014 mLayerPaint.setAlpha((int) (alpha * layerPaintAlpha)); 19015 } 19016 canvas.drawBitmap(cache, 0.0f, 0.0f, mLayerPaint); 19017 if (alpha < 1) { 19018 mLayerPaint.setAlpha(layerPaintAlpha); 19019 } 19020 } 19021 } 19022 19023 if (restoreTo >= 0) { 19024 canvas.restoreToCount(restoreTo); 19025 } 19026 19027 if (a != null && !more) { 19028 if (!hardwareAcceleratedCanvas && !a.getFillAfter()) { 19029 onSetAlpha(255); 19030 } 19031 parent.finishAnimatingView(this, a); 19032 } 19033 19034 if (more && hardwareAcceleratedCanvas) { 19035 if (a.hasAlpha() && (mPrivateFlags & PFLAG_ALPHA_SET) == PFLAG_ALPHA_SET) { 19036 // alpha animations should cause the child to recreate its display list 19037 invalidate(true); 19038 } 19039 } 19040 19041 mRecreateDisplayList = false; 19042 19043 return more; 19044 } 19045 19046 static Paint getDebugPaint() { 19047 if (sDebugPaint == null) { 19048 sDebugPaint = new Paint(); 19049 sDebugPaint.setAntiAlias(false); 19050 } 19051 return sDebugPaint; 19052 } 19053 19054 final int dipsToPixels(int dips) { 19055 float scale = getContext().getResources().getDisplayMetrics().density; 19056 return (int) (dips * scale + 0.5f); 19057 } 19058 19059 final private void debugDrawFocus(Canvas canvas) { 19060 if (isFocused()) { 19061 final int cornerSquareSize = dipsToPixels(DEBUG_CORNERS_SIZE_DIP); 19062 final int l = mScrollX; 19063 final int r = l + mRight - mLeft; 19064 final int t = mScrollY; 19065 final int b = t + mBottom - mTop; 19066 19067 final Paint paint = getDebugPaint(); 19068 paint.setColor(DEBUG_CORNERS_COLOR); 19069 19070 // Draw squares in corners. 19071 paint.setStyle(Paint.Style.FILL); 19072 canvas.drawRect(l, t, l + cornerSquareSize, t + cornerSquareSize, paint); 19073 canvas.drawRect(r - cornerSquareSize, t, r, t + cornerSquareSize, paint); 19074 canvas.drawRect(l, b - cornerSquareSize, l + cornerSquareSize, b, paint); 19075 canvas.drawRect(r - cornerSquareSize, b - cornerSquareSize, r, b, paint); 19076 19077 // Draw big X across the view. 19078 paint.setStyle(Paint.Style.STROKE); 19079 canvas.drawLine(l, t, r, b, paint); 19080 canvas.drawLine(l, b, r, t, paint); 19081 } 19082 } 19083 19084 /** 19085 * Manually render this view (and all of its children) to the given Canvas. 19086 * The view must have already done a full layout before this function is 19087 * called. When implementing a view, implement 19088 * {@link #onDraw(android.graphics.Canvas)} instead of overriding this method. 19089 * If you do need to override this method, call the superclass version. 19090 * 19091 * @param canvas The Canvas to which the View is rendered. 19092 */ 19093 @CallSuper 19094 public void draw(Canvas canvas) { 19095 final int privateFlags = mPrivateFlags; 19096 final boolean dirtyOpaque = (privateFlags & PFLAG_DIRTY_MASK) == PFLAG_DIRTY_OPAQUE && 19097 (mAttachInfo == null || !mAttachInfo.mIgnoreDirtyState); 19098 mPrivateFlags = (privateFlags & ~PFLAG_DIRTY_MASK) | PFLAG_DRAWN; 19099 19100 /* 19101 * Draw traversal performs several drawing steps which must be executed 19102 * in the appropriate order: 19103 * 19104 * 1. Draw the background 19105 * 2. If necessary, save the canvas' layers to prepare for fading 19106 * 3. Draw view's content 19107 * 4. Draw children 19108 * 5. If necessary, draw the fading edges and restore layers 19109 * 6. Draw decorations (scrollbars for instance) 19110 */ 19111 19112 // Step 1, draw the background, if needed 19113 int saveCount; 19114 19115 if (!dirtyOpaque) { 19116 drawBackground(canvas); 19117 } 19118 19119 // skip step 2 & 5 if possible (common case) 19120 final int viewFlags = mViewFlags; 19121 boolean horizontalEdges = (viewFlags & FADING_EDGE_HORIZONTAL) != 0; 19122 boolean verticalEdges = (viewFlags & FADING_EDGE_VERTICAL) != 0; 19123 if (!verticalEdges && !horizontalEdges) { 19124 // Step 3, draw the content 19125 if (!dirtyOpaque) onDraw(canvas); 19126 19127 // Step 4, draw the children 19128 dispatchDraw(canvas); 19129 19130 drawAutofilledHighlight(canvas); 19131 19132 // Overlay is part of the content and draws beneath Foreground 19133 if (mOverlay != null && !mOverlay.isEmpty()) { 19134 mOverlay.getOverlayView().dispatchDraw(canvas); 19135 } 19136 19137 // Step 6, draw decorations (foreground, scrollbars) 19138 onDrawForeground(canvas); 19139 19140 // Step 7, draw the default focus highlight 19141 drawDefaultFocusHighlight(canvas); 19142 19143 if (debugDraw()) { 19144 debugDrawFocus(canvas); 19145 } 19146 19147 // we're done... 19148 return; 19149 } 19150 19151 /* 19152 * Here we do the full fledged routine... 19153 * (this is an uncommon case where speed matters less, 19154 * this is why we repeat some of the tests that have been 19155 * done above) 19156 */ 19157 19158 boolean drawTop = false; 19159 boolean drawBottom = false; 19160 boolean drawLeft = false; 19161 boolean drawRight = false; 19162 19163 float topFadeStrength = 0.0f; 19164 float bottomFadeStrength = 0.0f; 19165 float leftFadeStrength = 0.0f; 19166 float rightFadeStrength = 0.0f; 19167 19168 // Step 2, save the canvas' layers 19169 int paddingLeft = mPaddingLeft; 19170 19171 final boolean offsetRequired = isPaddingOffsetRequired(); 19172 if (offsetRequired) { 19173 paddingLeft += getLeftPaddingOffset(); 19174 } 19175 19176 int left = mScrollX + paddingLeft; 19177 int right = left + mRight - mLeft - mPaddingRight - paddingLeft; 19178 int top = mScrollY + getFadeTop(offsetRequired); 19179 int bottom = top + getFadeHeight(offsetRequired); 19180 19181 if (offsetRequired) { 19182 right += getRightPaddingOffset(); 19183 bottom += getBottomPaddingOffset(); 19184 } 19185 19186 final ScrollabilityCache scrollabilityCache = mScrollCache; 19187 final float fadeHeight = scrollabilityCache.fadingEdgeLength; 19188 int length = (int) fadeHeight; 19189 19190 // clip the fade length if top and bottom fades overlap 19191 // overlapping fades produce odd-looking artifacts 19192 if (verticalEdges && (top + length > bottom - length)) { 19193 length = (bottom - top) / 2; 19194 } 19195 19196 // also clip horizontal fades if necessary 19197 if (horizontalEdges && (left + length > right - length)) { 19198 length = (right - left) / 2; 19199 } 19200 19201 if (verticalEdges) { 19202 topFadeStrength = Math.max(0.0f, Math.min(1.0f, getTopFadingEdgeStrength())); 19203 drawTop = topFadeStrength * fadeHeight > 1.0f; 19204 bottomFadeStrength = Math.max(0.0f, Math.min(1.0f, getBottomFadingEdgeStrength())); 19205 drawBottom = bottomFadeStrength * fadeHeight > 1.0f; 19206 } 19207 19208 if (horizontalEdges) { 19209 leftFadeStrength = Math.max(0.0f, Math.min(1.0f, getLeftFadingEdgeStrength())); 19210 drawLeft = leftFadeStrength * fadeHeight > 1.0f; 19211 rightFadeStrength = Math.max(0.0f, Math.min(1.0f, getRightFadingEdgeStrength())); 19212 drawRight = rightFadeStrength * fadeHeight > 1.0f; 19213 } 19214 19215 saveCount = canvas.getSaveCount(); 19216 19217 int solidColor = getSolidColor(); 19218 if (solidColor == 0) { 19219 final int flags = Canvas.HAS_ALPHA_LAYER_SAVE_FLAG; 19220 19221 if (drawTop) { 19222 canvas.saveLayer(left, top, right, top + length, null, flags); 19223 } 19224 19225 if (drawBottom) { 19226 canvas.saveLayer(left, bottom - length, right, bottom, null, flags); 19227 } 19228 19229 if (drawLeft) { 19230 canvas.saveLayer(left, top, left + length, bottom, null, flags); 19231 } 19232 19233 if (drawRight) { 19234 canvas.saveLayer(right - length, top, right, bottom, null, flags); 19235 } 19236 } else { 19237 scrollabilityCache.setFadeColor(solidColor); 19238 } 19239 19240 // Step 3, draw the content 19241 if (!dirtyOpaque) onDraw(canvas); 19242 19243 // Step 4, draw the children 19244 dispatchDraw(canvas); 19245 19246 // Step 5, draw the fade effect and restore layers 19247 final Paint p = scrollabilityCache.paint; 19248 final Matrix matrix = scrollabilityCache.matrix; 19249 final Shader fade = scrollabilityCache.shader; 19250 19251 if (drawTop) { 19252 matrix.setScale(1, fadeHeight * topFadeStrength); 19253 matrix.postTranslate(left, top); 19254 fade.setLocalMatrix(matrix); 19255 p.setShader(fade); 19256 canvas.drawRect(left, top, right, top + length, p); 19257 } 19258 19259 if (drawBottom) { 19260 matrix.setScale(1, fadeHeight * bottomFadeStrength); 19261 matrix.postRotate(180); 19262 matrix.postTranslate(left, bottom); 19263 fade.setLocalMatrix(matrix); 19264 p.setShader(fade); 19265 canvas.drawRect(left, bottom - length, right, bottom, p); 19266 } 19267 19268 if (drawLeft) { 19269 matrix.setScale(1, fadeHeight * leftFadeStrength); 19270 matrix.postRotate(-90); 19271 matrix.postTranslate(left, top); 19272 fade.setLocalMatrix(matrix); 19273 p.setShader(fade); 19274 canvas.drawRect(left, top, left + length, bottom, p); 19275 } 19276 19277 if (drawRight) { 19278 matrix.setScale(1, fadeHeight * rightFadeStrength); 19279 matrix.postRotate(90); 19280 matrix.postTranslate(right, top); 19281 fade.setLocalMatrix(matrix); 19282 p.setShader(fade); 19283 canvas.drawRect(right - length, top, right, bottom, p); 19284 } 19285 19286 canvas.restoreToCount(saveCount); 19287 19288 drawAutofilledHighlight(canvas); 19289 19290 // Overlay is part of the content and draws beneath Foreground 19291 if (mOverlay != null && !mOverlay.isEmpty()) { 19292 mOverlay.getOverlayView().dispatchDraw(canvas); 19293 } 19294 19295 // Step 6, draw decorations (foreground, scrollbars) 19296 onDrawForeground(canvas); 19297 19298 if (debugDraw()) { 19299 debugDrawFocus(canvas); 19300 } 19301 } 19302 19303 /** 19304 * Draws the background onto the specified canvas. 19305 * 19306 * @param canvas Canvas on which to draw the background 19307 */ 19308 private void drawBackground(Canvas canvas) { 19309 final Drawable background = mBackground; 19310 if (background == null) { 19311 return; 19312 } 19313 19314 setBackgroundBounds(); 19315 19316 // Attempt to use a display list if requested. 19317 if (canvas.isHardwareAccelerated() && mAttachInfo != null 19318 && mAttachInfo.mThreadedRenderer != null) { 19319 mBackgroundRenderNode = getDrawableRenderNode(background, mBackgroundRenderNode); 19320 19321 final RenderNode renderNode = mBackgroundRenderNode; 19322 if (renderNode != null && renderNode.isValid()) { 19323 setBackgroundRenderNodeProperties(renderNode); 19324 ((DisplayListCanvas) canvas).drawRenderNode(renderNode); 19325 return; 19326 } 19327 } 19328 19329 final int scrollX = mScrollX; 19330 final int scrollY = mScrollY; 19331 if ((scrollX | scrollY) == 0) { 19332 background.draw(canvas); 19333 } else { 19334 canvas.translate(scrollX, scrollY); 19335 background.draw(canvas); 19336 canvas.translate(-scrollX, -scrollY); 19337 } 19338 } 19339 19340 /** 19341 * Sets the correct background bounds and rebuilds the outline, if needed. 19342 * <p/> 19343 * This is called by LayoutLib. 19344 */ 19345 void setBackgroundBounds() { 19346 if (mBackgroundSizeChanged && mBackground != null) { 19347 mBackground.setBounds(0, 0, mRight - mLeft, mBottom - mTop); 19348 mBackgroundSizeChanged = false; 19349 rebuildOutline(); 19350 } 19351 } 19352 19353 private void setBackgroundRenderNodeProperties(RenderNode renderNode) { 19354 renderNode.setTranslationX(mScrollX); 19355 renderNode.setTranslationY(mScrollY); 19356 } 19357 19358 /** 19359 * Creates a new display list or updates the existing display list for the 19360 * specified Drawable. 19361 * 19362 * @param drawable Drawable for which to create a display list 19363 * @param renderNode Existing RenderNode, or {@code null} 19364 * @return A valid display list for the specified drawable 19365 */ 19366 private RenderNode getDrawableRenderNode(Drawable drawable, RenderNode renderNode) { 19367 if (renderNode == null) { 19368 renderNode = RenderNode.create(drawable.getClass().getName(), this); 19369 } 19370 19371 final Rect bounds = drawable.getBounds(); 19372 final int width = bounds.width(); 19373 final int height = bounds.height(); 19374 final DisplayListCanvas canvas = renderNode.start(width, height); 19375 19376 // Reverse left/top translation done by drawable canvas, which will 19377 // instead be applied by rendernode's LTRB bounds below. This way, the 19378 // drawable's bounds match with its rendernode bounds and its content 19379 // will lie within those bounds in the rendernode tree. 19380 canvas.translate(-bounds.left, -bounds.top); 19381 19382 try { 19383 drawable.draw(canvas); 19384 } finally { 19385 renderNode.end(canvas); 19386 } 19387 19388 // Set up drawable properties that are view-independent. 19389 renderNode.setLeftTopRightBottom(bounds.left, bounds.top, bounds.right, bounds.bottom); 19390 renderNode.setProjectBackwards(drawable.isProjected()); 19391 renderNode.setProjectionReceiver(true); 19392 renderNode.setClipToBounds(false); 19393 return renderNode; 19394 } 19395 19396 /** 19397 * Returns the overlay for this view, creating it if it does not yet exist. 19398 * Adding drawables to the overlay will cause them to be displayed whenever 19399 * the view itself is redrawn. Objects in the overlay should be actively 19400 * managed: remove them when they should not be displayed anymore. The 19401 * overlay will always have the same size as its host view. 19402 * 19403 * <p>Note: Overlays do not currently work correctly with {@link 19404 * SurfaceView} or {@link TextureView}; contents in overlays for these 19405 * types of views may not display correctly.</p> 19406 * 19407 * @return The ViewOverlay object for this view. 19408 * @see ViewOverlay 19409 */ 19410 public ViewOverlay getOverlay() { 19411 if (mOverlay == null) { 19412 mOverlay = new ViewOverlay(mContext, this); 19413 } 19414 return mOverlay; 19415 } 19416 19417 /** 19418 * Override this if your view is known to always be drawn on top of a solid color background, 19419 * and needs to draw fading edges. Returning a non-zero color enables the view system to 19420 * optimize the drawing of the fading edges. If you do return a non-zero color, the alpha 19421 * should be set to 0xFF. 19422 * 19423 * @see #setVerticalFadingEdgeEnabled(boolean) 19424 * @see #setHorizontalFadingEdgeEnabled(boolean) 19425 * 19426 * @return The known solid color background for this view, or 0 if the color may vary 19427 */ 19428 @ViewDebug.ExportedProperty(category = "drawing") 19429 @ColorInt 19430 public int getSolidColor() { 19431 return 0; 19432 } 19433 19434 /** 19435 * Build a human readable string representation of the specified view flags. 19436 * 19437 * @param flags the view flags to convert to a string 19438 * @return a String representing the supplied flags 19439 */ 19440 private static String printFlags(int flags) { 19441 String output = ""; 19442 int numFlags = 0; 19443 if ((flags & FOCUSABLE) == FOCUSABLE) { 19444 output += "TAKES_FOCUS"; 19445 numFlags++; 19446 } 19447 19448 switch (flags & VISIBILITY_MASK) { 19449 case INVISIBLE: 19450 if (numFlags > 0) { 19451 output += " "; 19452 } 19453 output += "INVISIBLE"; 19454 // USELESS HERE numFlags++; 19455 break; 19456 case GONE: 19457 if (numFlags > 0) { 19458 output += " "; 19459 } 19460 output += "GONE"; 19461 // USELESS HERE numFlags++; 19462 break; 19463 default: 19464 break; 19465 } 19466 return output; 19467 } 19468 19469 /** 19470 * Build a human readable string representation of the specified private 19471 * view flags. 19472 * 19473 * @param privateFlags the private view flags to convert to a string 19474 * @return a String representing the supplied flags 19475 */ 19476 private static String printPrivateFlags(int privateFlags) { 19477 String output = ""; 19478 int numFlags = 0; 19479 19480 if ((privateFlags & PFLAG_WANTS_FOCUS) == PFLAG_WANTS_FOCUS) { 19481 output += "WANTS_FOCUS"; 19482 numFlags++; 19483 } 19484 19485 if ((privateFlags & PFLAG_FOCUSED) == PFLAG_FOCUSED) { 19486 if (numFlags > 0) { 19487 output += " "; 19488 } 19489 output += "FOCUSED"; 19490 numFlags++; 19491 } 19492 19493 if ((privateFlags & PFLAG_SELECTED) == PFLAG_SELECTED) { 19494 if (numFlags > 0) { 19495 output += " "; 19496 } 19497 output += "SELECTED"; 19498 numFlags++; 19499 } 19500 19501 if ((privateFlags & PFLAG_IS_ROOT_NAMESPACE) == PFLAG_IS_ROOT_NAMESPACE) { 19502 if (numFlags > 0) { 19503 output += " "; 19504 } 19505 output += "IS_ROOT_NAMESPACE"; 19506 numFlags++; 19507 } 19508 19509 if ((privateFlags & PFLAG_HAS_BOUNDS) == PFLAG_HAS_BOUNDS) { 19510 if (numFlags > 0) { 19511 output += " "; 19512 } 19513 output += "HAS_BOUNDS"; 19514 numFlags++; 19515 } 19516 19517 if ((privateFlags & PFLAG_DRAWN) == PFLAG_DRAWN) { 19518 if (numFlags > 0) { 19519 output += " "; 19520 } 19521 output += "DRAWN"; 19522 // USELESS HERE numFlags++; 19523 } 19524 return output; 19525 } 19526 19527 /** 19528 * <p>Indicates whether or not this view's layout will be requested during 19529 * the next hierarchy layout pass.</p> 19530 * 19531 * @return true if the layout will be forced during next layout pass 19532 */ 19533 public boolean isLayoutRequested() { 19534 return (mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT; 19535 } 19536 19537 /** 19538 * Return true if o is a ViewGroup that is laying out using optical bounds. 19539 * @hide 19540 */ 19541 public static boolean isLayoutModeOptical(Object o) { 19542 return o instanceof ViewGroup && ((ViewGroup) o).isLayoutModeOptical(); 19543 } 19544 19545 private boolean setOpticalFrame(int left, int top, int right, int bottom) { 19546 Insets parentInsets = mParent instanceof View ? 19547 ((View) mParent).getOpticalInsets() : Insets.NONE; 19548 Insets childInsets = getOpticalInsets(); 19549 return setFrame( 19550 left + parentInsets.left - childInsets.left, 19551 top + parentInsets.top - childInsets.top, 19552 right + parentInsets.left + childInsets.right, 19553 bottom + parentInsets.top + childInsets.bottom); 19554 } 19555 19556 /** 19557 * Assign a size and position to a view and all of its 19558 * descendants 19559 * 19560 * <p>This is the second phase of the layout mechanism. 19561 * (The first is measuring). In this phase, each parent calls 19562 * layout on all of its children to position them. 19563 * This is typically done using the child measurements 19564 * that were stored in the measure pass().</p> 19565 * 19566 * <p>Derived classes should not override this method. 19567 * Derived classes with children should override 19568 * onLayout. In that method, they should 19569 * call layout on each of their children.</p> 19570 * 19571 * @param l Left position, relative to parent 19572 * @param t Top position, relative to parent 19573 * @param r Right position, relative to parent 19574 * @param b Bottom position, relative to parent 19575 */ 19576 @SuppressWarnings({"unchecked"}) 19577 public void layout(int l, int t, int r, int b) { 19578 if ((mPrivateFlags3 & PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT) != 0) { 19579 onMeasure(mOldWidthMeasureSpec, mOldHeightMeasureSpec); 19580 mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT; 19581 } 19582 19583 int oldL = mLeft; 19584 int oldT = mTop; 19585 int oldB = mBottom; 19586 int oldR = mRight; 19587 19588 boolean changed = isLayoutModeOptical(mParent) ? 19589 setOpticalFrame(l, t, r, b) : setFrame(l, t, r, b); 19590 19591 if (changed || (mPrivateFlags & PFLAG_LAYOUT_REQUIRED) == PFLAG_LAYOUT_REQUIRED) { 19592 onLayout(changed, l, t, r, b); 19593 19594 if (shouldDrawRoundScrollbar()) { 19595 if(mRoundScrollbarRenderer == null) { 19596 mRoundScrollbarRenderer = new RoundScrollbarRenderer(this); 19597 } 19598 } else { 19599 mRoundScrollbarRenderer = null; 19600 } 19601 19602 mPrivateFlags &= ~PFLAG_LAYOUT_REQUIRED; 19603 19604 ListenerInfo li = mListenerInfo; 19605 if (li != null && li.mOnLayoutChangeListeners != null) { 19606 ArrayList<OnLayoutChangeListener> listenersCopy = 19607 (ArrayList<OnLayoutChangeListener>)li.mOnLayoutChangeListeners.clone(); 19608 int numListeners = listenersCopy.size(); 19609 for (int i = 0; i < numListeners; ++i) { 19610 listenersCopy.get(i).onLayoutChange(this, l, t, r, b, oldL, oldT, oldR, oldB); 19611 } 19612 } 19613 } 19614 19615 mPrivateFlags &= ~PFLAG_FORCE_LAYOUT; 19616 mPrivateFlags3 |= PFLAG3_IS_LAID_OUT; 19617 19618 if ((mPrivateFlags3 & PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT) != 0) { 19619 mPrivateFlags3 &= ~PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT; 19620 notifyEnterOrExitForAutoFillIfNeeded(true); 19621 } 19622 } 19623 19624 /** 19625 * Called from layout when this view should 19626 * assign a size and position to each of its children. 19627 * 19628 * Derived classes with children should override 19629 * this method and call layout on each of 19630 * their children. 19631 * @param changed This is a new size or position for this view 19632 * @param left Left position, relative to parent 19633 * @param top Top position, relative to parent 19634 * @param right Right position, relative to parent 19635 * @param bottom Bottom position, relative to parent 19636 */ 19637 protected void onLayout(boolean changed, int left, int top, int right, int bottom) { 19638 } 19639 19640 /** 19641 * Assign a size and position to this view. 19642 * 19643 * This is called from layout. 19644 * 19645 * @param left Left position, relative to parent 19646 * @param top Top position, relative to parent 19647 * @param right Right position, relative to parent 19648 * @param bottom Bottom position, relative to parent 19649 * @return true if the new size and position are different than the 19650 * previous ones 19651 * {@hide} 19652 */ 19653 protected boolean setFrame(int left, int top, int right, int bottom) { 19654 boolean changed = false; 19655 19656 if (DBG) { 19657 Log.d("View", this + " View.setFrame(" + left + "," + top + "," 19658 + right + "," + bottom + ")"); 19659 } 19660 19661 if (mLeft != left || mRight != right || mTop != top || mBottom != bottom) { 19662 changed = true; 19663 19664 // Remember our drawn bit 19665 int drawn = mPrivateFlags & PFLAG_DRAWN; 19666 19667 int oldWidth = mRight - mLeft; 19668 int oldHeight = mBottom - mTop; 19669 int newWidth = right - left; 19670 int newHeight = bottom - top; 19671 boolean sizeChanged = (newWidth != oldWidth) || (newHeight != oldHeight); 19672 19673 // Invalidate our old position 19674 invalidate(sizeChanged); 19675 19676 mLeft = left; 19677 mTop = top; 19678 mRight = right; 19679 mBottom = bottom; 19680 mRenderNode.setLeftTopRightBottom(mLeft, mTop, mRight, mBottom); 19681 19682 mPrivateFlags |= PFLAG_HAS_BOUNDS; 19683 19684 19685 if (sizeChanged) { 19686 sizeChange(newWidth, newHeight, oldWidth, oldHeight); 19687 } 19688 19689 if ((mViewFlags & VISIBILITY_MASK) == VISIBLE || mGhostView != null) { 19690 // If we are visible, force the DRAWN bit to on so that 19691 // this invalidate will go through (at least to our parent). 19692 // This is because someone may have invalidated this view 19693 // before this call to setFrame came in, thereby clearing 19694 // the DRAWN bit. 19695 mPrivateFlags |= PFLAG_DRAWN; 19696 invalidate(sizeChanged); 19697 // parent display list may need to be recreated based on a change in the bounds 19698 // of any child 19699 invalidateParentCaches(); 19700 } 19701 19702 // Reset drawn bit to original value (invalidate turns it off) 19703 mPrivateFlags |= drawn; 19704 19705 mBackgroundSizeChanged = true; 19706 mDefaultFocusHighlightSizeChanged = true; 19707 if (mForegroundInfo != null) { 19708 mForegroundInfo.mBoundsChanged = true; 19709 } 19710 19711 notifySubtreeAccessibilityStateChangedIfNeeded(); 19712 } 19713 return changed; 19714 } 19715 19716 /** 19717 * Same as setFrame, but public and hidden. For use in {@link android.transition.ChangeBounds}. 19718 * @hide 19719 */ 19720 public void setLeftTopRightBottom(int left, int top, int right, int bottom) { 19721 setFrame(left, top, right, bottom); 19722 } 19723 19724 private void sizeChange(int newWidth, int newHeight, int oldWidth, int oldHeight) { 19725 onSizeChanged(newWidth, newHeight, oldWidth, oldHeight); 19726 if (mOverlay != null) { 19727 mOverlay.getOverlayView().setRight(newWidth); 19728 mOverlay.getOverlayView().setBottom(newHeight); 19729 } 19730 rebuildOutline(); 19731 } 19732 19733 /** 19734 * Finalize inflating a view from XML. This is called as the last phase 19735 * of inflation, after all child views have been added. 19736 * 19737 * <p>Even if the subclass overrides onFinishInflate, they should always be 19738 * sure to call the super method, so that we get called. 19739 */ 19740 @CallSuper 19741 protected void onFinishInflate() { 19742 } 19743 19744 /** 19745 * Returns the resources associated with this view. 19746 * 19747 * @return Resources object. 19748 */ 19749 public Resources getResources() { 19750 return mResources; 19751 } 19752 19753 /** 19754 * Invalidates the specified Drawable. 19755 * 19756 * @param drawable the drawable to invalidate 19757 */ 19758 @Override 19759 public void invalidateDrawable(@NonNull Drawable drawable) { 19760 if (verifyDrawable(drawable)) { 19761 final Rect dirty = drawable.getDirtyBounds(); 19762 final int scrollX = mScrollX; 19763 final int scrollY = mScrollY; 19764 19765 invalidate(dirty.left + scrollX, dirty.top + scrollY, 19766 dirty.right + scrollX, dirty.bottom + scrollY); 19767 rebuildOutline(); 19768 } 19769 } 19770 19771 /** 19772 * Schedules an action on a drawable to occur at a specified time. 19773 * 19774 * @param who the recipient of the action 19775 * @param what the action to run on the drawable 19776 * @param when the time at which the action must occur. Uses the 19777 * {@link SystemClock#uptimeMillis} timebase. 19778 */ 19779 @Override 19780 public void scheduleDrawable(@NonNull Drawable who, @NonNull Runnable what, long when) { 19781 if (verifyDrawable(who) && what != null) { 19782 final long delay = when - SystemClock.uptimeMillis(); 19783 if (mAttachInfo != null) { 19784 mAttachInfo.mViewRootImpl.mChoreographer.postCallbackDelayed( 19785 Choreographer.CALLBACK_ANIMATION, what, who, 19786 Choreographer.subtractFrameDelay(delay)); 19787 } else { 19788 // Postpone the runnable until we know 19789 // on which thread it needs to run. 19790 getRunQueue().postDelayed(what, delay); 19791 } 19792 } 19793 } 19794 19795 /** 19796 * Cancels a scheduled action on a drawable. 19797 * 19798 * @param who the recipient of the action 19799 * @param what the action to cancel 19800 */ 19801 @Override 19802 public void unscheduleDrawable(@NonNull Drawable who, @NonNull Runnable what) { 19803 if (verifyDrawable(who) && what != null) { 19804 if (mAttachInfo != null) { 19805 mAttachInfo.mViewRootImpl.mChoreographer.removeCallbacks( 19806 Choreographer.CALLBACK_ANIMATION, what, who); 19807 } 19808 getRunQueue().removeCallbacks(what); 19809 } 19810 } 19811 19812 /** 19813 * Unschedule any events associated with the given Drawable. This can be 19814 * used when selecting a new Drawable into a view, so that the previous 19815 * one is completely unscheduled. 19816 * 19817 * @param who The Drawable to unschedule. 19818 * 19819 * @see #drawableStateChanged 19820 */ 19821 public void unscheduleDrawable(Drawable who) { 19822 if (mAttachInfo != null && who != null) { 19823 mAttachInfo.mViewRootImpl.mChoreographer.removeCallbacks( 19824 Choreographer.CALLBACK_ANIMATION, null, who); 19825 } 19826 } 19827 19828 /** 19829 * Resolve the Drawables depending on the layout direction. This is implicitly supposing 19830 * that the View directionality can and will be resolved before its Drawables. 19831 * 19832 * Will call {@link View#onResolveDrawables} when resolution is done. 19833 * 19834 * @hide 19835 */ 19836 protected void resolveDrawables() { 19837 // Drawables resolution may need to happen before resolving the layout direction (which is 19838 // done only during the measure() call). 19839 // If the layout direction is not resolved yet, we cannot resolve the Drawables except in 19840 // one case: when the raw layout direction has not been defined as LAYOUT_DIRECTION_INHERIT. 19841 // So, if the raw layout direction is LAYOUT_DIRECTION_LTR or LAYOUT_DIRECTION_RTL or 19842 // LAYOUT_DIRECTION_LOCALE, we can "cheat" and we don't need to wait for the layout 19843 // direction to be resolved as its resolved value will be the same as its raw value. 19844 if (!isLayoutDirectionResolved() && 19845 getRawLayoutDirection() == View.LAYOUT_DIRECTION_INHERIT) { 19846 return; 19847 } 19848 19849 final int layoutDirection = isLayoutDirectionResolved() ? 19850 getLayoutDirection() : getRawLayoutDirection(); 19851 19852 if (mBackground != null) { 19853 mBackground.setLayoutDirection(layoutDirection); 19854 } 19855 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null) { 19856 mForegroundInfo.mDrawable.setLayoutDirection(layoutDirection); 19857 } 19858 if (mDefaultFocusHighlight != null) { 19859 mDefaultFocusHighlight.setLayoutDirection(layoutDirection); 19860 } 19861 mPrivateFlags2 |= PFLAG2_DRAWABLE_RESOLVED; 19862 onResolveDrawables(layoutDirection); 19863 } 19864 19865 boolean areDrawablesResolved() { 19866 return (mPrivateFlags2 & PFLAG2_DRAWABLE_RESOLVED) == PFLAG2_DRAWABLE_RESOLVED; 19867 } 19868 19869 /** 19870 * Called when layout direction has been resolved. 19871 * 19872 * The default implementation does nothing. 19873 * 19874 * @param layoutDirection The resolved layout direction. 19875 * 19876 * @see #LAYOUT_DIRECTION_LTR 19877 * @see #LAYOUT_DIRECTION_RTL 19878 * 19879 * @hide 19880 */ 19881 public void onResolveDrawables(@ResolvedLayoutDir int layoutDirection) { 19882 } 19883 19884 /** 19885 * @hide 19886 */ 19887 protected void resetResolvedDrawables() { 19888 resetResolvedDrawablesInternal(); 19889 } 19890 19891 void resetResolvedDrawablesInternal() { 19892 mPrivateFlags2 &= ~PFLAG2_DRAWABLE_RESOLVED; 19893 } 19894 19895 /** 19896 * If your view subclass is displaying its own Drawable objects, it should 19897 * override this function and return true for any Drawable it is 19898 * displaying. This allows animations for those drawables to be 19899 * scheduled. 19900 * 19901 * <p>Be sure to call through to the super class when overriding this 19902 * function. 19903 * 19904 * @param who The Drawable to verify. Return true if it is one you are 19905 * displaying, else return the result of calling through to the 19906 * super class. 19907 * 19908 * @return boolean If true than the Drawable is being displayed in the 19909 * view; else false and it is not allowed to animate. 19910 * 19911 * @see #unscheduleDrawable(android.graphics.drawable.Drawable) 19912 * @see #drawableStateChanged() 19913 */ 19914 @CallSuper 19915 protected boolean verifyDrawable(@NonNull Drawable who) { 19916 // Avoid verifying the scroll bar drawable so that we don't end up in 19917 // an invalidation loop. This effectively prevents the scroll bar 19918 // drawable from triggering invalidations and scheduling runnables. 19919 return who == mBackground || (mForegroundInfo != null && mForegroundInfo.mDrawable == who) 19920 || (mDefaultFocusHighlight == who); 19921 } 19922 19923 /** 19924 * This function is called whenever the state of the view changes in such 19925 * a way that it impacts the state of drawables being shown. 19926 * <p> 19927 * If the View has a StateListAnimator, it will also be called to run necessary state 19928 * change animations. 19929 * <p> 19930 * Be sure to call through to the superclass when overriding this function. 19931 * 19932 * @see Drawable#setState(int[]) 19933 */ 19934 @CallSuper 19935 protected void drawableStateChanged() { 19936 final int[] state = getDrawableState(); 19937 boolean changed = false; 19938 19939 final Drawable bg = mBackground; 19940 if (bg != null && bg.isStateful()) { 19941 changed |= bg.setState(state); 19942 } 19943 19944 final Drawable hl = mDefaultFocusHighlight; 19945 if (hl != null && hl.isStateful()) { 19946 changed |= hl.setState(state); 19947 } 19948 19949 final Drawable fg = mForegroundInfo != null ? mForegroundInfo.mDrawable : null; 19950 if (fg != null && fg.isStateful()) { 19951 changed |= fg.setState(state); 19952 } 19953 19954 if (mScrollCache != null) { 19955 final Drawable scrollBar = mScrollCache.scrollBar; 19956 if (scrollBar != null && scrollBar.isStateful()) { 19957 changed |= scrollBar.setState(state) 19958 && mScrollCache.state != ScrollabilityCache.OFF; 19959 } 19960 } 19961 19962 if (mStateListAnimator != null) { 19963 mStateListAnimator.setState(state); 19964 } 19965 19966 if (changed) { 19967 invalidate(); 19968 } 19969 } 19970 19971 /** 19972 * This function is called whenever the view hotspot changes and needs to 19973 * be propagated to drawables or child views managed by the view. 19974 * <p> 19975 * Dispatching to child views is handled by 19976 * {@link #dispatchDrawableHotspotChanged(float, float)}. 19977 * <p> 19978 * Be sure to call through to the superclass when overriding this function. 19979 * 19980 * @param x hotspot x coordinate 19981 * @param y hotspot y coordinate 19982 */ 19983 @CallSuper 19984 public void drawableHotspotChanged(float x, float y) { 19985 if (mBackground != null) { 19986 mBackground.setHotspot(x, y); 19987 } 19988 if (mDefaultFocusHighlight != null) { 19989 mDefaultFocusHighlight.setHotspot(x, y); 19990 } 19991 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null) { 19992 mForegroundInfo.mDrawable.setHotspot(x, y); 19993 } 19994 19995 dispatchDrawableHotspotChanged(x, y); 19996 } 19997 19998 /** 19999 * Dispatches drawableHotspotChanged to all of this View's children. 20000 * 20001 * @param x hotspot x coordinate 20002 * @param y hotspot y coordinate 20003 * @see #drawableHotspotChanged(float, float) 20004 */ 20005 public void dispatchDrawableHotspotChanged(float x, float y) { 20006 } 20007 20008 /** 20009 * Call this to force a view to update its drawable state. This will cause 20010 * drawableStateChanged to be called on this view. Views that are interested 20011 * in the new state should call getDrawableState. 20012 * 20013 * @see #drawableStateChanged 20014 * @see #getDrawableState 20015 */ 20016 public void refreshDrawableState() { 20017 mPrivateFlags |= PFLAG_DRAWABLE_STATE_DIRTY; 20018 drawableStateChanged(); 20019 20020 ViewParent parent = mParent; 20021 if (parent != null) { 20022 parent.childDrawableStateChanged(this); 20023 } 20024 } 20025 20026 /** 20027 * Create a default focus highlight if it doesn't exist. 20028 * @return a default focus highlight. 20029 */ 20030 private Drawable getDefaultFocusHighlightDrawable() { 20031 if (mDefaultFocusHighlightCache == null) { 20032 if (mContext != null) { 20033 final int[] attrs = new int[] { android.R.attr.selectableItemBackground }; 20034 final TypedArray ta = mContext.obtainStyledAttributes(attrs); 20035 mDefaultFocusHighlightCache = ta.getDrawable(0); 20036 ta.recycle(); 20037 } 20038 } 20039 return mDefaultFocusHighlightCache; 20040 } 20041 20042 /** 20043 * Set the current default focus highlight. 20044 * @param highlight the highlight drawable, or {@code null} if it's no longer needed. 20045 */ 20046 private void setDefaultFocusHighlight(Drawable highlight) { 20047 mDefaultFocusHighlight = highlight; 20048 mDefaultFocusHighlightSizeChanged = true; 20049 if (highlight != null) { 20050 if ((mPrivateFlags & PFLAG_SKIP_DRAW) != 0) { 20051 mPrivateFlags &= ~PFLAG_SKIP_DRAW; 20052 } 20053 highlight.setLayoutDirection(getLayoutDirection()); 20054 if (highlight.isStateful()) { 20055 highlight.setState(getDrawableState()); 20056 } 20057 if (isAttachedToWindow()) { 20058 highlight.setVisible(getWindowVisibility() == VISIBLE && isShown(), false); 20059 } 20060 // Set callback last, since the view may still be initializing. 20061 highlight.setCallback(this); 20062 } else if ((mViewFlags & WILL_NOT_DRAW) != 0 && mBackground == null 20063 && (mForegroundInfo == null || mForegroundInfo.mDrawable == null)) { 20064 mPrivateFlags |= PFLAG_SKIP_DRAW; 20065 } 20066 invalidate(); 20067 } 20068 20069 /** 20070 * Check whether we need to draw a default focus highlight when this view gets focused, 20071 * which requires: 20072 * <ul> 20073 * <li>In both background and foreground, {@link android.R.attr#state_focused} 20074 * is not defined.</li> 20075 * <li>This view is not in touch mode.</li> 20076 * <li>This view doesn't opt out for a default focus highlight, via 20077 * {@link #setDefaultFocusHighlightEnabled(boolean)}.</li> 20078 * <li>This view is attached to window.</li> 20079 * </ul> 20080 * @return {@code true} if a default focus highlight is needed. 20081 * @hide 20082 */ 20083 @TestApi 20084 public boolean isDefaultFocusHighlightNeeded(Drawable background, Drawable foreground) { 20085 final boolean lackFocusState = (background == null || !background.isStateful() 20086 || !background.hasFocusStateSpecified()) 20087 && (foreground == null || !foreground.isStateful() 20088 || !foreground.hasFocusStateSpecified()); 20089 return !isInTouchMode() && getDefaultFocusHighlightEnabled() && lackFocusState 20090 && isAttachedToWindow() && sUseDefaultFocusHighlight; 20091 } 20092 20093 /** 20094 * When this view is focused, switches on/off the default focused highlight. 20095 * <p> 20096 * This always happens when this view is focused, and only at this moment the default focus 20097 * highlight can be visible. 20098 */ 20099 private void switchDefaultFocusHighlight() { 20100 if (isFocused()) { 20101 final boolean needed = isDefaultFocusHighlightNeeded(mBackground, 20102 mForegroundInfo == null ? null : mForegroundInfo.mDrawable); 20103 final boolean active = mDefaultFocusHighlight != null; 20104 if (needed && !active) { 20105 setDefaultFocusHighlight(getDefaultFocusHighlightDrawable()); 20106 } else if (!needed && active) { 20107 // The highlight is no longer needed, so tear it down. 20108 setDefaultFocusHighlight(null); 20109 } 20110 } 20111 } 20112 20113 /** 20114 * Draw the default focus highlight onto the canvas. 20115 * @param canvas the canvas where we're drawing the highlight. 20116 */ 20117 private void drawDefaultFocusHighlight(Canvas canvas) { 20118 if (mDefaultFocusHighlight != null) { 20119 if (mDefaultFocusHighlightSizeChanged) { 20120 mDefaultFocusHighlightSizeChanged = false; 20121 final int l = mScrollX; 20122 final int r = l + mRight - mLeft; 20123 final int t = mScrollY; 20124 final int b = t + mBottom - mTop; 20125 mDefaultFocusHighlight.setBounds(l, t, r, b); 20126 } 20127 mDefaultFocusHighlight.draw(canvas); 20128 } 20129 } 20130 20131 /** 20132 * Return an array of resource IDs of the drawable states representing the 20133 * current state of the view. 20134 * 20135 * @return The current drawable state 20136 * 20137 * @see Drawable#setState(int[]) 20138 * @see #drawableStateChanged() 20139 * @see #onCreateDrawableState(int) 20140 */ 20141 public final int[] getDrawableState() { 20142 if ((mDrawableState != null) && ((mPrivateFlags & PFLAG_DRAWABLE_STATE_DIRTY) == 0)) { 20143 return mDrawableState; 20144 } else { 20145 mDrawableState = onCreateDrawableState(0); 20146 mPrivateFlags &= ~PFLAG_DRAWABLE_STATE_DIRTY; 20147 return mDrawableState; 20148 } 20149 } 20150 20151 /** 20152 * Generate the new {@link android.graphics.drawable.Drawable} state for 20153 * this view. This is called by the view 20154 * system when the cached Drawable state is determined to be invalid. To 20155 * retrieve the current state, you should use {@link #getDrawableState}. 20156 * 20157 * @param extraSpace if non-zero, this is the number of extra entries you 20158 * would like in the returned array in which you can place your own 20159 * states. 20160 * 20161 * @return Returns an array holding the current {@link Drawable} state of 20162 * the view. 20163 * 20164 * @see #mergeDrawableStates(int[], int[]) 20165 */ 20166 protected int[] onCreateDrawableState(int extraSpace) { 20167 if ((mViewFlags & DUPLICATE_PARENT_STATE) == DUPLICATE_PARENT_STATE && 20168 mParent instanceof View) { 20169 return ((View) mParent).onCreateDrawableState(extraSpace); 20170 } 20171 20172 int[] drawableState; 20173 20174 int privateFlags = mPrivateFlags; 20175 20176 int viewStateIndex = 0; 20177 if ((privateFlags & PFLAG_PRESSED) != 0) viewStateIndex |= StateSet.VIEW_STATE_PRESSED; 20178 if ((mViewFlags & ENABLED_MASK) == ENABLED) viewStateIndex |= StateSet.VIEW_STATE_ENABLED; 20179 if (isFocused()) viewStateIndex |= StateSet.VIEW_STATE_FOCUSED; 20180 if ((privateFlags & PFLAG_SELECTED) != 0) viewStateIndex |= StateSet.VIEW_STATE_SELECTED; 20181 if (hasWindowFocus()) viewStateIndex |= StateSet.VIEW_STATE_WINDOW_FOCUSED; 20182 if ((privateFlags & PFLAG_ACTIVATED) != 0) viewStateIndex |= StateSet.VIEW_STATE_ACTIVATED; 20183 if (mAttachInfo != null && mAttachInfo.mHardwareAccelerationRequested && 20184 ThreadedRenderer.isAvailable()) { 20185 // This is set if HW acceleration is requested, even if the current 20186 // process doesn't allow it. This is just to allow app preview 20187 // windows to better match their app. 20188 viewStateIndex |= StateSet.VIEW_STATE_ACCELERATED; 20189 } 20190 if ((privateFlags & PFLAG_HOVERED) != 0) viewStateIndex |= StateSet.VIEW_STATE_HOVERED; 20191 20192 final int privateFlags2 = mPrivateFlags2; 20193 if ((privateFlags2 & PFLAG2_DRAG_CAN_ACCEPT) != 0) { 20194 viewStateIndex |= StateSet.VIEW_STATE_DRAG_CAN_ACCEPT; 20195 } 20196 if ((privateFlags2 & PFLAG2_DRAG_HOVERED) != 0) { 20197 viewStateIndex |= StateSet.VIEW_STATE_DRAG_HOVERED; 20198 } 20199 20200 drawableState = StateSet.get(viewStateIndex); 20201 20202 //noinspection ConstantIfStatement 20203 if (false) { 20204 Log.i("View", "drawableStateIndex=" + viewStateIndex); 20205 Log.i("View", toString() 20206 + " pressed=" + ((privateFlags & PFLAG_PRESSED) != 0) 20207 + " en=" + ((mViewFlags & ENABLED_MASK) == ENABLED) 20208 + " fo=" + hasFocus() 20209 + " sl=" + ((privateFlags & PFLAG_SELECTED) != 0) 20210 + " wf=" + hasWindowFocus() 20211 + ": " + Arrays.toString(drawableState)); 20212 } 20213 20214 if (extraSpace == 0) { 20215 return drawableState; 20216 } 20217 20218 final int[] fullState; 20219 if (drawableState != null) { 20220 fullState = new int[drawableState.length + extraSpace]; 20221 System.arraycopy(drawableState, 0, fullState, 0, drawableState.length); 20222 } else { 20223 fullState = new int[extraSpace]; 20224 } 20225 20226 return fullState; 20227 } 20228 20229 /** 20230 * Merge your own state values in <var>additionalState</var> into the base 20231 * state values <var>baseState</var> that were returned by 20232 * {@link #onCreateDrawableState(int)}. 20233 * 20234 * @param baseState The base state values returned by 20235 * {@link #onCreateDrawableState(int)}, which will be modified to also hold your 20236 * own additional state values. 20237 * 20238 * @param additionalState The additional state values you would like 20239 * added to <var>baseState</var>; this array is not modified. 20240 * 20241 * @return As a convenience, the <var>baseState</var> array you originally 20242 * passed into the function is returned. 20243 * 20244 * @see #onCreateDrawableState(int) 20245 */ 20246 protected static int[] mergeDrawableStates(int[] baseState, int[] additionalState) { 20247 final int N = baseState.length; 20248 int i = N - 1; 20249 while (i >= 0 && baseState[i] == 0) { 20250 i--; 20251 } 20252 System.arraycopy(additionalState, 0, baseState, i + 1, additionalState.length); 20253 return baseState; 20254 } 20255 20256 /** 20257 * Call {@link Drawable#jumpToCurrentState() Drawable.jumpToCurrentState()} 20258 * on all Drawable objects associated with this view. 20259 * <p> 20260 * Also calls {@link StateListAnimator#jumpToCurrentState()} if there is a StateListAnimator 20261 * attached to this view. 20262 */ 20263 @CallSuper 20264 public void jumpDrawablesToCurrentState() { 20265 if (mBackground != null) { 20266 mBackground.jumpToCurrentState(); 20267 } 20268 if (mStateListAnimator != null) { 20269 mStateListAnimator.jumpToCurrentState(); 20270 } 20271 if (mDefaultFocusHighlight != null) { 20272 mDefaultFocusHighlight.jumpToCurrentState(); 20273 } 20274 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null) { 20275 mForegroundInfo.mDrawable.jumpToCurrentState(); 20276 } 20277 } 20278 20279 /** 20280 * Sets the background color for this view. 20281 * @param color the color of the background 20282 */ 20283 @RemotableViewMethod 20284 public void setBackgroundColor(@ColorInt int color) { 20285 if (mBackground instanceof ColorDrawable) { 20286 ((ColorDrawable) mBackground.mutate()).setColor(color); 20287 computeOpaqueFlags(); 20288 mBackgroundResource = 0; 20289 } else { 20290 setBackground(new ColorDrawable(color)); 20291 } 20292 } 20293 20294 /** 20295 * Set the background to a given resource. The resource should refer to 20296 * a Drawable object or 0 to remove the background. 20297 * @param resid The identifier of the resource. 20298 * 20299 * @attr ref android.R.styleable#View_background 20300 */ 20301 @RemotableViewMethod 20302 public void setBackgroundResource(@DrawableRes int resid) { 20303 if (resid != 0 && resid == mBackgroundResource) { 20304 return; 20305 } 20306 20307 Drawable d = null; 20308 if (resid != 0) { 20309 d = mContext.getDrawable(resid); 20310 } 20311 setBackground(d); 20312 20313 mBackgroundResource = resid; 20314 } 20315 20316 /** 20317 * Set the background to a given Drawable, or remove the background. If the 20318 * background has padding, this View's padding is set to the background's 20319 * padding. However, when a background is removed, this View's padding isn't 20320 * touched. If setting the padding is desired, please use 20321 * {@link #setPadding(int, int, int, int)}. 20322 * 20323 * @param background The Drawable to use as the background, or null to remove the 20324 * background 20325 */ 20326 public void setBackground(Drawable background) { 20327 //noinspection deprecation 20328 setBackgroundDrawable(background); 20329 } 20330 20331 /** 20332 * @deprecated use {@link #setBackground(Drawable)} instead 20333 */ 20334 @Deprecated 20335 public void setBackgroundDrawable(Drawable background) { 20336 computeOpaqueFlags(); 20337 20338 if (background == mBackground) { 20339 return; 20340 } 20341 20342 boolean requestLayout = false; 20343 20344 mBackgroundResource = 0; 20345 20346 /* 20347 * Regardless of whether we're setting a new background or not, we want 20348 * to clear the previous drawable. setVisible first while we still have the callback set. 20349 */ 20350 if (mBackground != null) { 20351 if (isAttachedToWindow()) { 20352 mBackground.setVisible(false, false); 20353 } 20354 mBackground.setCallback(null); 20355 unscheduleDrawable(mBackground); 20356 } 20357 20358 if (background != null) { 20359 Rect padding = sThreadLocal.get(); 20360 if (padding == null) { 20361 padding = new Rect(); 20362 sThreadLocal.set(padding); 20363 } 20364 resetResolvedDrawablesInternal(); 20365 background.setLayoutDirection(getLayoutDirection()); 20366 if (background.getPadding(padding)) { 20367 resetResolvedPaddingInternal(); 20368 switch (background.getLayoutDirection()) { 20369 case LAYOUT_DIRECTION_RTL: 20370 mUserPaddingLeftInitial = padding.right; 20371 mUserPaddingRightInitial = padding.left; 20372 internalSetPadding(padding.right, padding.top, padding.left, padding.bottom); 20373 break; 20374 case LAYOUT_DIRECTION_LTR: 20375 default: 20376 mUserPaddingLeftInitial = padding.left; 20377 mUserPaddingRightInitial = padding.right; 20378 internalSetPadding(padding.left, padding.top, padding.right, padding.bottom); 20379 } 20380 mLeftPaddingDefined = false; 20381 mRightPaddingDefined = false; 20382 } 20383 20384 // Compare the minimum sizes of the old Drawable and the new. If there isn't an old or 20385 // if it has a different minimum size, we should layout again 20386 if (mBackground == null 20387 || mBackground.getMinimumHeight() != background.getMinimumHeight() 20388 || mBackground.getMinimumWidth() != background.getMinimumWidth()) { 20389 requestLayout = true; 20390 } 20391 20392 // Set mBackground before we set this as the callback and start making other 20393 // background drawable state change calls. In particular, the setVisible call below 20394 // can result in drawables attempting to start animations or otherwise invalidate, 20395 // which requires the view set as the callback (us) to recognize the drawable as 20396 // belonging to it as per verifyDrawable. 20397 mBackground = background; 20398 if (background.isStateful()) { 20399 background.setState(getDrawableState()); 20400 } 20401 if (isAttachedToWindow()) { 20402 background.setVisible(getWindowVisibility() == VISIBLE && isShown(), false); 20403 } 20404 20405 applyBackgroundTint(); 20406 20407 // Set callback last, since the view may still be initializing. 20408 background.setCallback(this); 20409 20410 if ((mPrivateFlags & PFLAG_SKIP_DRAW) != 0) { 20411 mPrivateFlags &= ~PFLAG_SKIP_DRAW; 20412 requestLayout = true; 20413 } 20414 } else { 20415 /* Remove the background */ 20416 mBackground = null; 20417 if ((mViewFlags & WILL_NOT_DRAW) != 0 20418 && (mDefaultFocusHighlight == null) 20419 && (mForegroundInfo == null || mForegroundInfo.mDrawable == null)) { 20420 mPrivateFlags |= PFLAG_SKIP_DRAW; 20421 } 20422 20423 /* 20424 * When the background is set, we try to apply its padding to this 20425 * View. When the background is removed, we don't touch this View's 20426 * padding. This is noted in the Javadocs. Hence, we don't need to 20427 * requestLayout(), the invalidate() below is sufficient. 20428 */ 20429 20430 // The old background's minimum size could have affected this 20431 // View's layout, so let's requestLayout 20432 requestLayout = true; 20433 } 20434 20435 computeOpaqueFlags(); 20436 20437 if (requestLayout) { 20438 requestLayout(); 20439 } 20440 20441 mBackgroundSizeChanged = true; 20442 invalidate(true); 20443 invalidateOutline(); 20444 } 20445 20446 /** 20447 * Gets the background drawable 20448 * 20449 * @return The drawable used as the background for this view, if any. 20450 * 20451 * @see #setBackground(Drawable) 20452 * 20453 * @attr ref android.R.styleable#View_background 20454 */ 20455 public Drawable getBackground() { 20456 return mBackground; 20457 } 20458 20459 /** 20460 * Applies a tint to the background drawable. Does not modify the current tint 20461 * mode, which is {@link PorterDuff.Mode#SRC_IN} by default. 20462 * <p> 20463 * Subsequent calls to {@link #setBackground(Drawable)} will automatically 20464 * mutate the drawable and apply the specified tint and tint mode using 20465 * {@link Drawable#setTintList(ColorStateList)}. 20466 * 20467 * @param tint the tint to apply, may be {@code null} to clear tint 20468 * 20469 * @attr ref android.R.styleable#View_backgroundTint 20470 * @see #getBackgroundTintList() 20471 * @see Drawable#setTintList(ColorStateList) 20472 */ 20473 public void setBackgroundTintList(@Nullable ColorStateList tint) { 20474 if (mBackgroundTint == null) { 20475 mBackgroundTint = new TintInfo(); 20476 } 20477 mBackgroundTint.mTintList = tint; 20478 mBackgroundTint.mHasTintList = true; 20479 20480 applyBackgroundTint(); 20481 } 20482 20483 /** 20484 * Return the tint applied to the background drawable, if specified. 20485 * 20486 * @return the tint applied to the background drawable 20487 * @attr ref android.R.styleable#View_backgroundTint 20488 * @see #setBackgroundTintList(ColorStateList) 20489 */ 20490 @Nullable 20491 public ColorStateList getBackgroundTintList() { 20492 return mBackgroundTint != null ? mBackgroundTint.mTintList : null; 20493 } 20494 20495 /** 20496 * Specifies the blending mode used to apply the tint specified by 20497 * {@link #setBackgroundTintList(ColorStateList)}} to the background 20498 * drawable. The default mode is {@link PorterDuff.Mode#SRC_IN}. 20499 * 20500 * @param tintMode the blending mode used to apply the tint, may be 20501 * {@code null} to clear tint 20502 * @attr ref android.R.styleable#View_backgroundTintMode 20503 * @see #getBackgroundTintMode() 20504 * @see Drawable#setTintMode(PorterDuff.Mode) 20505 */ 20506 public void setBackgroundTintMode(@Nullable PorterDuff.Mode tintMode) { 20507 if (mBackgroundTint == null) { 20508 mBackgroundTint = new TintInfo(); 20509 } 20510 mBackgroundTint.mTintMode = tintMode; 20511 mBackgroundTint.mHasTintMode = true; 20512 20513 applyBackgroundTint(); 20514 } 20515 20516 /** 20517 * Return the blending mode used to apply the tint to the background 20518 * drawable, if specified. 20519 * 20520 * @return the blending mode used to apply the tint to the background 20521 * drawable 20522 * @attr ref android.R.styleable#View_backgroundTintMode 20523 * @see #setBackgroundTintMode(PorterDuff.Mode) 20524 */ 20525 @Nullable 20526 public PorterDuff.Mode getBackgroundTintMode() { 20527 return mBackgroundTint != null ? mBackgroundTint.mTintMode : null; 20528 } 20529 20530 private void applyBackgroundTint() { 20531 if (mBackground != null && mBackgroundTint != null) { 20532 final TintInfo tintInfo = mBackgroundTint; 20533 if (tintInfo.mHasTintList || tintInfo.mHasTintMode) { 20534 mBackground = mBackground.mutate(); 20535 20536 if (tintInfo.mHasTintList) { 20537 mBackground.setTintList(tintInfo.mTintList); 20538 } 20539 20540 if (tintInfo.mHasTintMode) { 20541 mBackground.setTintMode(tintInfo.mTintMode); 20542 } 20543 20544 // The drawable (or one of its children) may not have been 20545 // stateful before applying the tint, so let's try again. 20546 if (mBackground.isStateful()) { 20547 mBackground.setState(getDrawableState()); 20548 } 20549 } 20550 } 20551 } 20552 20553 /** 20554 * Returns the drawable used as the foreground of this View. The 20555 * foreground drawable, if non-null, is always drawn on top of the view's content. 20556 * 20557 * @return a Drawable or null if no foreground was set 20558 * 20559 * @see #onDrawForeground(Canvas) 20560 */ 20561 public Drawable getForeground() { 20562 return mForegroundInfo != null ? mForegroundInfo.mDrawable : null; 20563 } 20564 20565 /** 20566 * Supply a Drawable that is to be rendered on top of all of the content in the view. 20567 * 20568 * @param foreground the Drawable to be drawn on top of the children 20569 * 20570 * @attr ref android.R.styleable#View_foreground 20571 */ 20572 public void setForeground(Drawable foreground) { 20573 if (mForegroundInfo == null) { 20574 if (foreground == null) { 20575 // Nothing to do. 20576 return; 20577 } 20578 mForegroundInfo = new ForegroundInfo(); 20579 } 20580 20581 if (foreground == mForegroundInfo.mDrawable) { 20582 // Nothing to do 20583 return; 20584 } 20585 20586 if (mForegroundInfo.mDrawable != null) { 20587 if (isAttachedToWindow()) { 20588 mForegroundInfo.mDrawable.setVisible(false, false); 20589 } 20590 mForegroundInfo.mDrawable.setCallback(null); 20591 unscheduleDrawable(mForegroundInfo.mDrawable); 20592 } 20593 20594 mForegroundInfo.mDrawable = foreground; 20595 mForegroundInfo.mBoundsChanged = true; 20596 if (foreground != null) { 20597 if ((mPrivateFlags & PFLAG_SKIP_DRAW) != 0) { 20598 mPrivateFlags &= ~PFLAG_SKIP_DRAW; 20599 } 20600 foreground.setLayoutDirection(getLayoutDirection()); 20601 if (foreground.isStateful()) { 20602 foreground.setState(getDrawableState()); 20603 } 20604 applyForegroundTint(); 20605 if (isAttachedToWindow()) { 20606 foreground.setVisible(getWindowVisibility() == VISIBLE && isShown(), false); 20607 } 20608 // Set callback last, since the view may still be initializing. 20609 foreground.setCallback(this); 20610 } else if ((mViewFlags & WILL_NOT_DRAW) != 0 && mBackground == null 20611 && (mDefaultFocusHighlight == null)) { 20612 mPrivateFlags |= PFLAG_SKIP_DRAW; 20613 } 20614 requestLayout(); 20615 invalidate(); 20616 } 20617 20618 /** 20619 * Magic bit used to support features of framework-internal window decor implementation details. 20620 * This used to live exclusively in FrameLayout. 20621 * 20622 * @return true if the foreground should draw inside the padding region or false 20623 * if it should draw inset by the view's padding 20624 * @hide internal use only; only used by FrameLayout and internal screen layouts. 20625 */ 20626 public boolean isForegroundInsidePadding() { 20627 return mForegroundInfo != null ? mForegroundInfo.mInsidePadding : true; 20628 } 20629 20630 /** 20631 * Describes how the foreground is positioned. 20632 * 20633 * @return foreground gravity. 20634 * 20635 * @see #setForegroundGravity(int) 20636 * 20637 * @attr ref android.R.styleable#View_foregroundGravity 20638 */ 20639 public int getForegroundGravity() { 20640 return mForegroundInfo != null ? mForegroundInfo.mGravity 20641 : Gravity.START | Gravity.TOP; 20642 } 20643 20644 /** 20645 * Describes how the foreground is positioned. Defaults to START and TOP. 20646 * 20647 * @param gravity see {@link android.view.Gravity} 20648 * 20649 * @see #getForegroundGravity() 20650 * 20651 * @attr ref android.R.styleable#View_foregroundGravity 20652 */ 20653 public void setForegroundGravity(int gravity) { 20654 if (mForegroundInfo == null) { 20655 mForegroundInfo = new ForegroundInfo(); 20656 } 20657 20658 if (mForegroundInfo.mGravity != gravity) { 20659 if ((gravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK) == 0) { 20660 gravity |= Gravity.START; 20661 } 20662 20663 if ((gravity & Gravity.VERTICAL_GRAVITY_MASK) == 0) { 20664 gravity |= Gravity.TOP; 20665 } 20666 20667 mForegroundInfo.mGravity = gravity; 20668 requestLayout(); 20669 } 20670 } 20671 20672 /** 20673 * Applies a tint to the foreground drawable. Does not modify the current tint 20674 * mode, which is {@link PorterDuff.Mode#SRC_IN} by default. 20675 * <p> 20676 * Subsequent calls to {@link #setForeground(Drawable)} will automatically 20677 * mutate the drawable and apply the specified tint and tint mode using 20678 * {@link Drawable#setTintList(ColorStateList)}. 20679 * 20680 * @param tint the tint to apply, may be {@code null} to clear tint 20681 * 20682 * @attr ref android.R.styleable#View_foregroundTint 20683 * @see #getForegroundTintList() 20684 * @see Drawable#setTintList(ColorStateList) 20685 */ 20686 public void setForegroundTintList(@Nullable ColorStateList tint) { 20687 if (mForegroundInfo == null) { 20688 mForegroundInfo = new ForegroundInfo(); 20689 } 20690 if (mForegroundInfo.mTintInfo == null) { 20691 mForegroundInfo.mTintInfo = new TintInfo(); 20692 } 20693 mForegroundInfo.mTintInfo.mTintList = tint; 20694 mForegroundInfo.mTintInfo.mHasTintList = true; 20695 20696 applyForegroundTint(); 20697 } 20698 20699 /** 20700 * Return the tint applied to the foreground drawable, if specified. 20701 * 20702 * @return the tint applied to the foreground drawable 20703 * @attr ref android.R.styleable#View_foregroundTint 20704 * @see #setForegroundTintList(ColorStateList) 20705 */ 20706 @Nullable 20707 public ColorStateList getForegroundTintList() { 20708 return mForegroundInfo != null && mForegroundInfo.mTintInfo != null 20709 ? mForegroundInfo.mTintInfo.mTintList : null; 20710 } 20711 20712 /** 20713 * Specifies the blending mode used to apply the tint specified by 20714 * {@link #setForegroundTintList(ColorStateList)}} to the background 20715 * drawable. The default mode is {@link PorterDuff.Mode#SRC_IN}. 20716 * 20717 * @param tintMode the blending mode used to apply the tint, may be 20718 * {@code null} to clear tint 20719 * @attr ref android.R.styleable#View_foregroundTintMode 20720 * @see #getForegroundTintMode() 20721 * @see Drawable#setTintMode(PorterDuff.Mode) 20722 */ 20723 public void setForegroundTintMode(@Nullable PorterDuff.Mode tintMode) { 20724 if (mForegroundInfo == null) { 20725 mForegroundInfo = new ForegroundInfo(); 20726 } 20727 if (mForegroundInfo.mTintInfo == null) { 20728 mForegroundInfo.mTintInfo = new TintInfo(); 20729 } 20730 mForegroundInfo.mTintInfo.mTintMode = tintMode; 20731 mForegroundInfo.mTintInfo.mHasTintMode = true; 20732 20733 applyForegroundTint(); 20734 } 20735 20736 /** 20737 * Return the blending mode used to apply the tint to the foreground 20738 * drawable, if specified. 20739 * 20740 * @return the blending mode used to apply the tint to the foreground 20741 * drawable 20742 * @attr ref android.R.styleable#View_foregroundTintMode 20743 * @see #setForegroundTintMode(PorterDuff.Mode) 20744 */ 20745 @Nullable 20746 public PorterDuff.Mode getForegroundTintMode() { 20747 return mForegroundInfo != null && mForegroundInfo.mTintInfo != null 20748 ? mForegroundInfo.mTintInfo.mTintMode : null; 20749 } 20750 20751 private void applyForegroundTint() { 20752 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null 20753 && mForegroundInfo.mTintInfo != null) { 20754 final TintInfo tintInfo = mForegroundInfo.mTintInfo; 20755 if (tintInfo.mHasTintList || tintInfo.mHasTintMode) { 20756 mForegroundInfo.mDrawable = mForegroundInfo.mDrawable.mutate(); 20757 20758 if (tintInfo.mHasTintList) { 20759 mForegroundInfo.mDrawable.setTintList(tintInfo.mTintList); 20760 } 20761 20762 if (tintInfo.mHasTintMode) { 20763 mForegroundInfo.mDrawable.setTintMode(tintInfo.mTintMode); 20764 } 20765 20766 // The drawable (or one of its children) may not have been 20767 // stateful before applying the tint, so let's try again. 20768 if (mForegroundInfo.mDrawable.isStateful()) { 20769 mForegroundInfo.mDrawable.setState(getDrawableState()); 20770 } 20771 } 20772 } 20773 } 20774 20775 /** 20776 * Get the drawable to be overlayed when a view is autofilled 20777 * 20778 * @return The drawable 20779 * 20780 * @throws IllegalStateException if the drawable could not be found. 20781 */ 20782 @Nullable private Drawable getAutofilledDrawable() { 20783 if (mAttachInfo == null) { 20784 return null; 20785 } 20786 // Lazily load the isAutofilled drawable. 20787 if (mAttachInfo.mAutofilledDrawable == null) { 20788 Context rootContext = getRootView().getContext(); 20789 TypedArray a = rootContext.getTheme().obtainStyledAttributes(AUTOFILL_HIGHLIGHT_ATTR); 20790 int attributeResourceId = a.getResourceId(0, 0); 20791 mAttachInfo.mAutofilledDrawable = rootContext.getDrawable(attributeResourceId); 20792 a.recycle(); 20793 } 20794 20795 return mAttachInfo.mAutofilledDrawable; 20796 } 20797 20798 /** 20799 * Draw {@link View#isAutofilled()} highlight over view if the view is autofilled. 20800 * 20801 * @param canvas The canvas to draw on 20802 */ 20803 private void drawAutofilledHighlight(@NonNull Canvas canvas) { 20804 if (isAutofilled()) { 20805 Drawable autofilledHighlight = getAutofilledDrawable(); 20806 20807 if (autofilledHighlight != null) { 20808 autofilledHighlight.setBounds(0, 0, getWidth(), getHeight()); 20809 autofilledHighlight.draw(canvas); 20810 } 20811 } 20812 } 20813 20814 /** 20815 * Draw any foreground content for this view. 20816 * 20817 * <p>Foreground content may consist of scroll bars, a {@link #setForeground foreground} 20818 * drawable or other view-specific decorations. The foreground is drawn on top of the 20819 * primary view content.</p> 20820 * 20821 * @param canvas canvas to draw into 20822 */ 20823 public void onDrawForeground(Canvas canvas) { 20824 onDrawScrollIndicators(canvas); 20825 onDrawScrollBars(canvas); 20826 20827 final Drawable foreground = mForegroundInfo != null ? mForegroundInfo.mDrawable : null; 20828 if (foreground != null) { 20829 if (mForegroundInfo.mBoundsChanged) { 20830 mForegroundInfo.mBoundsChanged = false; 20831 final Rect selfBounds = mForegroundInfo.mSelfBounds; 20832 final Rect overlayBounds = mForegroundInfo.mOverlayBounds; 20833 20834 if (mForegroundInfo.mInsidePadding) { 20835 selfBounds.set(0, 0, getWidth(), getHeight()); 20836 } else { 20837 selfBounds.set(getPaddingLeft(), getPaddingTop(), 20838 getWidth() - getPaddingRight(), getHeight() - getPaddingBottom()); 20839 } 20840 20841 final int ld = getLayoutDirection(); 20842 Gravity.apply(mForegroundInfo.mGravity, foreground.getIntrinsicWidth(), 20843 foreground.getIntrinsicHeight(), selfBounds, overlayBounds, ld); 20844 foreground.setBounds(overlayBounds); 20845 } 20846 20847 foreground.draw(canvas); 20848 } 20849 } 20850 20851 /** 20852 * Sets the padding. The view may add on the space required to display 20853 * the scrollbars, depending on the style and visibility of the scrollbars. 20854 * So the values returned from {@link #getPaddingLeft}, {@link #getPaddingTop}, 20855 * {@link #getPaddingRight} and {@link #getPaddingBottom} may be different 20856 * from the values set in this call. 20857 * 20858 * @attr ref android.R.styleable#View_padding 20859 * @attr ref android.R.styleable#View_paddingBottom 20860 * @attr ref android.R.styleable#View_paddingLeft 20861 * @attr ref android.R.styleable#View_paddingRight 20862 * @attr ref android.R.styleable#View_paddingTop 20863 * @param left the left padding in pixels 20864 * @param top the top padding in pixels 20865 * @param right the right padding in pixels 20866 * @param bottom the bottom padding in pixels 20867 */ 20868 public void setPadding(int left, int top, int right, int bottom) { 20869 resetResolvedPaddingInternal(); 20870 20871 mUserPaddingStart = UNDEFINED_PADDING; 20872 mUserPaddingEnd = UNDEFINED_PADDING; 20873 20874 mUserPaddingLeftInitial = left; 20875 mUserPaddingRightInitial = right; 20876 20877 mLeftPaddingDefined = true; 20878 mRightPaddingDefined = true; 20879 20880 internalSetPadding(left, top, right, bottom); 20881 } 20882 20883 /** 20884 * @hide 20885 */ 20886 protected void internalSetPadding(int left, int top, int right, int bottom) { 20887 mUserPaddingLeft = left; 20888 mUserPaddingRight = right; 20889 mUserPaddingBottom = bottom; 20890 20891 final int viewFlags = mViewFlags; 20892 boolean changed = false; 20893 20894 // Common case is there are no scroll bars. 20895 if ((viewFlags & (SCROLLBARS_VERTICAL|SCROLLBARS_HORIZONTAL)) != 0) { 20896 if ((viewFlags & SCROLLBARS_VERTICAL) != 0) { 20897 final int offset = (viewFlags & SCROLLBARS_INSET_MASK) == 0 20898 ? 0 : getVerticalScrollbarWidth(); 20899 switch (mVerticalScrollbarPosition) { 20900 case SCROLLBAR_POSITION_DEFAULT: 20901 if (isLayoutRtl()) { 20902 left += offset; 20903 } else { 20904 right += offset; 20905 } 20906 break; 20907 case SCROLLBAR_POSITION_RIGHT: 20908 right += offset; 20909 break; 20910 case SCROLLBAR_POSITION_LEFT: 20911 left += offset; 20912 break; 20913 } 20914 } 20915 if ((viewFlags & SCROLLBARS_HORIZONTAL) != 0) { 20916 bottom += (viewFlags & SCROLLBARS_INSET_MASK) == 0 20917 ? 0 : getHorizontalScrollbarHeight(); 20918 } 20919 } 20920 20921 if (mPaddingLeft != left) { 20922 changed = true; 20923 mPaddingLeft = left; 20924 } 20925 if (mPaddingTop != top) { 20926 changed = true; 20927 mPaddingTop = top; 20928 } 20929 if (mPaddingRight != right) { 20930 changed = true; 20931 mPaddingRight = right; 20932 } 20933 if (mPaddingBottom != bottom) { 20934 changed = true; 20935 mPaddingBottom = bottom; 20936 } 20937 20938 if (changed) { 20939 requestLayout(); 20940 invalidateOutline(); 20941 } 20942 } 20943 20944 /** 20945 * Sets the relative padding. The view may add on the space required to display 20946 * the scrollbars, depending on the style and visibility of the scrollbars. 20947 * So the values returned from {@link #getPaddingStart}, {@link #getPaddingTop}, 20948 * {@link #getPaddingEnd} and {@link #getPaddingBottom} may be different 20949 * from the values set in this call. 20950 * 20951 * @attr ref android.R.styleable#View_padding 20952 * @attr ref android.R.styleable#View_paddingBottom 20953 * @attr ref android.R.styleable#View_paddingStart 20954 * @attr ref android.R.styleable#View_paddingEnd 20955 * @attr ref android.R.styleable#View_paddingTop 20956 * @param start the start padding in pixels 20957 * @param top the top padding in pixels 20958 * @param end the end padding in pixels 20959 * @param bottom the bottom padding in pixels 20960 */ 20961 public void setPaddingRelative(int start, int top, int end, int bottom) { 20962 resetResolvedPaddingInternal(); 20963 20964 mUserPaddingStart = start; 20965 mUserPaddingEnd = end; 20966 mLeftPaddingDefined = true; 20967 mRightPaddingDefined = true; 20968 20969 switch(getLayoutDirection()) { 20970 case LAYOUT_DIRECTION_RTL: 20971 mUserPaddingLeftInitial = end; 20972 mUserPaddingRightInitial = start; 20973 internalSetPadding(end, top, start, bottom); 20974 break; 20975 case LAYOUT_DIRECTION_LTR: 20976 default: 20977 mUserPaddingLeftInitial = start; 20978 mUserPaddingRightInitial = end; 20979 internalSetPadding(start, top, end, bottom); 20980 } 20981 } 20982 20983 /** 20984 * Returns the top padding of this view. 20985 * 20986 * @return the top padding in pixels 20987 */ 20988 public int getPaddingTop() { 20989 return mPaddingTop; 20990 } 20991 20992 /** 20993 * Returns the bottom padding of this view. If there are inset and enabled 20994 * scrollbars, this value may include the space required to display the 20995 * scrollbars as well. 20996 * 20997 * @return the bottom padding in pixels 20998 */ 20999 public int getPaddingBottom() { 21000 return mPaddingBottom; 21001 } 21002 21003 /** 21004 * Returns the left padding of this view. If there are inset and enabled 21005 * scrollbars, this value may include the space required to display the 21006 * scrollbars as well. 21007 * 21008 * @return the left padding in pixels 21009 */ 21010 public int getPaddingLeft() { 21011 if (!isPaddingResolved()) { 21012 resolvePadding(); 21013 } 21014 return mPaddingLeft; 21015 } 21016 21017 /** 21018 * Returns the start padding of this view depending on its resolved layout direction. 21019 * If there are inset and enabled scrollbars, this value may include the space 21020 * required to display the scrollbars as well. 21021 * 21022 * @return the start padding in pixels 21023 */ 21024 public int getPaddingStart() { 21025 if (!isPaddingResolved()) { 21026 resolvePadding(); 21027 } 21028 return (getLayoutDirection() == LAYOUT_DIRECTION_RTL) ? 21029 mPaddingRight : mPaddingLeft; 21030 } 21031 21032 /** 21033 * Returns the right padding of this view. If there are inset and enabled 21034 * scrollbars, this value may include the space required to display the 21035 * scrollbars as well. 21036 * 21037 * @return the right padding in pixels 21038 */ 21039 public int getPaddingRight() { 21040 if (!isPaddingResolved()) { 21041 resolvePadding(); 21042 } 21043 return mPaddingRight; 21044 } 21045 21046 /** 21047 * Returns the end padding of this view depending on its resolved layout direction. 21048 * If there are inset and enabled scrollbars, this value may include the space 21049 * required to display the scrollbars as well. 21050 * 21051 * @return the end padding in pixels 21052 */ 21053 public int getPaddingEnd() { 21054 if (!isPaddingResolved()) { 21055 resolvePadding(); 21056 } 21057 return (getLayoutDirection() == LAYOUT_DIRECTION_RTL) ? 21058 mPaddingLeft : mPaddingRight; 21059 } 21060 21061 /** 21062 * Return if the padding has been set through relative values 21063 * {@link #setPaddingRelative(int, int, int, int)} or through 21064 * @attr ref android.R.styleable#View_paddingStart or 21065 * @attr ref android.R.styleable#View_paddingEnd 21066 * 21067 * @return true if the padding is relative or false if it is not. 21068 */ 21069 public boolean isPaddingRelative() { 21070 return (mUserPaddingStart != UNDEFINED_PADDING || mUserPaddingEnd != UNDEFINED_PADDING); 21071 } 21072 21073 Insets computeOpticalInsets() { 21074 return (mBackground == null) ? Insets.NONE : mBackground.getOpticalInsets(); 21075 } 21076 21077 /** 21078 * @hide 21079 */ 21080 public void resetPaddingToInitialValues() { 21081 if (isRtlCompatibilityMode()) { 21082 mPaddingLeft = mUserPaddingLeftInitial; 21083 mPaddingRight = mUserPaddingRightInitial; 21084 return; 21085 } 21086 if (isLayoutRtl()) { 21087 mPaddingLeft = (mUserPaddingEnd >= 0) ? mUserPaddingEnd : mUserPaddingLeftInitial; 21088 mPaddingRight = (mUserPaddingStart >= 0) ? mUserPaddingStart : mUserPaddingRightInitial; 21089 } else { 21090 mPaddingLeft = (mUserPaddingStart >= 0) ? mUserPaddingStart : mUserPaddingLeftInitial; 21091 mPaddingRight = (mUserPaddingEnd >= 0) ? mUserPaddingEnd : mUserPaddingRightInitial; 21092 } 21093 } 21094 21095 /** 21096 * @hide 21097 */ 21098 public Insets getOpticalInsets() { 21099 if (mLayoutInsets == null) { 21100 mLayoutInsets = computeOpticalInsets(); 21101 } 21102 return mLayoutInsets; 21103 } 21104 21105 /** 21106 * Set this view's optical insets. 21107 * 21108 * <p>This method should be treated similarly to setMeasuredDimension and not as a general 21109 * property. Views that compute their own optical insets should call it as part of measurement. 21110 * This method does not request layout. If you are setting optical insets outside of 21111 * measure/layout itself you will want to call requestLayout() yourself. 21112 * </p> 21113 * @hide 21114 */ 21115 public void setOpticalInsets(Insets insets) { 21116 mLayoutInsets = insets; 21117 } 21118 21119 /** 21120 * Changes the selection state of this view. A view can be selected or not. 21121 * Note that selection is not the same as focus. Views are typically 21122 * selected in the context of an AdapterView like ListView or GridView; 21123 * the selected view is the view that is highlighted. 21124 * 21125 * @param selected true if the view must be selected, false otherwise 21126 */ 21127 public void setSelected(boolean selected) { 21128 //noinspection DoubleNegation 21129 if (((mPrivateFlags & PFLAG_SELECTED) != 0) != selected) { 21130 mPrivateFlags = (mPrivateFlags & ~PFLAG_SELECTED) | (selected ? PFLAG_SELECTED : 0); 21131 if (!selected) resetPressedState(); 21132 invalidate(true); 21133 refreshDrawableState(); 21134 dispatchSetSelected(selected); 21135 if (selected) { 21136 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED); 21137 } else { 21138 notifyViewAccessibilityStateChangedIfNeeded( 21139 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 21140 } 21141 } 21142 } 21143 21144 /** 21145 * Dispatch setSelected to all of this View's children. 21146 * 21147 * @see #setSelected(boolean) 21148 * 21149 * @param selected The new selected state 21150 */ 21151 protected void dispatchSetSelected(boolean selected) { 21152 } 21153 21154 /** 21155 * Indicates the selection state of this view. 21156 * 21157 * @return true if the view is selected, false otherwise 21158 */ 21159 @ViewDebug.ExportedProperty 21160 public boolean isSelected() { 21161 return (mPrivateFlags & PFLAG_SELECTED) != 0; 21162 } 21163 21164 /** 21165 * Changes the activated state of this view. A view can be activated or not. 21166 * Note that activation is not the same as selection. Selection is 21167 * a transient property, representing the view (hierarchy) the user is 21168 * currently interacting with. Activation is a longer-term state that the 21169 * user can move views in and out of. For example, in a list view with 21170 * single or multiple selection enabled, the views in the current selection 21171 * set are activated. (Um, yeah, we are deeply sorry about the terminology 21172 * here.) The activated state is propagated down to children of the view it 21173 * is set on. 21174 * 21175 * @param activated true if the view must be activated, false otherwise 21176 */ 21177 public void setActivated(boolean activated) { 21178 //noinspection DoubleNegation 21179 if (((mPrivateFlags & PFLAG_ACTIVATED) != 0) != activated) { 21180 mPrivateFlags = (mPrivateFlags & ~PFLAG_ACTIVATED) | (activated ? PFLAG_ACTIVATED : 0); 21181 invalidate(true); 21182 refreshDrawableState(); 21183 dispatchSetActivated(activated); 21184 } 21185 } 21186 21187 /** 21188 * Dispatch setActivated to all of this View's children. 21189 * 21190 * @see #setActivated(boolean) 21191 * 21192 * @param activated The new activated state 21193 */ 21194 protected void dispatchSetActivated(boolean activated) { 21195 } 21196 21197 /** 21198 * Indicates the activation state of this view. 21199 * 21200 * @return true if the view is activated, false otherwise 21201 */ 21202 @ViewDebug.ExportedProperty 21203 public boolean isActivated() { 21204 return (mPrivateFlags & PFLAG_ACTIVATED) != 0; 21205 } 21206 21207 /** 21208 * Returns the ViewTreeObserver for this view's hierarchy. The view tree 21209 * observer can be used to get notifications when global events, like 21210 * layout, happen. 21211 * 21212 * The returned ViewTreeObserver observer is not guaranteed to remain 21213 * valid for the lifetime of this View. If the caller of this method keeps 21214 * a long-lived reference to ViewTreeObserver, it should always check for 21215 * the return value of {@link ViewTreeObserver#isAlive()}. 21216 * 21217 * @return The ViewTreeObserver for this view's hierarchy. 21218 */ 21219 public ViewTreeObserver getViewTreeObserver() { 21220 if (mAttachInfo != null) { 21221 return mAttachInfo.mTreeObserver; 21222 } 21223 if (mFloatingTreeObserver == null) { 21224 mFloatingTreeObserver = new ViewTreeObserver(mContext); 21225 } 21226 return mFloatingTreeObserver; 21227 } 21228 21229 /** 21230 * <p>Finds the topmost view in the current view hierarchy.</p> 21231 * 21232 * @return the topmost view containing this view 21233 */ 21234 public View getRootView() { 21235 if (mAttachInfo != null) { 21236 final View v = mAttachInfo.mRootView; 21237 if (v != null) { 21238 return v; 21239 } 21240 } 21241 21242 View parent = this; 21243 21244 while (parent.mParent != null && parent.mParent instanceof View) { 21245 parent = (View) parent.mParent; 21246 } 21247 21248 return parent; 21249 } 21250 21251 /** 21252 * Transforms a motion event from view-local coordinates to on-screen 21253 * coordinates. 21254 * 21255 * @param ev the view-local motion event 21256 * @return false if the transformation could not be applied 21257 * @hide 21258 */ 21259 public boolean toGlobalMotionEvent(MotionEvent ev) { 21260 final AttachInfo info = mAttachInfo; 21261 if (info == null) { 21262 return false; 21263 } 21264 21265 final Matrix m = info.mTmpMatrix; 21266 m.set(Matrix.IDENTITY_MATRIX); 21267 transformMatrixToGlobal(m); 21268 ev.transform(m); 21269 return true; 21270 } 21271 21272 /** 21273 * Transforms a motion event from on-screen coordinates to view-local 21274 * coordinates. 21275 * 21276 * @param ev the on-screen motion event 21277 * @return false if the transformation could not be applied 21278 * @hide 21279 */ 21280 public boolean toLocalMotionEvent(MotionEvent ev) { 21281 final AttachInfo info = mAttachInfo; 21282 if (info == null) { 21283 return false; 21284 } 21285 21286 final Matrix m = info.mTmpMatrix; 21287 m.set(Matrix.IDENTITY_MATRIX); 21288 transformMatrixToLocal(m); 21289 ev.transform(m); 21290 return true; 21291 } 21292 21293 /** 21294 * Modifies the input matrix such that it maps view-local coordinates to 21295 * on-screen coordinates. 21296 * 21297 * @param m input matrix to modify 21298 * @hide 21299 */ 21300 public void transformMatrixToGlobal(Matrix m) { 21301 final ViewParent parent = mParent; 21302 if (parent instanceof View) { 21303 final View vp = (View) parent; 21304 vp.transformMatrixToGlobal(m); 21305 m.preTranslate(-vp.mScrollX, -vp.mScrollY); 21306 } else if (parent instanceof ViewRootImpl) { 21307 final ViewRootImpl vr = (ViewRootImpl) parent; 21308 vr.transformMatrixToGlobal(m); 21309 m.preTranslate(0, -vr.mCurScrollY); 21310 } 21311 21312 m.preTranslate(mLeft, mTop); 21313 21314 if (!hasIdentityMatrix()) { 21315 m.preConcat(getMatrix()); 21316 } 21317 } 21318 21319 /** 21320 * Modifies the input matrix such that it maps on-screen coordinates to 21321 * view-local coordinates. 21322 * 21323 * @param m input matrix to modify 21324 * @hide 21325 */ 21326 public void transformMatrixToLocal(Matrix m) { 21327 final ViewParent parent = mParent; 21328 if (parent instanceof View) { 21329 final View vp = (View) parent; 21330 vp.transformMatrixToLocal(m); 21331 m.postTranslate(vp.mScrollX, vp.mScrollY); 21332 } else if (parent instanceof ViewRootImpl) { 21333 final ViewRootImpl vr = (ViewRootImpl) parent; 21334 vr.transformMatrixToLocal(m); 21335 m.postTranslate(0, vr.mCurScrollY); 21336 } 21337 21338 m.postTranslate(-mLeft, -mTop); 21339 21340 if (!hasIdentityMatrix()) { 21341 m.postConcat(getInverseMatrix()); 21342 } 21343 } 21344 21345 /** 21346 * @hide 21347 */ 21348 @ViewDebug.ExportedProperty(category = "layout", indexMapping = { 21349 @ViewDebug.IntToString(from = 0, to = "x"), 21350 @ViewDebug.IntToString(from = 1, to = "y") 21351 }) 21352 public int[] getLocationOnScreen() { 21353 int[] location = new int[2]; 21354 getLocationOnScreen(location); 21355 return location; 21356 } 21357 21358 /** 21359 * <p>Computes the coordinates of this view on the screen. The argument 21360 * must be an array of two integers. After the method returns, the array 21361 * contains the x and y location in that order.</p> 21362 * 21363 * @param outLocation an array of two integers in which to hold the coordinates 21364 */ 21365 public void getLocationOnScreen(@Size(2) int[] outLocation) { 21366 getLocationInWindow(outLocation); 21367 21368 final AttachInfo info = mAttachInfo; 21369 if (info != null) { 21370 outLocation[0] += info.mWindowLeft; 21371 outLocation[1] += info.mWindowTop; 21372 } 21373 } 21374 21375 /** 21376 * <p>Computes the coordinates of this view in its window. The argument 21377 * must be an array of two integers. After the method returns, the array 21378 * contains the x and y location in that order.</p> 21379 * 21380 * @param outLocation an array of two integers in which to hold the coordinates 21381 */ 21382 public void getLocationInWindow(@Size(2) int[] outLocation) { 21383 if (outLocation == null || outLocation.length < 2) { 21384 throw new IllegalArgumentException("outLocation must be an array of two integers"); 21385 } 21386 21387 outLocation[0] = 0; 21388 outLocation[1] = 0; 21389 21390 transformFromViewToWindowSpace(outLocation); 21391 } 21392 21393 /** @hide */ 21394 public void transformFromViewToWindowSpace(@Size(2) int[] inOutLocation) { 21395 if (inOutLocation == null || inOutLocation.length < 2) { 21396 throw new IllegalArgumentException("inOutLocation must be an array of two integers"); 21397 } 21398 21399 if (mAttachInfo == null) { 21400 // When the view is not attached to a window, this method does not make sense 21401 inOutLocation[0] = inOutLocation[1] = 0; 21402 return; 21403 } 21404 21405 float position[] = mAttachInfo.mTmpTransformLocation; 21406 position[0] = inOutLocation[0]; 21407 position[1] = inOutLocation[1]; 21408 21409 if (!hasIdentityMatrix()) { 21410 getMatrix().mapPoints(position); 21411 } 21412 21413 position[0] += mLeft; 21414 position[1] += mTop; 21415 21416 ViewParent viewParent = mParent; 21417 while (viewParent instanceof View) { 21418 final View view = (View) viewParent; 21419 21420 position[0] -= view.mScrollX; 21421 position[1] -= view.mScrollY; 21422 21423 if (!view.hasIdentityMatrix()) { 21424 view.getMatrix().mapPoints(position); 21425 } 21426 21427 position[0] += view.mLeft; 21428 position[1] += view.mTop; 21429 21430 viewParent = view.mParent; 21431 } 21432 21433 if (viewParent instanceof ViewRootImpl) { 21434 // *cough* 21435 final ViewRootImpl vr = (ViewRootImpl) viewParent; 21436 position[1] -= vr.mCurScrollY; 21437 } 21438 21439 inOutLocation[0] = Math.round(position[0]); 21440 inOutLocation[1] = Math.round(position[1]); 21441 } 21442 21443 /** 21444 * @param id the id of the view to be found 21445 * @return the view of the specified id, null if cannot be found 21446 * @hide 21447 */ 21448 protected <T extends View> T findViewTraversal(@IdRes int id) { 21449 if (id == mID) { 21450 return (T) this; 21451 } 21452 return null; 21453 } 21454 21455 /** 21456 * @param tag the tag of the view to be found 21457 * @return the view of specified tag, null if cannot be found 21458 * @hide 21459 */ 21460 protected <T extends View> T findViewWithTagTraversal(Object tag) { 21461 if (tag != null && tag.equals(mTag)) { 21462 return (T) this; 21463 } 21464 return null; 21465 } 21466 21467 /** 21468 * @param predicate The predicate to evaluate. 21469 * @param childToSkip If not null, ignores this child during the recursive traversal. 21470 * @return The first view that matches the predicate or null. 21471 * @hide 21472 */ 21473 protected <T extends View> T findViewByPredicateTraversal(Predicate<View> predicate, 21474 View childToSkip) { 21475 if (predicate.test(this)) { 21476 return (T) this; 21477 } 21478 return null; 21479 } 21480 21481 /** 21482 * Finds the first descendant view with the given ID, the view itself if 21483 * the ID matches {@link #getId()}, or {@code null} if the ID is invalid 21484 * (< 0) or there is no matching view in the hierarchy. 21485 * <p> 21486 * <strong>Note:</strong> In most cases -- depending on compiler support -- 21487 * the resulting view is automatically cast to the target class type. If 21488 * the target class type is unconstrained, an explicit cast may be 21489 * necessary. 21490 * 21491 * @param id the ID to search for 21492 * @return a view with given ID if found, or {@code null} otherwise 21493 * @see View#findViewById(int) 21494 */ 21495 @Nullable 21496 public final <T extends View> T findViewById(@IdRes int id) { 21497 if (id == NO_ID) { 21498 return null; 21499 } 21500 return findViewTraversal(id); 21501 } 21502 21503 /** 21504 * Finds a view by its unuque and stable accessibility id. 21505 * 21506 * @param accessibilityId The searched accessibility id. 21507 * @return The found view. 21508 */ 21509 final <T extends View> T findViewByAccessibilityId(int accessibilityId) { 21510 if (accessibilityId < 0) { 21511 return null; 21512 } 21513 T view = findViewByAccessibilityIdTraversal(accessibilityId); 21514 if (view != null) { 21515 return view.includeForAccessibility() ? view : null; 21516 } 21517 return null; 21518 } 21519 21520 /** 21521 * Performs the traversal to find a view by its unique and stable accessibility id. 21522 * 21523 * <strong>Note:</strong>This method does not stop at the root namespace 21524 * boundary since the user can touch the screen at an arbitrary location 21525 * potentially crossing the root namespace boundary which will send an 21526 * accessibility event to accessibility services and they should be able 21527 * to obtain the event source. Also accessibility ids are guaranteed to be 21528 * unique in the window. 21529 * 21530 * @param accessibilityId The accessibility id. 21531 * @return The found view. 21532 * @hide 21533 */ 21534 public <T extends View> T findViewByAccessibilityIdTraversal(int accessibilityId) { 21535 if (getAccessibilityViewId() == accessibilityId) { 21536 return (T) this; 21537 } 21538 return null; 21539 } 21540 21541 /** 21542 * Performs the traversal to find a view by its autofill id. 21543 * 21544 * <strong>Note:</strong>This method does not stop at the root namespace 21545 * boundary. 21546 * 21547 * @param autofillId The autofill id. 21548 * @return The found view. 21549 * @hide 21550 */ 21551 public <T extends View> T findViewByAutofillIdTraversal(int autofillId) { 21552 if (getAutofillViewId() == autofillId) { 21553 return (T) this; 21554 } 21555 return null; 21556 } 21557 21558 /** 21559 * Look for a child view with the given tag. If this view has the given 21560 * tag, return this view. 21561 * 21562 * @param tag The tag to search for, using "tag.equals(getTag())". 21563 * @return The View that has the given tag in the hierarchy or null 21564 */ 21565 public final <T extends View> T findViewWithTag(Object tag) { 21566 if (tag == null) { 21567 return null; 21568 } 21569 return findViewWithTagTraversal(tag); 21570 } 21571 21572 /** 21573 * Look for a child view that matches the specified predicate. 21574 * If this view matches the predicate, return this view. 21575 * 21576 * @param predicate The predicate to evaluate. 21577 * @return The first view that matches the predicate or null. 21578 * @hide 21579 */ 21580 public final <T extends View> T findViewByPredicate(Predicate<View> predicate) { 21581 return findViewByPredicateTraversal(predicate, null); 21582 } 21583 21584 /** 21585 * Look for a child view that matches the specified predicate, 21586 * starting with the specified view and its descendents and then 21587 * recusively searching the ancestors and siblings of that view 21588 * until this view is reached. 21589 * 21590 * This method is useful in cases where the predicate does not match 21591 * a single unique view (perhaps multiple views use the same id) 21592 * and we are trying to find the view that is "closest" in scope to the 21593 * starting view. 21594 * 21595 * @param start The view to start from. 21596 * @param predicate The predicate to evaluate. 21597 * @return The first view that matches the predicate or null. 21598 * @hide 21599 */ 21600 public final <T extends View> T findViewByPredicateInsideOut( 21601 View start, Predicate<View> predicate) { 21602 View childToSkip = null; 21603 for (;;) { 21604 T view = start.findViewByPredicateTraversal(predicate, childToSkip); 21605 if (view != null || start == this) { 21606 return view; 21607 } 21608 21609 ViewParent parent = start.getParent(); 21610 if (parent == null || !(parent instanceof View)) { 21611 return null; 21612 } 21613 21614 childToSkip = start; 21615 start = (View) parent; 21616 } 21617 } 21618 21619 /** 21620 * Sets the identifier for this view. The identifier does not have to be 21621 * unique in this view's hierarchy. The identifier should be a positive 21622 * number. 21623 * 21624 * @see #NO_ID 21625 * @see #getId() 21626 * @see #findViewById(int) 21627 * 21628 * @param id a number used to identify the view 21629 * 21630 * @attr ref android.R.styleable#View_id 21631 */ 21632 public void setId(@IdRes int id) { 21633 mID = id; 21634 if (mID == View.NO_ID && mLabelForId != View.NO_ID) { 21635 mID = generateViewId(); 21636 } 21637 } 21638 21639 /** 21640 * {@hide} 21641 * 21642 * @param isRoot true if the view belongs to the root namespace, false 21643 * otherwise 21644 */ 21645 public void setIsRootNamespace(boolean isRoot) { 21646 if (isRoot) { 21647 mPrivateFlags |= PFLAG_IS_ROOT_NAMESPACE; 21648 } else { 21649 mPrivateFlags &= ~PFLAG_IS_ROOT_NAMESPACE; 21650 } 21651 } 21652 21653 /** 21654 * {@hide} 21655 * 21656 * @return true if the view belongs to the root namespace, false otherwise 21657 */ 21658 public boolean isRootNamespace() { 21659 return (mPrivateFlags&PFLAG_IS_ROOT_NAMESPACE) != 0; 21660 } 21661 21662 /** 21663 * Returns this view's identifier. 21664 * 21665 * @return a positive integer used to identify the view or {@link #NO_ID} 21666 * if the view has no ID 21667 * 21668 * @see #setId(int) 21669 * @see #findViewById(int) 21670 * @attr ref android.R.styleable#View_id 21671 */ 21672 @IdRes 21673 @ViewDebug.CapturedViewProperty 21674 public int getId() { 21675 return mID; 21676 } 21677 21678 /** 21679 * Returns this view's tag. 21680 * 21681 * @return the Object stored in this view as a tag, or {@code null} if not 21682 * set 21683 * 21684 * @see #setTag(Object) 21685 * @see #getTag(int) 21686 */ 21687 @ViewDebug.ExportedProperty 21688 public Object getTag() { 21689 return mTag; 21690 } 21691 21692 /** 21693 * Sets the tag associated with this view. A tag can be used to mark 21694 * a view in its hierarchy and does not have to be unique within the 21695 * hierarchy. Tags can also be used to store data within a view without 21696 * resorting to another data structure. 21697 * 21698 * @param tag an Object to tag the view with 21699 * 21700 * @see #getTag() 21701 * @see #setTag(int, Object) 21702 */ 21703 public void setTag(final Object tag) { 21704 mTag = tag; 21705 } 21706 21707 /** 21708 * Returns the tag associated with this view and the specified key. 21709 * 21710 * @param key The key identifying the tag 21711 * 21712 * @return the Object stored in this view as a tag, or {@code null} if not 21713 * set 21714 * 21715 * @see #setTag(int, Object) 21716 * @see #getTag() 21717 */ 21718 public Object getTag(int key) { 21719 if (mKeyedTags != null) return mKeyedTags.get(key); 21720 return null; 21721 } 21722 21723 /** 21724 * Sets a tag associated with this view and a key. A tag can be used 21725 * to mark a view in its hierarchy and does not have to be unique within 21726 * the hierarchy. Tags can also be used to store data within a view 21727 * without resorting to another data structure. 21728 * 21729 * The specified key should be an id declared in the resources of the 21730 * application to ensure it is unique (see the <a 21731 * href="{@docRoot}guide/topics/resources/more-resources.html#Id">ID resource type</a>). 21732 * Keys identified as belonging to 21733 * the Android framework or not associated with any package will cause 21734 * an {@link IllegalArgumentException} to be thrown. 21735 * 21736 * @param key The key identifying the tag 21737 * @param tag An Object to tag the view with 21738 * 21739 * @throws IllegalArgumentException If they specified key is not valid 21740 * 21741 * @see #setTag(Object) 21742 * @see #getTag(int) 21743 */ 21744 public void setTag(int key, final Object tag) { 21745 // If the package id is 0x00 or 0x01, it's either an undefined package 21746 // or a framework id 21747 if ((key >>> 24) < 2) { 21748 throw new IllegalArgumentException("The key must be an application-specific " 21749 + "resource id."); 21750 } 21751 21752 setKeyedTag(key, tag); 21753 } 21754 21755 /** 21756 * Variation of {@link #setTag(int, Object)} that enforces the key to be a 21757 * framework id. 21758 * 21759 * @hide 21760 */ 21761 public void setTagInternal(int key, Object tag) { 21762 if ((key >>> 24) != 0x1) { 21763 throw new IllegalArgumentException("The key must be a framework-specific " 21764 + "resource id."); 21765 } 21766 21767 setKeyedTag(key, tag); 21768 } 21769 21770 private void setKeyedTag(int key, Object tag) { 21771 if (mKeyedTags == null) { 21772 mKeyedTags = new SparseArray<Object>(2); 21773 } 21774 21775 mKeyedTags.put(key, tag); 21776 } 21777 21778 /** 21779 * Prints information about this view in the log output, with the tag 21780 * {@link #VIEW_LOG_TAG}. 21781 * 21782 * @hide 21783 */ 21784 public void debug() { 21785 debug(0); 21786 } 21787 21788 /** 21789 * Prints information about this view in the log output, with the tag 21790 * {@link #VIEW_LOG_TAG}. Each line in the output is preceded with an 21791 * indentation defined by the <code>depth</code>. 21792 * 21793 * @param depth the indentation level 21794 * 21795 * @hide 21796 */ 21797 protected void debug(int depth) { 21798 String output = debugIndent(depth - 1); 21799 21800 output += "+ " + this; 21801 int id = getId(); 21802 if (id != -1) { 21803 output += " (id=" + id + ")"; 21804 } 21805 Object tag = getTag(); 21806 if (tag != null) { 21807 output += " (tag=" + tag + ")"; 21808 } 21809 Log.d(VIEW_LOG_TAG, output); 21810 21811 if ((mPrivateFlags & PFLAG_FOCUSED) != 0) { 21812 output = debugIndent(depth) + " FOCUSED"; 21813 Log.d(VIEW_LOG_TAG, output); 21814 } 21815 21816 output = debugIndent(depth); 21817 output += "frame={" + mLeft + ", " + mTop + ", " + mRight 21818 + ", " + mBottom + "} scroll={" + mScrollX + ", " + mScrollY 21819 + "} "; 21820 Log.d(VIEW_LOG_TAG, output); 21821 21822 if (mPaddingLeft != 0 || mPaddingTop != 0 || mPaddingRight != 0 21823 || mPaddingBottom != 0) { 21824 output = debugIndent(depth); 21825 output += "padding={" + mPaddingLeft + ", " + mPaddingTop 21826 + ", " + mPaddingRight + ", " + mPaddingBottom + "}"; 21827 Log.d(VIEW_LOG_TAG, output); 21828 } 21829 21830 output = debugIndent(depth); 21831 output += "mMeasureWidth=" + mMeasuredWidth + 21832 " mMeasureHeight=" + mMeasuredHeight; 21833 Log.d(VIEW_LOG_TAG, output); 21834 21835 output = debugIndent(depth); 21836 if (mLayoutParams == null) { 21837 output += "BAD! no layout params"; 21838 } else { 21839 output = mLayoutParams.debug(output); 21840 } 21841 Log.d(VIEW_LOG_TAG, output); 21842 21843 output = debugIndent(depth); 21844 output += "flags={"; 21845 output += View.printFlags(mViewFlags); 21846 output += "}"; 21847 Log.d(VIEW_LOG_TAG, output); 21848 21849 output = debugIndent(depth); 21850 output += "privateFlags={"; 21851 output += View.printPrivateFlags(mPrivateFlags); 21852 output += "}"; 21853 Log.d(VIEW_LOG_TAG, output); 21854 } 21855 21856 /** 21857 * Creates a string of whitespaces used for indentation. 21858 * 21859 * @param depth the indentation level 21860 * @return a String containing (depth * 2 + 3) * 2 white spaces 21861 * 21862 * @hide 21863 */ 21864 protected static String debugIndent(int depth) { 21865 StringBuilder spaces = new StringBuilder((depth * 2 + 3) * 2); 21866 for (int i = 0; i < (depth * 2) + 3; i++) { 21867 spaces.append(' ').append(' '); 21868 } 21869 return spaces.toString(); 21870 } 21871 21872 /** 21873 * <p>Return the offset of the widget's text baseline from the widget's top 21874 * boundary. If this widget does not support baseline alignment, this 21875 * method returns -1. </p> 21876 * 21877 * @return the offset of the baseline within the widget's bounds or -1 21878 * if baseline alignment is not supported 21879 */ 21880 @ViewDebug.ExportedProperty(category = "layout") 21881 public int getBaseline() { 21882 return -1; 21883 } 21884 21885 /** 21886 * Returns whether the view hierarchy is currently undergoing a layout pass. This 21887 * information is useful to avoid situations such as calling {@link #requestLayout()} during 21888 * a layout pass. 21889 * 21890 * @return whether the view hierarchy is currently undergoing a layout pass 21891 */ 21892 public boolean isInLayout() { 21893 ViewRootImpl viewRoot = getViewRootImpl(); 21894 return (viewRoot != null && viewRoot.isInLayout()); 21895 } 21896 21897 /** 21898 * Call this when something has changed which has invalidated the 21899 * layout of this view. This will schedule a layout pass of the view 21900 * tree. This should not be called while the view hierarchy is currently in a layout 21901 * pass ({@link #isInLayout()}. If layout is happening, the request may be honored at the 21902 * end of the current layout pass (and then layout will run again) or after the current 21903 * frame is drawn and the next layout occurs. 21904 * 21905 * <p>Subclasses which override this method should call the superclass method to 21906 * handle possible request-during-layout errors correctly.</p> 21907 */ 21908 @CallSuper 21909 public void requestLayout() { 21910 if (mMeasureCache != null) mMeasureCache.clear(); 21911 21912 if (mAttachInfo != null && mAttachInfo.mViewRequestingLayout == null) { 21913 // Only trigger request-during-layout logic if this is the view requesting it, 21914 // not the views in its parent hierarchy 21915 ViewRootImpl viewRoot = getViewRootImpl(); 21916 if (viewRoot != null && viewRoot.isInLayout()) { 21917 if (!viewRoot.requestLayoutDuringLayout(this)) { 21918 return; 21919 } 21920 } 21921 mAttachInfo.mViewRequestingLayout = this; 21922 } 21923 21924 mPrivateFlags |= PFLAG_FORCE_LAYOUT; 21925 mPrivateFlags |= PFLAG_INVALIDATED; 21926 21927 if (mParent != null && !mParent.isLayoutRequested()) { 21928 mParent.requestLayout(); 21929 } 21930 if (mAttachInfo != null && mAttachInfo.mViewRequestingLayout == this) { 21931 mAttachInfo.mViewRequestingLayout = null; 21932 } 21933 } 21934 21935 /** 21936 * Forces this view to be laid out during the next layout pass. 21937 * This method does not call requestLayout() or forceLayout() 21938 * on the parent. 21939 */ 21940 public void forceLayout() { 21941 if (mMeasureCache != null) mMeasureCache.clear(); 21942 21943 mPrivateFlags |= PFLAG_FORCE_LAYOUT; 21944 mPrivateFlags |= PFLAG_INVALIDATED; 21945 } 21946 21947 /** 21948 * <p> 21949 * This is called to find out how big a view should be. The parent 21950 * supplies constraint information in the width and height parameters. 21951 * </p> 21952 * 21953 * <p> 21954 * The actual measurement work of a view is performed in 21955 * {@link #onMeasure(int, int)}, called by this method. Therefore, only 21956 * {@link #onMeasure(int, int)} can and must be overridden by subclasses. 21957 * </p> 21958 * 21959 * 21960 * @param widthMeasureSpec Horizontal space requirements as imposed by the 21961 * parent 21962 * @param heightMeasureSpec Vertical space requirements as imposed by the 21963 * parent 21964 * 21965 * @see #onMeasure(int, int) 21966 */ 21967 public final void measure(int widthMeasureSpec, int heightMeasureSpec) { 21968 boolean optical = isLayoutModeOptical(this); 21969 if (optical != isLayoutModeOptical(mParent)) { 21970 Insets insets = getOpticalInsets(); 21971 int oWidth = insets.left + insets.right; 21972 int oHeight = insets.top + insets.bottom; 21973 widthMeasureSpec = MeasureSpec.adjust(widthMeasureSpec, optical ? -oWidth : oWidth); 21974 heightMeasureSpec = MeasureSpec.adjust(heightMeasureSpec, optical ? -oHeight : oHeight); 21975 } 21976 21977 // Suppress sign extension for the low bytes 21978 long key = (long) widthMeasureSpec << 32 | (long) heightMeasureSpec & 0xffffffffL; 21979 if (mMeasureCache == null) mMeasureCache = new LongSparseLongArray(2); 21980 21981 final boolean forceLayout = (mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT; 21982 21983 // Optimize layout by avoiding an extra EXACTLY pass when the view is 21984 // already measured as the correct size. In API 23 and below, this 21985 // extra pass is required to make LinearLayout re-distribute weight. 21986 final boolean specChanged = widthMeasureSpec != mOldWidthMeasureSpec 21987 || heightMeasureSpec != mOldHeightMeasureSpec; 21988 final boolean isSpecExactly = MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY 21989 && MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.EXACTLY; 21990 final boolean matchesSpecSize = getMeasuredWidth() == MeasureSpec.getSize(widthMeasureSpec) 21991 && getMeasuredHeight() == MeasureSpec.getSize(heightMeasureSpec); 21992 final boolean needsLayout = specChanged 21993 && (sAlwaysRemeasureExactly || !isSpecExactly || !matchesSpecSize); 21994 21995 if (forceLayout || needsLayout) { 21996 // first clears the measured dimension flag 21997 mPrivateFlags &= ~PFLAG_MEASURED_DIMENSION_SET; 21998 21999 resolveRtlPropertiesIfNeeded(); 22000 22001 int cacheIndex = forceLayout ? -1 : mMeasureCache.indexOfKey(key); 22002 if (cacheIndex < 0 || sIgnoreMeasureCache) { 22003 // measure ourselves, this should set the measured dimension flag back 22004 onMeasure(widthMeasureSpec, heightMeasureSpec); 22005 mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT; 22006 } else { 22007 long value = mMeasureCache.valueAt(cacheIndex); 22008 // Casting a long to int drops the high 32 bits, no mask needed 22009 setMeasuredDimensionRaw((int) (value >> 32), (int) value); 22010 mPrivateFlags3 |= PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT; 22011 } 22012 22013 // flag not set, setMeasuredDimension() was not invoked, we raise 22014 // an exception to warn the developer 22015 if ((mPrivateFlags & PFLAG_MEASURED_DIMENSION_SET) != PFLAG_MEASURED_DIMENSION_SET) { 22016 throw new IllegalStateException("View with id " + getId() + ": " 22017 + getClass().getName() + "#onMeasure() did not set the" 22018 + " measured dimension by calling" 22019 + " setMeasuredDimension()"); 22020 } 22021 22022 mPrivateFlags |= PFLAG_LAYOUT_REQUIRED; 22023 } 22024 22025 mOldWidthMeasureSpec = widthMeasureSpec; 22026 mOldHeightMeasureSpec = heightMeasureSpec; 22027 22028 mMeasureCache.put(key, ((long) mMeasuredWidth) << 32 | 22029 (long) mMeasuredHeight & 0xffffffffL); // suppress sign extension 22030 } 22031 22032 /** 22033 * <p> 22034 * Measure the view and its content to determine the measured width and the 22035 * measured height. This method is invoked by {@link #measure(int, int)} and 22036 * should be overridden by subclasses to provide accurate and efficient 22037 * measurement of their contents. 22038 * </p> 22039 * 22040 * <p> 22041 * <strong>CONTRACT:</strong> When overriding this method, you 22042 * <em>must</em> call {@link #setMeasuredDimension(int, int)} to store the 22043 * measured width and height of this view. Failure to do so will trigger an 22044 * <code>IllegalStateException</code>, thrown by 22045 * {@link #measure(int, int)}. Calling the superclass' 22046 * {@link #onMeasure(int, int)} is a valid use. 22047 * </p> 22048 * 22049 * <p> 22050 * The base class implementation of measure defaults to the background size, 22051 * unless a larger size is allowed by the MeasureSpec. Subclasses should 22052 * override {@link #onMeasure(int, int)} to provide better measurements of 22053 * their content. 22054 * </p> 22055 * 22056 * <p> 22057 * If this method is overridden, it is the subclass's responsibility to make 22058 * sure the measured height and width are at least the view's minimum height 22059 * and width ({@link #getSuggestedMinimumHeight()} and 22060 * {@link #getSuggestedMinimumWidth()}). 22061 * </p> 22062 * 22063 * @param widthMeasureSpec horizontal space requirements as imposed by the parent. 22064 * The requirements are encoded with 22065 * {@link android.view.View.MeasureSpec}. 22066 * @param heightMeasureSpec vertical space requirements as imposed by the parent. 22067 * The requirements are encoded with 22068 * {@link android.view.View.MeasureSpec}. 22069 * 22070 * @see #getMeasuredWidth() 22071 * @see #getMeasuredHeight() 22072 * @see #setMeasuredDimension(int, int) 22073 * @see #getSuggestedMinimumHeight() 22074 * @see #getSuggestedMinimumWidth() 22075 * @see android.view.View.MeasureSpec#getMode(int) 22076 * @see android.view.View.MeasureSpec#getSize(int) 22077 */ 22078 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 22079 setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec), 22080 getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec)); 22081 } 22082 22083 /** 22084 * <p>This method must be called by {@link #onMeasure(int, int)} to store the 22085 * measured width and measured height. Failing to do so will trigger an 22086 * exception at measurement time.</p> 22087 * 22088 * @param measuredWidth The measured width of this view. May be a complex 22089 * bit mask as defined by {@link #MEASURED_SIZE_MASK} and 22090 * {@link #MEASURED_STATE_TOO_SMALL}. 22091 * @param measuredHeight The measured height of this view. May be a complex 22092 * bit mask as defined by {@link #MEASURED_SIZE_MASK} and 22093 * {@link #MEASURED_STATE_TOO_SMALL}. 22094 */ 22095 protected final void setMeasuredDimension(int measuredWidth, int measuredHeight) { 22096 boolean optical = isLayoutModeOptical(this); 22097 if (optical != isLayoutModeOptical(mParent)) { 22098 Insets insets = getOpticalInsets(); 22099 int opticalWidth = insets.left + insets.right; 22100 int opticalHeight = insets.top + insets.bottom; 22101 22102 measuredWidth += optical ? opticalWidth : -opticalWidth; 22103 measuredHeight += optical ? opticalHeight : -opticalHeight; 22104 } 22105 setMeasuredDimensionRaw(measuredWidth, measuredHeight); 22106 } 22107 22108 /** 22109 * Sets the measured dimension without extra processing for things like optical bounds. 22110 * Useful for reapplying consistent values that have already been cooked with adjustments 22111 * for optical bounds, etc. such as those from the measurement cache. 22112 * 22113 * @param measuredWidth The measured width of this view. May be a complex 22114 * bit mask as defined by {@link #MEASURED_SIZE_MASK} and 22115 * {@link #MEASURED_STATE_TOO_SMALL}. 22116 * @param measuredHeight The measured height of this view. May be a complex 22117 * bit mask as defined by {@link #MEASURED_SIZE_MASK} and 22118 * {@link #MEASURED_STATE_TOO_SMALL}. 22119 */ 22120 private void setMeasuredDimensionRaw(int measuredWidth, int measuredHeight) { 22121 mMeasuredWidth = measuredWidth; 22122 mMeasuredHeight = measuredHeight; 22123 22124 mPrivateFlags |= PFLAG_MEASURED_DIMENSION_SET; 22125 } 22126 22127 /** 22128 * Merge two states as returned by {@link #getMeasuredState()}. 22129 * @param curState The current state as returned from a view or the result 22130 * of combining multiple views. 22131 * @param newState The new view state to combine. 22132 * @return Returns a new integer reflecting the combination of the two 22133 * states. 22134 */ 22135 public static int combineMeasuredStates(int curState, int newState) { 22136 return curState | newState; 22137 } 22138 22139 /** 22140 * Version of {@link #resolveSizeAndState(int, int, int)} 22141 * returning only the {@link #MEASURED_SIZE_MASK} bits of the result. 22142 */ 22143 public static int resolveSize(int size, int measureSpec) { 22144 return resolveSizeAndState(size, measureSpec, 0) & MEASURED_SIZE_MASK; 22145 } 22146 22147 /** 22148 * Utility to reconcile a desired size and state, with constraints imposed 22149 * by a MeasureSpec. Will take the desired size, unless a different size 22150 * is imposed by the constraints. The returned value is a compound integer, 22151 * with the resolved size in the {@link #MEASURED_SIZE_MASK} bits and 22152 * optionally the bit {@link #MEASURED_STATE_TOO_SMALL} set if the 22153 * resulting size is smaller than the size the view wants to be. 22154 * 22155 * @param size How big the view wants to be. 22156 * @param measureSpec Constraints imposed by the parent. 22157 * @param childMeasuredState Size information bit mask for the view's 22158 * children. 22159 * @return Size information bit mask as defined by 22160 * {@link #MEASURED_SIZE_MASK} and 22161 * {@link #MEASURED_STATE_TOO_SMALL}. 22162 */ 22163 public static int resolveSizeAndState(int size, int measureSpec, int childMeasuredState) { 22164 final int specMode = MeasureSpec.getMode(measureSpec); 22165 final int specSize = MeasureSpec.getSize(measureSpec); 22166 final int result; 22167 switch (specMode) { 22168 case MeasureSpec.AT_MOST: 22169 if (specSize < size) { 22170 result = specSize | MEASURED_STATE_TOO_SMALL; 22171 } else { 22172 result = size; 22173 } 22174 break; 22175 case MeasureSpec.EXACTLY: 22176 result = specSize; 22177 break; 22178 case MeasureSpec.UNSPECIFIED: 22179 default: 22180 result = size; 22181 } 22182 return result | (childMeasuredState & MEASURED_STATE_MASK); 22183 } 22184 22185 /** 22186 * Utility to return a default size. Uses the supplied size if the 22187 * MeasureSpec imposed no constraints. Will get larger if allowed 22188 * by the MeasureSpec. 22189 * 22190 * @param size Default size for this view 22191 * @param measureSpec Constraints imposed by the parent 22192 * @return The size this view should be. 22193 */ 22194 public static int getDefaultSize(int size, int measureSpec) { 22195 int result = size; 22196 int specMode = MeasureSpec.getMode(measureSpec); 22197 int specSize = MeasureSpec.getSize(measureSpec); 22198 22199 switch (specMode) { 22200 case MeasureSpec.UNSPECIFIED: 22201 result = size; 22202 break; 22203 case MeasureSpec.AT_MOST: 22204 case MeasureSpec.EXACTLY: 22205 result = specSize; 22206 break; 22207 } 22208 return result; 22209 } 22210 22211 /** 22212 * Returns the suggested minimum height that the view should use. This 22213 * returns the maximum of the view's minimum height 22214 * and the background's minimum height 22215 * ({@link android.graphics.drawable.Drawable#getMinimumHeight()}). 22216 * <p> 22217 * When being used in {@link #onMeasure(int, int)}, the caller should still 22218 * ensure the returned height is within the requirements of the parent. 22219 * 22220 * @return The suggested minimum height of the view. 22221 */ 22222 protected int getSuggestedMinimumHeight() { 22223 return (mBackground == null) ? mMinHeight : max(mMinHeight, mBackground.getMinimumHeight()); 22224 22225 } 22226 22227 /** 22228 * Returns the suggested minimum width that the view should use. This 22229 * returns the maximum of the view's minimum width 22230 * and the background's minimum width 22231 * ({@link android.graphics.drawable.Drawable#getMinimumWidth()}). 22232 * <p> 22233 * When being used in {@link #onMeasure(int, int)}, the caller should still 22234 * ensure the returned width is within the requirements of the parent. 22235 * 22236 * @return The suggested minimum width of the view. 22237 */ 22238 protected int getSuggestedMinimumWidth() { 22239 return (mBackground == null) ? mMinWidth : max(mMinWidth, mBackground.getMinimumWidth()); 22240 } 22241 22242 /** 22243 * Returns the minimum height of the view. 22244 * 22245 * @return the minimum height the view will try to be, in pixels 22246 * 22247 * @see #setMinimumHeight(int) 22248 * 22249 * @attr ref android.R.styleable#View_minHeight 22250 */ 22251 public int getMinimumHeight() { 22252 return mMinHeight; 22253 } 22254 22255 /** 22256 * Sets the minimum height of the view. It is not guaranteed the view will 22257 * be able to achieve this minimum height (for example, if its parent layout 22258 * constrains it with less available height). 22259 * 22260 * @param minHeight The minimum height the view will try to be, in pixels 22261 * 22262 * @see #getMinimumHeight() 22263 * 22264 * @attr ref android.R.styleable#View_minHeight 22265 */ 22266 @RemotableViewMethod 22267 public void setMinimumHeight(int minHeight) { 22268 mMinHeight = minHeight; 22269 requestLayout(); 22270 } 22271 22272 /** 22273 * Returns the minimum width of the view. 22274 * 22275 * @return the minimum width the view will try to be, in pixels 22276 * 22277 * @see #setMinimumWidth(int) 22278 * 22279 * @attr ref android.R.styleable#View_minWidth 22280 */ 22281 public int getMinimumWidth() { 22282 return mMinWidth; 22283 } 22284 22285 /** 22286 * Sets the minimum width of the view. It is not guaranteed the view will 22287 * be able to achieve this minimum width (for example, if its parent layout 22288 * constrains it with less available width). 22289 * 22290 * @param minWidth The minimum width the view will try to be, in pixels 22291 * 22292 * @see #getMinimumWidth() 22293 * 22294 * @attr ref android.R.styleable#View_minWidth 22295 */ 22296 public void setMinimumWidth(int minWidth) { 22297 mMinWidth = minWidth; 22298 requestLayout(); 22299 22300 } 22301 22302 /** 22303 * Get the animation currently associated with this view. 22304 * 22305 * @return The animation that is currently playing or 22306 * scheduled to play for this view. 22307 */ 22308 public Animation getAnimation() { 22309 return mCurrentAnimation; 22310 } 22311 22312 /** 22313 * Start the specified animation now. 22314 * 22315 * @param animation the animation to start now 22316 */ 22317 public void startAnimation(Animation animation) { 22318 animation.setStartTime(Animation.START_ON_FIRST_FRAME); 22319 setAnimation(animation); 22320 invalidateParentCaches(); 22321 invalidate(true); 22322 } 22323 22324 /** 22325 * Cancels any animations for this view. 22326 */ 22327 public void clearAnimation() { 22328 if (mCurrentAnimation != null) { 22329 mCurrentAnimation.detach(); 22330 } 22331 mCurrentAnimation = null; 22332 invalidateParentIfNeeded(); 22333 } 22334 22335 /** 22336 * Sets the next animation to play for this view. 22337 * If you want the animation to play immediately, use 22338 * {@link #startAnimation(android.view.animation.Animation)} instead. 22339 * This method provides allows fine-grained 22340 * control over the start time and invalidation, but you 22341 * must make sure that 1) the animation has a start time set, and 22342 * 2) the view's parent (which controls animations on its children) 22343 * will be invalidated when the animation is supposed to 22344 * start. 22345 * 22346 * @param animation The next animation, or null. 22347 */ 22348 public void setAnimation(Animation animation) { 22349 mCurrentAnimation = animation; 22350 22351 if (animation != null) { 22352 // If the screen is off assume the animation start time is now instead of 22353 // the next frame we draw. Keeping the START_ON_FIRST_FRAME start time 22354 // would cause the animation to start when the screen turns back on 22355 if (mAttachInfo != null && mAttachInfo.mDisplayState == Display.STATE_OFF 22356 && animation.getStartTime() == Animation.START_ON_FIRST_FRAME) { 22357 animation.setStartTime(AnimationUtils.currentAnimationTimeMillis()); 22358 } 22359 animation.reset(); 22360 } 22361 } 22362 22363 /** 22364 * Invoked by a parent ViewGroup to notify the start of the animation 22365 * currently associated with this view. If you override this method, 22366 * always call super.onAnimationStart(); 22367 * 22368 * @see #setAnimation(android.view.animation.Animation) 22369 * @see #getAnimation() 22370 */ 22371 @CallSuper 22372 protected void onAnimationStart() { 22373 mPrivateFlags |= PFLAG_ANIMATION_STARTED; 22374 } 22375 22376 /** 22377 * Invoked by a parent ViewGroup to notify the end of the animation 22378 * currently associated with this view. If you override this method, 22379 * always call super.onAnimationEnd(); 22380 * 22381 * @see #setAnimation(android.view.animation.Animation) 22382 * @see #getAnimation() 22383 */ 22384 @CallSuper 22385 protected void onAnimationEnd() { 22386 mPrivateFlags &= ~PFLAG_ANIMATION_STARTED; 22387 } 22388 22389 /** 22390 * Invoked if there is a Transform that involves alpha. Subclass that can 22391 * draw themselves with the specified alpha should return true, and then 22392 * respect that alpha when their onDraw() is called. If this returns false 22393 * then the view may be redirected to draw into an offscreen buffer to 22394 * fulfill the request, which will look fine, but may be slower than if the 22395 * subclass handles it internally. The default implementation returns false. 22396 * 22397 * @param alpha The alpha (0..255) to apply to the view's drawing 22398 * @return true if the view can draw with the specified alpha. 22399 */ 22400 protected boolean onSetAlpha(int alpha) { 22401 return false; 22402 } 22403 22404 /** 22405 * This is used by the RootView to perform an optimization when 22406 * the view hierarchy contains one or several SurfaceView. 22407 * SurfaceView is always considered transparent, but its children are not, 22408 * therefore all View objects remove themselves from the global transparent 22409 * region (passed as a parameter to this function). 22410 * 22411 * @param region The transparent region for this ViewAncestor (window). 22412 * 22413 * @return Returns true if the effective visibility of the view at this 22414 * point is opaque, regardless of the transparent region; returns false 22415 * if it is possible for underlying windows to be seen behind the view. 22416 * 22417 * {@hide} 22418 */ 22419 public boolean gatherTransparentRegion(Region region) { 22420 final AttachInfo attachInfo = mAttachInfo; 22421 if (region != null && attachInfo != null) { 22422 final int pflags = mPrivateFlags; 22423 if ((pflags & PFLAG_SKIP_DRAW) == 0) { 22424 // The SKIP_DRAW flag IS NOT set, so this view draws. We need to 22425 // remove it from the transparent region. 22426 final int[] location = attachInfo.mTransparentLocation; 22427 getLocationInWindow(location); 22428 // When a view has Z value, then it will be better to leave some area below the view 22429 // for drawing shadow. The shadow outset is proportional to the Z value. Note that 22430 // the bottom part needs more offset than the left, top and right parts due to the 22431 // spot light effects. 22432 int shadowOffset = getZ() > 0 ? (int) getZ() : 0; 22433 region.op(location[0] - shadowOffset, location[1] - shadowOffset, 22434 location[0] + mRight - mLeft + shadowOffset, 22435 location[1] + mBottom - mTop + (shadowOffset * 3), Region.Op.DIFFERENCE); 22436 } else { 22437 if (mBackground != null && mBackground.getOpacity() != PixelFormat.TRANSPARENT) { 22438 // The SKIP_DRAW flag IS set and the background drawable exists, we remove 22439 // the background drawable's non-transparent parts from this transparent region. 22440 applyDrawableToTransparentRegion(mBackground, region); 22441 } 22442 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null 22443 && mForegroundInfo.mDrawable.getOpacity() != PixelFormat.TRANSPARENT) { 22444 // Similarly, we remove the foreground drawable's non-transparent parts. 22445 applyDrawableToTransparentRegion(mForegroundInfo.mDrawable, region); 22446 } 22447 if (mDefaultFocusHighlight != null 22448 && mDefaultFocusHighlight.getOpacity() != PixelFormat.TRANSPARENT) { 22449 // Similarly, we remove the default focus highlight's non-transparent parts. 22450 applyDrawableToTransparentRegion(mDefaultFocusHighlight, region); 22451 } 22452 } 22453 } 22454 return true; 22455 } 22456 22457 /** 22458 * Play a sound effect for this view. 22459 * 22460 * <p>The framework will play sound effects for some built in actions, such as 22461 * clicking, but you may wish to play these effects in your widget, 22462 * for instance, for internal navigation. 22463 * 22464 * <p>The sound effect will only be played if sound effects are enabled by the user, and 22465 * {@link #isSoundEffectsEnabled()} is true. 22466 * 22467 * @param soundConstant One of the constants defined in {@link SoundEffectConstants} 22468 */ 22469 public void playSoundEffect(int soundConstant) { 22470 if (mAttachInfo == null || mAttachInfo.mRootCallbacks == null || !isSoundEffectsEnabled()) { 22471 return; 22472 } 22473 mAttachInfo.mRootCallbacks.playSoundEffect(soundConstant); 22474 } 22475 22476 /** 22477 * BZZZTT!!1! 22478 * 22479 * <p>Provide haptic feedback to the user for this view. 22480 * 22481 * <p>The framework will provide haptic feedback for some built in actions, 22482 * such as long presses, but you may wish to provide feedback for your 22483 * own widget. 22484 * 22485 * <p>The feedback will only be performed if 22486 * {@link #isHapticFeedbackEnabled()} is true. 22487 * 22488 * @param feedbackConstant One of the constants defined in 22489 * {@link HapticFeedbackConstants} 22490 */ 22491 public boolean performHapticFeedback(int feedbackConstant) { 22492 return performHapticFeedback(feedbackConstant, 0); 22493 } 22494 22495 /** 22496 * BZZZTT!!1! 22497 * 22498 * <p>Like {@link #performHapticFeedback(int)}, with additional options. 22499 * 22500 * @param feedbackConstant One of the constants defined in 22501 * {@link HapticFeedbackConstants} 22502 * @param flags Additional flags as per {@link HapticFeedbackConstants}. 22503 */ 22504 public boolean performHapticFeedback(int feedbackConstant, int flags) { 22505 if (mAttachInfo == null) { 22506 return false; 22507 } 22508 //noinspection SimplifiableIfStatement 22509 if ((flags & HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING) == 0 22510 && !isHapticFeedbackEnabled()) { 22511 return false; 22512 } 22513 return mAttachInfo.mRootCallbacks.performHapticFeedback(feedbackConstant, 22514 (flags & HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING) != 0); 22515 } 22516 22517 /** 22518 * Request that the visibility of the status bar or other screen/window 22519 * decorations be changed. 22520 * 22521 * <p>This method is used to put the over device UI into temporary modes 22522 * where the user's attention is focused more on the application content, 22523 * by dimming or hiding surrounding system affordances. This is typically 22524 * used in conjunction with {@link Window#FEATURE_ACTION_BAR_OVERLAY 22525 * Window.FEATURE_ACTION_BAR_OVERLAY}, allowing the applications content 22526 * to be placed behind the action bar (and with these flags other system 22527 * affordances) so that smooth transitions between hiding and showing them 22528 * can be done. 22529 * 22530 * <p>Two representative examples of the use of system UI visibility is 22531 * implementing a content browsing application (like a magazine reader) 22532 * and a video playing application. 22533 * 22534 * <p>The first code shows a typical implementation of a View in a content 22535 * browsing application. In this implementation, the application goes 22536 * into a content-oriented mode by hiding the status bar and action bar, 22537 * and putting the navigation elements into lights out mode. The user can 22538 * then interact with content while in this mode. Such an application should 22539 * provide an easy way for the user to toggle out of the mode (such as to 22540 * check information in the status bar or access notifications). In the 22541 * implementation here, this is done simply by tapping on the content. 22542 * 22543 * {@sample development/samples/ApiDemos/src/com/example/android/apis/view/ContentBrowserActivity.java 22544 * content} 22545 * 22546 * <p>This second code sample shows a typical implementation of a View 22547 * in a video playing application. In this situation, while the video is 22548 * playing the application would like to go into a complete full-screen mode, 22549 * to use as much of the display as possible for the video. When in this state 22550 * the user can not interact with the application; the system intercepts 22551 * touching on the screen to pop the UI out of full screen mode. See 22552 * {@link #fitSystemWindows(Rect)} for a sample layout that goes with this code. 22553 * 22554 * {@sample development/samples/ApiDemos/src/com/example/android/apis/view/VideoPlayerActivity.java 22555 * content} 22556 * 22557 * @param visibility Bitwise-or of flags {@link #SYSTEM_UI_FLAG_LOW_PROFILE}, 22558 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, {@link #SYSTEM_UI_FLAG_FULLSCREEN}, 22559 * {@link #SYSTEM_UI_FLAG_LAYOUT_STABLE}, {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION}, 22560 * {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN}, {@link #SYSTEM_UI_FLAG_IMMERSIVE}, 22561 * and {@link #SYSTEM_UI_FLAG_IMMERSIVE_STICKY}. 22562 */ 22563 public void setSystemUiVisibility(int visibility) { 22564 if (visibility != mSystemUiVisibility) { 22565 mSystemUiVisibility = visibility; 22566 if (mParent != null && mAttachInfo != null && !mAttachInfo.mRecomputeGlobalAttributes) { 22567 mParent.recomputeViewAttributes(this); 22568 } 22569 } 22570 } 22571 22572 /** 22573 * Returns the last {@link #setSystemUiVisibility(int)} that this view has requested. 22574 * @return Bitwise-or of flags {@link #SYSTEM_UI_FLAG_LOW_PROFILE}, 22575 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, {@link #SYSTEM_UI_FLAG_FULLSCREEN}, 22576 * {@link #SYSTEM_UI_FLAG_LAYOUT_STABLE}, {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION}, 22577 * {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN}, {@link #SYSTEM_UI_FLAG_IMMERSIVE}, 22578 * and {@link #SYSTEM_UI_FLAG_IMMERSIVE_STICKY}. 22579 */ 22580 public int getSystemUiVisibility() { 22581 return mSystemUiVisibility; 22582 } 22583 22584 /** 22585 * Returns the current system UI visibility that is currently set for 22586 * the entire window. This is the combination of the 22587 * {@link #setSystemUiVisibility(int)} values supplied by all of the 22588 * views in the window. 22589 */ 22590 public int getWindowSystemUiVisibility() { 22591 return mAttachInfo != null ? mAttachInfo.mSystemUiVisibility : 0; 22592 } 22593 22594 /** 22595 * Override to find out when the window's requested system UI visibility 22596 * has changed, that is the value returned by {@link #getWindowSystemUiVisibility()}. 22597 * This is different from the callbacks received through 22598 * {@link #setOnSystemUiVisibilityChangeListener(OnSystemUiVisibilityChangeListener)} 22599 * in that this is only telling you about the local request of the window, 22600 * not the actual values applied by the system. 22601 */ 22602 public void onWindowSystemUiVisibilityChanged(int visible) { 22603 } 22604 22605 /** 22606 * Dispatch callbacks to {@link #onWindowSystemUiVisibilityChanged(int)} down 22607 * the view hierarchy. 22608 */ 22609 public void dispatchWindowSystemUiVisiblityChanged(int visible) { 22610 onWindowSystemUiVisibilityChanged(visible); 22611 } 22612 22613 /** 22614 * Set a listener to receive callbacks when the visibility of the system bar changes. 22615 * @param l The {@link OnSystemUiVisibilityChangeListener} to receive callbacks. 22616 */ 22617 public void setOnSystemUiVisibilityChangeListener(OnSystemUiVisibilityChangeListener l) { 22618 getListenerInfo().mOnSystemUiVisibilityChangeListener = l; 22619 if (mParent != null && mAttachInfo != null && !mAttachInfo.mRecomputeGlobalAttributes) { 22620 mParent.recomputeViewAttributes(this); 22621 } 22622 } 22623 22624 /** 22625 * Dispatch callbacks to {@link #setOnSystemUiVisibilityChangeListener} down 22626 * the view hierarchy. 22627 */ 22628 public void dispatchSystemUiVisibilityChanged(int visibility) { 22629 ListenerInfo li = mListenerInfo; 22630 if (li != null && li.mOnSystemUiVisibilityChangeListener != null) { 22631 li.mOnSystemUiVisibilityChangeListener.onSystemUiVisibilityChange( 22632 visibility & PUBLIC_STATUS_BAR_VISIBILITY_MASK); 22633 } 22634 } 22635 22636 boolean updateLocalSystemUiVisibility(int localValue, int localChanges) { 22637 int val = (mSystemUiVisibility&~localChanges) | (localValue&localChanges); 22638 if (val != mSystemUiVisibility) { 22639 setSystemUiVisibility(val); 22640 return true; 22641 } 22642 return false; 22643 } 22644 22645 /** @hide */ 22646 public void setDisabledSystemUiVisibility(int flags) { 22647 if (mAttachInfo != null) { 22648 if (mAttachInfo.mDisabledSystemUiVisibility != flags) { 22649 mAttachInfo.mDisabledSystemUiVisibility = flags; 22650 if (mParent != null) { 22651 mParent.recomputeViewAttributes(this); 22652 } 22653 } 22654 } 22655 } 22656 22657 /** 22658 * Creates an image that the system displays during the drag and drop 22659 * operation. This is called a "drag shadow". The default implementation 22660 * for a DragShadowBuilder based on a View returns an image that has exactly the same 22661 * appearance as the given View. The default also positions the center of the drag shadow 22662 * directly under the touch point. If no View is provided (the constructor with no parameters 22663 * is used), and {@link #onProvideShadowMetrics(Point,Point) onProvideShadowMetrics()} and 22664 * {@link #onDrawShadow(Canvas) onDrawShadow()} are not overridden, then the 22665 * default is an invisible drag shadow. 22666 * <p> 22667 * You are not required to use the View you provide to the constructor as the basis of the 22668 * drag shadow. The {@link #onDrawShadow(Canvas) onDrawShadow()} method allows you to draw 22669 * anything you want as the drag shadow. 22670 * </p> 22671 * <p> 22672 * You pass a DragShadowBuilder object to the system when you start the drag. The system 22673 * calls {@link #onProvideShadowMetrics(Point,Point) onProvideShadowMetrics()} to get the 22674 * size and position of the drag shadow. It uses this data to construct a 22675 * {@link android.graphics.Canvas} object, then it calls {@link #onDrawShadow(Canvas) onDrawShadow()} 22676 * so that your application can draw the shadow image in the Canvas. 22677 * </p> 22678 * 22679 * <div class="special reference"> 22680 * <h3>Developer Guides</h3> 22681 * <p>For a guide to implementing drag and drop features, read the 22682 * <a href="{@docRoot}guide/topics/ui/drag-drop.html">Drag and Drop</a> developer guide.</p> 22683 * </div> 22684 */ 22685 public static class DragShadowBuilder { 22686 private final WeakReference<View> mView; 22687 22688 /** 22689 * Constructs a shadow image builder based on a View. By default, the resulting drag 22690 * shadow will have the same appearance and dimensions as the View, with the touch point 22691 * over the center of the View. 22692 * @param view A View. Any View in scope can be used. 22693 */ 22694 public DragShadowBuilder(View view) { 22695 mView = new WeakReference<View>(view); 22696 } 22697 22698 /** 22699 * Construct a shadow builder object with no associated View. This 22700 * constructor variant is only useful when the {@link #onProvideShadowMetrics(Point, Point)} 22701 * and {@link #onDrawShadow(Canvas)} methods are also overridden in order 22702 * to supply the drag shadow's dimensions and appearance without 22703 * reference to any View object. If they are not overridden, then the result is an 22704 * invisible drag shadow. 22705 */ 22706 public DragShadowBuilder() { 22707 mView = new WeakReference<View>(null); 22708 } 22709 22710 /** 22711 * Returns the View object that had been passed to the 22712 * {@link #View.DragShadowBuilder(View)} 22713 * constructor. If that View parameter was {@code null} or if the 22714 * {@link #View.DragShadowBuilder()} 22715 * constructor was used to instantiate the builder object, this method will return 22716 * null. 22717 * 22718 * @return The View object associate with this builder object. 22719 */ 22720 @SuppressWarnings({"JavadocReference"}) 22721 final public View getView() { 22722 return mView.get(); 22723 } 22724 22725 /** 22726 * Provides the metrics for the shadow image. These include the dimensions of 22727 * the shadow image, and the point within that shadow that should 22728 * be centered under the touch location while dragging. 22729 * <p> 22730 * The default implementation sets the dimensions of the shadow to be the 22731 * same as the dimensions of the View itself and centers the shadow under 22732 * the touch point. 22733 * </p> 22734 * 22735 * @param outShadowSize A {@link android.graphics.Point} containing the width and height 22736 * of the shadow image. Your application must set {@link android.graphics.Point#x} to the 22737 * desired width and must set {@link android.graphics.Point#y} to the desired height of the 22738 * image. 22739 * 22740 * @param outShadowTouchPoint A {@link android.graphics.Point} for the position within the 22741 * shadow image that should be underneath the touch point during the drag and drop 22742 * operation. Your application must set {@link android.graphics.Point#x} to the 22743 * X coordinate and {@link android.graphics.Point#y} to the Y coordinate of this position. 22744 */ 22745 public void onProvideShadowMetrics(Point outShadowSize, Point outShadowTouchPoint) { 22746 final View view = mView.get(); 22747 if (view != null) { 22748 outShadowSize.set(view.getWidth(), view.getHeight()); 22749 outShadowTouchPoint.set(outShadowSize.x / 2, outShadowSize.y / 2); 22750 } else { 22751 Log.e(View.VIEW_LOG_TAG, "Asked for drag thumb metrics but no view"); 22752 } 22753 } 22754 22755 /** 22756 * Draws the shadow image. The system creates the {@link android.graphics.Canvas} object 22757 * based on the dimensions it received from the 22758 * {@link #onProvideShadowMetrics(Point, Point)} callback. 22759 * 22760 * @param canvas A {@link android.graphics.Canvas} object in which to draw the shadow image. 22761 */ 22762 public void onDrawShadow(Canvas canvas) { 22763 final View view = mView.get(); 22764 if (view != null) { 22765 view.draw(canvas); 22766 } else { 22767 Log.e(View.VIEW_LOG_TAG, "Asked to draw drag shadow but no view"); 22768 } 22769 } 22770 } 22771 22772 /** 22773 * @deprecated Use {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, int) 22774 * startDragAndDrop()} for newer platform versions. 22775 */ 22776 @Deprecated 22777 public final boolean startDrag(ClipData data, DragShadowBuilder shadowBuilder, 22778 Object myLocalState, int flags) { 22779 return startDragAndDrop(data, shadowBuilder, myLocalState, flags); 22780 } 22781 22782 /** 22783 * Starts a drag and drop operation. When your application calls this method, it passes a 22784 * {@link android.view.View.DragShadowBuilder} object to the system. The 22785 * system calls this object's {@link DragShadowBuilder#onProvideShadowMetrics(Point, Point)} 22786 * to get metrics for the drag shadow, and then calls the object's 22787 * {@link DragShadowBuilder#onDrawShadow(Canvas)} to draw the drag shadow itself. 22788 * <p> 22789 * Once the system has the drag shadow, it begins the drag and drop operation by sending 22790 * drag events to all the View objects in your application that are currently visible. It does 22791 * this either by calling the View object's drag listener (an implementation of 22792 * {@link android.view.View.OnDragListener#onDrag(View,DragEvent) onDrag()} or by calling the 22793 * View object's {@link android.view.View#onDragEvent(DragEvent) onDragEvent()} method. 22794 * Both are passed a {@link android.view.DragEvent} object that has a 22795 * {@link android.view.DragEvent#getAction()} value of 22796 * {@link android.view.DragEvent#ACTION_DRAG_STARTED}. 22797 * </p> 22798 * <p> 22799 * Your application can invoke {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, 22800 * int) startDragAndDrop()} on any attached View object. The View object does not need to be 22801 * the one used in {@link android.view.View.DragShadowBuilder}, nor does it need to be related 22802 * to the View the user selected for dragging. 22803 * </p> 22804 * @param data A {@link android.content.ClipData} object pointing to the data to be 22805 * transferred by the drag and drop operation. 22806 * @param shadowBuilder A {@link android.view.View.DragShadowBuilder} object for building the 22807 * drag shadow. 22808 * @param myLocalState An {@link java.lang.Object} containing local data about the drag and 22809 * drop operation. When dispatching drag events to views in the same activity this object 22810 * will be available through {@link android.view.DragEvent#getLocalState()}. Views in other 22811 * activities will not have access to this data ({@link android.view.DragEvent#getLocalState()} 22812 * will return null). 22813 * <p> 22814 * myLocalState is a lightweight mechanism for the sending information from the dragged View 22815 * to the target Views. For example, it can contain flags that differentiate between a 22816 * a copy operation and a move operation. 22817 * </p> 22818 * @param flags Flags that control the drag and drop operation. This can be set to 0 for no 22819 * flags, or any combination of the following: 22820 * <ul> 22821 * <li>{@link #DRAG_FLAG_GLOBAL}</li> 22822 * <li>{@link #DRAG_FLAG_GLOBAL_PERSISTABLE_URI_PERMISSION}</li> 22823 * <li>{@link #DRAG_FLAG_GLOBAL_PREFIX_URI_PERMISSION}</li> 22824 * <li>{@link #DRAG_FLAG_GLOBAL_URI_READ}</li> 22825 * <li>{@link #DRAG_FLAG_GLOBAL_URI_WRITE}</li> 22826 * <li>{@link #DRAG_FLAG_OPAQUE}</li> 22827 * </ul> 22828 * @return {@code true} if the method completes successfully, or 22829 * {@code false} if it fails anywhere. Returning {@code false} means the system was unable to 22830 * do a drag, and so no drag operation is in progress. 22831 */ 22832 public final boolean startDragAndDrop(ClipData data, DragShadowBuilder shadowBuilder, 22833 Object myLocalState, int flags) { 22834 if (ViewDebug.DEBUG_DRAG) { 22835 Log.d(VIEW_LOG_TAG, "startDragAndDrop: data=" + data + " flags=" + flags); 22836 } 22837 if (mAttachInfo == null) { 22838 Log.w(VIEW_LOG_TAG, "startDragAndDrop called on a detached view."); 22839 return false; 22840 } 22841 22842 if (data != null) { 22843 data.prepareToLeaveProcess((flags & View.DRAG_FLAG_GLOBAL) != 0); 22844 } 22845 22846 boolean okay = false; 22847 22848 Point shadowSize = new Point(); 22849 Point shadowTouchPoint = new Point(); 22850 shadowBuilder.onProvideShadowMetrics(shadowSize, shadowTouchPoint); 22851 22852 if ((shadowSize.x < 0) || (shadowSize.y < 0) || 22853 (shadowTouchPoint.x < 0) || (shadowTouchPoint.y < 0)) { 22854 throw new IllegalStateException("Drag shadow dimensions must not be negative"); 22855 } 22856 22857 if (ViewDebug.DEBUG_DRAG) { 22858 Log.d(VIEW_LOG_TAG, "drag shadow: width=" + shadowSize.x + " height=" + shadowSize.y 22859 + " shadowX=" + shadowTouchPoint.x + " shadowY=" + shadowTouchPoint.y); 22860 } 22861 if (mAttachInfo.mDragSurface != null) { 22862 mAttachInfo.mDragSurface.release(); 22863 } 22864 mAttachInfo.mDragSurface = new Surface(); 22865 try { 22866 mAttachInfo.mDragToken = mAttachInfo.mSession.prepareDrag(mAttachInfo.mWindow, 22867 flags, shadowSize.x, shadowSize.y, mAttachInfo.mDragSurface); 22868 if (ViewDebug.DEBUG_DRAG) Log.d(VIEW_LOG_TAG, "prepareDrag returned token=" 22869 + mAttachInfo.mDragToken + " surface=" + mAttachInfo.mDragSurface); 22870 if (mAttachInfo.mDragToken != null) { 22871 Canvas canvas = mAttachInfo.mDragSurface.lockCanvas(null); 22872 try { 22873 canvas.drawColor(0, PorterDuff.Mode.CLEAR); 22874 shadowBuilder.onDrawShadow(canvas); 22875 } finally { 22876 mAttachInfo.mDragSurface.unlockCanvasAndPost(canvas); 22877 } 22878 22879 final ViewRootImpl root = getViewRootImpl(); 22880 22881 // Cache the local state object for delivery with DragEvents 22882 root.setLocalDragState(myLocalState); 22883 22884 // repurpose 'shadowSize' for the last touch point 22885 root.getLastTouchPoint(shadowSize); 22886 22887 okay = mAttachInfo.mSession.performDrag(mAttachInfo.mWindow, mAttachInfo.mDragToken, 22888 root.getLastTouchSource(), shadowSize.x, shadowSize.y, 22889 shadowTouchPoint.x, shadowTouchPoint.y, data); 22890 if (ViewDebug.DEBUG_DRAG) Log.d(VIEW_LOG_TAG, "performDrag returned " + okay); 22891 } 22892 } catch (Exception e) { 22893 Log.e(VIEW_LOG_TAG, "Unable to initiate drag", e); 22894 mAttachInfo.mDragSurface.destroy(); 22895 mAttachInfo.mDragSurface = null; 22896 } 22897 22898 return okay; 22899 } 22900 22901 /** 22902 * Cancels an ongoing drag and drop operation. 22903 * <p> 22904 * A {@link android.view.DragEvent} object with 22905 * {@link android.view.DragEvent#getAction()} value of 22906 * {@link android.view.DragEvent#ACTION_DRAG_ENDED} and 22907 * {@link android.view.DragEvent#getResult()} value of {@code false} 22908 * will be sent to every 22909 * View that received {@link android.view.DragEvent#ACTION_DRAG_STARTED} 22910 * even if they are not currently visible. 22911 * </p> 22912 * <p> 22913 * This method can be called on any View in the same window as the View on which 22914 * {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, int) startDragAndDrop} 22915 * was called. 22916 * </p> 22917 */ 22918 public final void cancelDragAndDrop() { 22919 if (ViewDebug.DEBUG_DRAG) { 22920 Log.d(VIEW_LOG_TAG, "cancelDragAndDrop"); 22921 } 22922 if (mAttachInfo == null) { 22923 Log.w(VIEW_LOG_TAG, "cancelDragAndDrop called on a detached view."); 22924 return; 22925 } 22926 if (mAttachInfo.mDragToken != null) { 22927 try { 22928 mAttachInfo.mSession.cancelDragAndDrop(mAttachInfo.mDragToken); 22929 } catch (Exception e) { 22930 Log.e(VIEW_LOG_TAG, "Unable to cancel drag", e); 22931 } 22932 mAttachInfo.mDragToken = null; 22933 } else { 22934 Log.e(VIEW_LOG_TAG, "No active drag to cancel"); 22935 } 22936 } 22937 22938 /** 22939 * Updates the drag shadow for the ongoing drag and drop operation. 22940 * 22941 * @param shadowBuilder A {@link android.view.View.DragShadowBuilder} object for building the 22942 * new drag shadow. 22943 */ 22944 public final void updateDragShadow(DragShadowBuilder shadowBuilder) { 22945 if (ViewDebug.DEBUG_DRAG) { 22946 Log.d(VIEW_LOG_TAG, "updateDragShadow"); 22947 } 22948 if (mAttachInfo == null) { 22949 Log.w(VIEW_LOG_TAG, "updateDragShadow called on a detached view."); 22950 return; 22951 } 22952 if (mAttachInfo.mDragToken != null) { 22953 try { 22954 Canvas canvas = mAttachInfo.mDragSurface.lockCanvas(null); 22955 try { 22956 canvas.drawColor(0, PorterDuff.Mode.CLEAR); 22957 shadowBuilder.onDrawShadow(canvas); 22958 } finally { 22959 mAttachInfo.mDragSurface.unlockCanvasAndPost(canvas); 22960 } 22961 } catch (Exception e) { 22962 Log.e(VIEW_LOG_TAG, "Unable to update drag shadow", e); 22963 } 22964 } else { 22965 Log.e(VIEW_LOG_TAG, "No active drag"); 22966 } 22967 } 22968 22969 /** 22970 * Starts a move from {startX, startY}, the amount of the movement will be the offset 22971 * between {startX, startY} and the new cursor positon. 22972 * @param startX horizontal coordinate where the move started. 22973 * @param startY vertical coordinate where the move started. 22974 * @return whether moving was started successfully. 22975 * @hide 22976 */ 22977 public final boolean startMovingTask(float startX, float startY) { 22978 if (ViewDebug.DEBUG_POSITIONING) { 22979 Log.d(VIEW_LOG_TAG, "startMovingTask: {" + startX + "," + startY + "}"); 22980 } 22981 try { 22982 return mAttachInfo.mSession.startMovingTask(mAttachInfo.mWindow, startX, startY); 22983 } catch (RemoteException e) { 22984 Log.e(VIEW_LOG_TAG, "Unable to start moving", e); 22985 } 22986 return false; 22987 } 22988 22989 /** 22990 * Handles drag events sent by the system following a call to 22991 * {@link android.view.View#startDragAndDrop(ClipData,DragShadowBuilder,Object,int) 22992 * startDragAndDrop()}. 22993 *<p> 22994 * When the system calls this method, it passes a 22995 * {@link android.view.DragEvent} object. A call to 22996 * {@link android.view.DragEvent#getAction()} returns one of the action type constants defined 22997 * in DragEvent. The method uses these to determine what is happening in the drag and drop 22998 * operation. 22999 * @param event The {@link android.view.DragEvent} sent by the system. 23000 * The {@link android.view.DragEvent#getAction()} method returns an action type constant defined 23001 * in DragEvent, indicating the type of drag event represented by this object. 23002 * @return {@code true} if the method was successful, otherwise {@code false}. 23003 * <p> 23004 * The method should return {@code true} in response to an action type of 23005 * {@link android.view.DragEvent#ACTION_DRAG_STARTED} to receive drag events for the current 23006 * operation. 23007 * </p> 23008 * <p> 23009 * The method should also return {@code true} in response to an action type of 23010 * {@link android.view.DragEvent#ACTION_DROP} if it consumed the drop, or 23011 * {@code false} if it didn't. 23012 * </p> 23013 * <p> 23014 * For all other events, the return value is ignored. 23015 * </p> 23016 */ 23017 public boolean onDragEvent(DragEvent event) { 23018 return false; 23019 } 23020 23021 // Dispatches ACTION_DRAG_ENTERED and ACTION_DRAG_EXITED events for pre-Nougat apps. 23022 boolean dispatchDragEnterExitInPreN(DragEvent event) { 23023 return callDragEventHandler(event); 23024 } 23025 23026 /** 23027 * Detects if this View is enabled and has a drag event listener. 23028 * If both are true, then it calls the drag event listener with the 23029 * {@link android.view.DragEvent} it received. If the drag event listener returns 23030 * {@code true}, then dispatchDragEvent() returns {@code true}. 23031 * <p> 23032 * For all other cases, the method calls the 23033 * {@link android.view.View#onDragEvent(DragEvent) onDragEvent()} drag event handler 23034 * method and returns its result. 23035 * </p> 23036 * <p> 23037 * This ensures that a drag event is always consumed, even if the View does not have a drag 23038 * event listener. However, if the View has a listener and the listener returns true, then 23039 * onDragEvent() is not called. 23040 * </p> 23041 */ 23042 public boolean dispatchDragEvent(DragEvent event) { 23043 event.mEventHandlerWasCalled = true; 23044 if (event.mAction == DragEvent.ACTION_DRAG_LOCATION || 23045 event.mAction == DragEvent.ACTION_DROP) { 23046 // About to deliver an event with coordinates to this view. Notify that now this view 23047 // has drag focus. This will send exit/enter events as needed. 23048 getViewRootImpl().setDragFocus(this, event); 23049 } 23050 return callDragEventHandler(event); 23051 } 23052 23053 final boolean callDragEventHandler(DragEvent event) { 23054 final boolean result; 23055 23056 ListenerInfo li = mListenerInfo; 23057 //noinspection SimplifiableIfStatement 23058 if (li != null && li.mOnDragListener != null && (mViewFlags & ENABLED_MASK) == ENABLED 23059 && li.mOnDragListener.onDrag(this, event)) { 23060 result = true; 23061 } else { 23062 result = onDragEvent(event); 23063 } 23064 23065 switch (event.mAction) { 23066 case DragEvent.ACTION_DRAG_ENTERED: { 23067 mPrivateFlags2 |= View.PFLAG2_DRAG_HOVERED; 23068 refreshDrawableState(); 23069 } break; 23070 case DragEvent.ACTION_DRAG_EXITED: { 23071 mPrivateFlags2 &= ~View.PFLAG2_DRAG_HOVERED; 23072 refreshDrawableState(); 23073 } break; 23074 case DragEvent.ACTION_DRAG_ENDED: { 23075 mPrivateFlags2 &= ~View.DRAG_MASK; 23076 refreshDrawableState(); 23077 } break; 23078 } 23079 23080 return result; 23081 } 23082 23083 boolean canAcceptDrag() { 23084 return (mPrivateFlags2 & PFLAG2_DRAG_CAN_ACCEPT) != 0; 23085 } 23086 23087 /** 23088 * This needs to be a better API (NOT ON VIEW) before it is exposed. If 23089 * it is ever exposed at all. 23090 * @hide 23091 */ 23092 public void onCloseSystemDialogs(String reason) { 23093 } 23094 23095 /** 23096 * Given a Drawable whose bounds have been set to draw into this view, 23097 * update a Region being computed for 23098 * {@link #gatherTransparentRegion(android.graphics.Region)} so 23099 * that any non-transparent parts of the Drawable are removed from the 23100 * given transparent region. 23101 * 23102 * @param dr The Drawable whose transparency is to be applied to the region. 23103 * @param region A Region holding the current transparency information, 23104 * where any parts of the region that are set are considered to be 23105 * transparent. On return, this region will be modified to have the 23106 * transparency information reduced by the corresponding parts of the 23107 * Drawable that are not transparent. 23108 * {@hide} 23109 */ 23110 public void applyDrawableToTransparentRegion(Drawable dr, Region region) { 23111 if (DBG) { 23112 Log.i("View", "Getting transparent region for: " + this); 23113 } 23114 final Region r = dr.getTransparentRegion(); 23115 final Rect db = dr.getBounds(); 23116 final AttachInfo attachInfo = mAttachInfo; 23117 if (r != null && attachInfo != null) { 23118 final int w = getRight()-getLeft(); 23119 final int h = getBottom()-getTop(); 23120 if (db.left > 0) { 23121 //Log.i("VIEW", "Drawable left " + db.left + " > view 0"); 23122 r.op(0, 0, db.left, h, Region.Op.UNION); 23123 } 23124 if (db.right < w) { 23125 //Log.i("VIEW", "Drawable right " + db.right + " < view " + w); 23126 r.op(db.right, 0, w, h, Region.Op.UNION); 23127 } 23128 if (db.top > 0) { 23129 //Log.i("VIEW", "Drawable top " + db.top + " > view 0"); 23130 r.op(0, 0, w, db.top, Region.Op.UNION); 23131 } 23132 if (db.bottom < h) { 23133 //Log.i("VIEW", "Drawable bottom " + db.bottom + " < view " + h); 23134 r.op(0, db.bottom, w, h, Region.Op.UNION); 23135 } 23136 final int[] location = attachInfo.mTransparentLocation; 23137 getLocationInWindow(location); 23138 r.translate(location[0], location[1]); 23139 region.op(r, Region.Op.INTERSECT); 23140 } else { 23141 region.op(db, Region.Op.DIFFERENCE); 23142 } 23143 } 23144 23145 private void checkForLongClick(int delayOffset, float x, float y) { 23146 if ((mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE || (mViewFlags & TOOLTIP) == TOOLTIP) { 23147 mHasPerformedLongPress = false; 23148 23149 if (mPendingCheckForLongPress == null) { 23150 mPendingCheckForLongPress = new CheckForLongPress(); 23151 } 23152 mPendingCheckForLongPress.setAnchor(x, y); 23153 mPendingCheckForLongPress.rememberWindowAttachCount(); 23154 mPendingCheckForLongPress.rememberPressedState(); 23155 postDelayed(mPendingCheckForLongPress, 23156 ViewConfiguration.getLongPressTimeout() - delayOffset); 23157 } 23158 } 23159 23160 /** 23161 * Inflate a view from an XML resource. This convenience method wraps the {@link 23162 * LayoutInflater} class, which provides a full range of options for view inflation. 23163 * 23164 * @param context The Context object for your activity or application. 23165 * @param resource The resource ID to inflate 23166 * @param root A view group that will be the parent. Used to properly inflate the 23167 * layout_* parameters. 23168 * @see LayoutInflater 23169 */ 23170 public static View inflate(Context context, @LayoutRes int resource, ViewGroup root) { 23171 LayoutInflater factory = LayoutInflater.from(context); 23172 return factory.inflate(resource, root); 23173 } 23174 23175 /** 23176 * Scroll the view with standard behavior for scrolling beyond the normal 23177 * content boundaries. Views that call this method should override 23178 * {@link #onOverScrolled(int, int, boolean, boolean)} to respond to the 23179 * results of an over-scroll operation. 23180 * 23181 * Views can use this method to handle any touch or fling-based scrolling. 23182 * 23183 * @param deltaX Change in X in pixels 23184 * @param deltaY Change in Y in pixels 23185 * @param scrollX Current X scroll value in pixels before applying deltaX 23186 * @param scrollY Current Y scroll value in pixels before applying deltaY 23187 * @param scrollRangeX Maximum content scroll range along the X axis 23188 * @param scrollRangeY Maximum content scroll range along the Y axis 23189 * @param maxOverScrollX Number of pixels to overscroll by in either direction 23190 * along the X axis. 23191 * @param maxOverScrollY Number of pixels to overscroll by in either direction 23192 * along the Y axis. 23193 * @param isTouchEvent true if this scroll operation is the result of a touch event. 23194 * @return true if scrolling was clamped to an over-scroll boundary along either 23195 * axis, false otherwise. 23196 */ 23197 @SuppressWarnings({"UnusedParameters"}) 23198 protected boolean overScrollBy(int deltaX, int deltaY, 23199 int scrollX, int scrollY, 23200 int scrollRangeX, int scrollRangeY, 23201 int maxOverScrollX, int maxOverScrollY, 23202 boolean isTouchEvent) { 23203 final int overScrollMode = mOverScrollMode; 23204 final boolean canScrollHorizontal = 23205 computeHorizontalScrollRange() > computeHorizontalScrollExtent(); 23206 final boolean canScrollVertical = 23207 computeVerticalScrollRange() > computeVerticalScrollExtent(); 23208 final boolean overScrollHorizontal = overScrollMode == OVER_SCROLL_ALWAYS || 23209 (overScrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && canScrollHorizontal); 23210 final boolean overScrollVertical = overScrollMode == OVER_SCROLL_ALWAYS || 23211 (overScrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && canScrollVertical); 23212 23213 int newScrollX = scrollX + deltaX; 23214 if (!overScrollHorizontal) { 23215 maxOverScrollX = 0; 23216 } 23217 23218 int newScrollY = scrollY + deltaY; 23219 if (!overScrollVertical) { 23220 maxOverScrollY = 0; 23221 } 23222 23223 // Clamp values if at the limits and record 23224 final int left = -maxOverScrollX; 23225 final int right = maxOverScrollX + scrollRangeX; 23226 final int top = -maxOverScrollY; 23227 final int bottom = maxOverScrollY + scrollRangeY; 23228 23229 boolean clampedX = false; 23230 if (newScrollX > right) { 23231 newScrollX = right; 23232 clampedX = true; 23233 } else if (newScrollX < left) { 23234 newScrollX = left; 23235 clampedX = true; 23236 } 23237 23238 boolean clampedY = false; 23239 if (newScrollY > bottom) { 23240 newScrollY = bottom; 23241 clampedY = true; 23242 } else if (newScrollY < top) { 23243 newScrollY = top; 23244 clampedY = true; 23245 } 23246 23247 onOverScrolled(newScrollX, newScrollY, clampedX, clampedY); 23248 23249 return clampedX || clampedY; 23250 } 23251 23252 /** 23253 * Called by {@link #overScrollBy(int, int, int, int, int, int, int, int, boolean)} to 23254 * respond to the results of an over-scroll operation. 23255 * 23256 * @param scrollX New X scroll value in pixels 23257 * @param scrollY New Y scroll value in pixels 23258 * @param clampedX True if scrollX was clamped to an over-scroll boundary 23259 * @param clampedY True if scrollY was clamped to an over-scroll boundary 23260 */ 23261 protected void onOverScrolled(int scrollX, int scrollY, 23262 boolean clampedX, boolean clampedY) { 23263 // Intentionally empty. 23264 } 23265 23266 /** 23267 * Returns the over-scroll mode for this view. The result will be 23268 * one of {@link #OVER_SCROLL_ALWAYS} (default), {@link #OVER_SCROLL_IF_CONTENT_SCROLLS} 23269 * (allow over-scrolling only if the view content is larger than the container), 23270 * or {@link #OVER_SCROLL_NEVER}. 23271 * 23272 * @return This view's over-scroll mode. 23273 */ 23274 public int getOverScrollMode() { 23275 return mOverScrollMode; 23276 } 23277 23278 /** 23279 * Set the over-scroll mode for this view. Valid over-scroll modes are 23280 * {@link #OVER_SCROLL_ALWAYS} (default), {@link #OVER_SCROLL_IF_CONTENT_SCROLLS} 23281 * (allow over-scrolling only if the view content is larger than the container), 23282 * or {@link #OVER_SCROLL_NEVER}. 23283 * 23284 * Setting the over-scroll mode of a view will have an effect only if the 23285 * view is capable of scrolling. 23286 * 23287 * @param overScrollMode The new over-scroll mode for this view. 23288 */ 23289 public void setOverScrollMode(int overScrollMode) { 23290 if (overScrollMode != OVER_SCROLL_ALWAYS && 23291 overScrollMode != OVER_SCROLL_IF_CONTENT_SCROLLS && 23292 overScrollMode != OVER_SCROLL_NEVER) { 23293 throw new IllegalArgumentException("Invalid overscroll mode " + overScrollMode); 23294 } 23295 mOverScrollMode = overScrollMode; 23296 } 23297 23298 /** 23299 * Enable or disable nested scrolling for this view. 23300 * 23301 * <p>If this property is set to true the view will be permitted to initiate nested 23302 * scrolling operations with a compatible parent view in the current hierarchy. If this 23303 * view does not implement nested scrolling this will have no effect. Disabling nested scrolling 23304 * while a nested scroll is in progress has the effect of {@link #stopNestedScroll() stopping} 23305 * the nested scroll.</p> 23306 * 23307 * @param enabled true to enable nested scrolling, false to disable 23308 * 23309 * @see #isNestedScrollingEnabled() 23310 */ 23311 public void setNestedScrollingEnabled(boolean enabled) { 23312 if (enabled) { 23313 mPrivateFlags3 |= PFLAG3_NESTED_SCROLLING_ENABLED; 23314 } else { 23315 stopNestedScroll(); 23316 mPrivateFlags3 &= ~PFLAG3_NESTED_SCROLLING_ENABLED; 23317 } 23318 } 23319 23320 /** 23321 * Returns true if nested scrolling is enabled for this view. 23322 * 23323 * <p>If nested scrolling is enabled and this View class implementation supports it, 23324 * this view will act as a nested scrolling child view when applicable, forwarding data 23325 * about the scroll operation in progress to a compatible and cooperating nested scrolling 23326 * parent.</p> 23327 * 23328 * @return true if nested scrolling is enabled 23329 * 23330 * @see #setNestedScrollingEnabled(boolean) 23331 */ 23332 public boolean isNestedScrollingEnabled() { 23333 return (mPrivateFlags3 & PFLAG3_NESTED_SCROLLING_ENABLED) == 23334 PFLAG3_NESTED_SCROLLING_ENABLED; 23335 } 23336 23337 /** 23338 * Begin a nestable scroll operation along the given axes. 23339 * 23340 * <p>A view starting a nested scroll promises to abide by the following contract:</p> 23341 * 23342 * <p>The view will call startNestedScroll upon initiating a scroll operation. In the case 23343 * of a touch scroll this corresponds to the initial {@link MotionEvent#ACTION_DOWN}. 23344 * In the case of touch scrolling the nested scroll will be terminated automatically in 23345 * the same manner as {@link ViewParent#requestDisallowInterceptTouchEvent(boolean)}. 23346 * In the event of programmatic scrolling the caller must explicitly call 23347 * {@link #stopNestedScroll()} to indicate the end of the nested scroll.</p> 23348 * 23349 * <p>If <code>startNestedScroll</code> returns true, a cooperative parent was found. 23350 * If it returns false the caller may ignore the rest of this contract until the next scroll. 23351 * Calling startNestedScroll while a nested scroll is already in progress will return true.</p> 23352 * 23353 * <p>At each incremental step of the scroll the caller should invoke 23354 * {@link #dispatchNestedPreScroll(int, int, int[], int[]) dispatchNestedPreScroll} 23355 * once it has calculated the requested scrolling delta. If it returns true the nested scrolling 23356 * parent at least partially consumed the scroll and the caller should adjust the amount it 23357 * scrolls by.</p> 23358 * 23359 * <p>After applying the remainder of the scroll delta the caller should invoke 23360 * {@link #dispatchNestedScroll(int, int, int, int, int[]) dispatchNestedScroll}, passing 23361 * both the delta consumed and the delta unconsumed. A nested scrolling parent may treat 23362 * these values differently. See {@link ViewParent#onNestedScroll(View, int, int, int, int)}. 23363 * </p> 23364 * 23365 * @param axes Flags consisting of a combination of {@link #SCROLL_AXIS_HORIZONTAL} and/or 23366 * {@link #SCROLL_AXIS_VERTICAL}. 23367 * @return true if a cooperative parent was found and nested scrolling has been enabled for 23368 * the current gesture. 23369 * 23370 * @see #stopNestedScroll() 23371 * @see #dispatchNestedPreScroll(int, int, int[], int[]) 23372 * @see #dispatchNestedScroll(int, int, int, int, int[]) 23373 */ 23374 public boolean startNestedScroll(int axes) { 23375 if (hasNestedScrollingParent()) { 23376 // Already in progress 23377 return true; 23378 } 23379 if (isNestedScrollingEnabled()) { 23380 ViewParent p = getParent(); 23381 View child = this; 23382 while (p != null) { 23383 try { 23384 if (p.onStartNestedScroll(child, this, axes)) { 23385 mNestedScrollingParent = p; 23386 p.onNestedScrollAccepted(child, this, axes); 23387 return true; 23388 } 23389 } catch (AbstractMethodError e) { 23390 Log.e(VIEW_LOG_TAG, "ViewParent " + p + " does not implement interface " + 23391 "method onStartNestedScroll", e); 23392 // Allow the search upward to continue 23393 } 23394 if (p instanceof View) { 23395 child = (View) p; 23396 } 23397 p = p.getParent(); 23398 } 23399 } 23400 return false; 23401 } 23402 23403 /** 23404 * Stop a nested scroll in progress. 23405 * 23406 * <p>Calling this method when a nested scroll is not currently in progress is harmless.</p> 23407 * 23408 * @see #startNestedScroll(int) 23409 */ 23410 public void stopNestedScroll() { 23411 if (mNestedScrollingParent != null) { 23412 mNestedScrollingParent.onStopNestedScroll(this); 23413 mNestedScrollingParent = null; 23414 } 23415 } 23416 23417 /** 23418 * Returns true if this view has a nested scrolling parent. 23419 * 23420 * <p>The presence of a nested scrolling parent indicates that this view has initiated 23421 * a nested scroll and it was accepted by an ancestor view further up the view hierarchy.</p> 23422 * 23423 * @return whether this view has a nested scrolling parent 23424 */ 23425 public boolean hasNestedScrollingParent() { 23426 return mNestedScrollingParent != null; 23427 } 23428 23429 /** 23430 * Dispatch one step of a nested scroll in progress. 23431 * 23432 * <p>Implementations of views that support nested scrolling should call this to report 23433 * info about a scroll in progress to the current nested scrolling parent. If a nested scroll 23434 * is not currently in progress or nested scrolling is not 23435 * {@link #isNestedScrollingEnabled() enabled} for this view this method does nothing.</p> 23436 * 23437 * <p>Compatible View implementations should also call 23438 * {@link #dispatchNestedPreScroll(int, int, int[], int[]) dispatchNestedPreScroll} before 23439 * consuming a component of the scroll event themselves.</p> 23440 * 23441 * @param dxConsumed Horizontal distance in pixels consumed by this view during this scroll step 23442 * @param dyConsumed Vertical distance in pixels consumed by this view during this scroll step 23443 * @param dxUnconsumed Horizontal scroll distance in pixels not consumed by this view 23444 * @param dyUnconsumed Horizontal scroll distance in pixels not consumed by this view 23445 * @param offsetInWindow Optional. If not null, on return this will contain the offset 23446 * in local view coordinates of this view from before this operation 23447 * to after it completes. View implementations may use this to adjust 23448 * expected input coordinate tracking. 23449 * @return true if the event was dispatched, false if it could not be dispatched. 23450 * @see #dispatchNestedPreScroll(int, int, int[], int[]) 23451 */ 23452 public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed, 23453 int dxUnconsumed, int dyUnconsumed, @Nullable @Size(2) int[] offsetInWindow) { 23454 if (isNestedScrollingEnabled() && mNestedScrollingParent != null) { 23455 if (dxConsumed != 0 || dyConsumed != 0 || dxUnconsumed != 0 || dyUnconsumed != 0) { 23456 int startX = 0; 23457 int startY = 0; 23458 if (offsetInWindow != null) { 23459 getLocationInWindow(offsetInWindow); 23460 startX = offsetInWindow[0]; 23461 startY = offsetInWindow[1]; 23462 } 23463 23464 mNestedScrollingParent.onNestedScroll(this, dxConsumed, dyConsumed, 23465 dxUnconsumed, dyUnconsumed); 23466 23467 if (offsetInWindow != null) { 23468 getLocationInWindow(offsetInWindow); 23469 offsetInWindow[0] -= startX; 23470 offsetInWindow[1] -= startY; 23471 } 23472 return true; 23473 } else if (offsetInWindow != null) { 23474 // No motion, no dispatch. Keep offsetInWindow up to date. 23475 offsetInWindow[0] = 0; 23476 offsetInWindow[1] = 0; 23477 } 23478 } 23479 return false; 23480 } 23481 23482 /** 23483 * Dispatch one step of a nested scroll in progress before this view consumes any portion of it. 23484 * 23485 * <p>Nested pre-scroll events are to nested scroll events what touch intercept is to touch. 23486 * <code>dispatchNestedPreScroll</code> offers an opportunity for the parent view in a nested 23487 * scrolling operation to consume some or all of the scroll operation before the child view 23488 * consumes it.</p> 23489 * 23490 * @param dx Horizontal scroll distance in pixels 23491 * @param dy Vertical scroll distance in pixels 23492 * @param consumed Output. If not null, consumed[0] will contain the consumed component of dx 23493 * and consumed[1] the consumed dy. 23494 * @param offsetInWindow Optional. If not null, on return this will contain the offset 23495 * in local view coordinates of this view from before this operation 23496 * to after it completes. View implementations may use this to adjust 23497 * expected input coordinate tracking. 23498 * @return true if the parent consumed some or all of the scroll delta 23499 * @see #dispatchNestedScroll(int, int, int, int, int[]) 23500 */ 23501 public boolean dispatchNestedPreScroll(int dx, int dy, 23502 @Nullable @Size(2) int[] consumed, @Nullable @Size(2) int[] offsetInWindow) { 23503 if (isNestedScrollingEnabled() && mNestedScrollingParent != null) { 23504 if (dx != 0 || dy != 0) { 23505 int startX = 0; 23506 int startY = 0; 23507 if (offsetInWindow != null) { 23508 getLocationInWindow(offsetInWindow); 23509 startX = offsetInWindow[0]; 23510 startY = offsetInWindow[1]; 23511 } 23512 23513 if (consumed == null) { 23514 if (mTempNestedScrollConsumed == null) { 23515 mTempNestedScrollConsumed = new int[2]; 23516 } 23517 consumed = mTempNestedScrollConsumed; 23518 } 23519 consumed[0] = 0; 23520 consumed[1] = 0; 23521 mNestedScrollingParent.onNestedPreScroll(this, dx, dy, consumed); 23522 23523 if (offsetInWindow != null) { 23524 getLocationInWindow(offsetInWindow); 23525 offsetInWindow[0] -= startX; 23526 offsetInWindow[1] -= startY; 23527 } 23528 return consumed[0] != 0 || consumed[1] != 0; 23529 } else if (offsetInWindow != null) { 23530 offsetInWindow[0] = 0; 23531 offsetInWindow[1] = 0; 23532 } 23533 } 23534 return false; 23535 } 23536 23537 /** 23538 * Dispatch a fling to a nested scrolling parent. 23539 * 23540 * <p>This method should be used to indicate that a nested scrolling child has detected 23541 * suitable conditions for a fling. Generally this means that a touch scroll has ended with a 23542 * {@link VelocityTracker velocity} in the direction of scrolling that meets or exceeds 23543 * the {@link ViewConfiguration#getScaledMinimumFlingVelocity() minimum fling velocity} 23544 * along a scrollable axis.</p> 23545 * 23546 * <p>If a nested scrolling child view would normally fling but it is at the edge of 23547 * its own content, it can use this method to delegate the fling to its nested scrolling 23548 * parent instead. The parent may optionally consume the fling or observe a child fling.</p> 23549 * 23550 * @param velocityX Horizontal fling velocity in pixels per second 23551 * @param velocityY Vertical fling velocity in pixels per second 23552 * @param consumed true if the child consumed the fling, false otherwise 23553 * @return true if the nested scrolling parent consumed or otherwise reacted to the fling 23554 */ 23555 public boolean dispatchNestedFling(float velocityX, float velocityY, boolean consumed) { 23556 if (isNestedScrollingEnabled() && mNestedScrollingParent != null) { 23557 return mNestedScrollingParent.onNestedFling(this, velocityX, velocityY, consumed); 23558 } 23559 return false; 23560 } 23561 23562 /** 23563 * Dispatch a fling to a nested scrolling parent before it is processed by this view. 23564 * 23565 * <p>Nested pre-fling events are to nested fling events what touch intercept is to touch 23566 * and what nested pre-scroll is to nested scroll. <code>dispatchNestedPreFling</code> 23567 * offsets an opportunity for the parent view in a nested fling to fully consume the fling 23568 * before the child view consumes it. If this method returns <code>true</code>, a nested 23569 * parent view consumed the fling and this view should not scroll as a result.</p> 23570 * 23571 * <p>For a better user experience, only one view in a nested scrolling chain should consume 23572 * the fling at a time. If a parent view consumed the fling this method will return false. 23573 * Custom view implementations should account for this in two ways:</p> 23574 * 23575 * <ul> 23576 * <li>If a custom view is paged and needs to settle to a fixed page-point, do not 23577 * call <code>dispatchNestedPreFling</code>; consume the fling and settle to a valid 23578 * position regardless.</li> 23579 * <li>If a nested parent does consume the fling, this view should not scroll at all, 23580 * even to settle back to a valid idle position.</li> 23581 * </ul> 23582 * 23583 * <p>Views should also not offer fling velocities to nested parent views along an axis 23584 * where scrolling is not currently supported; a {@link android.widget.ScrollView ScrollView} 23585 * should not offer a horizontal fling velocity to its parents since scrolling along that 23586 * axis is not permitted and carrying velocity along that motion does not make sense.</p> 23587 * 23588 * @param velocityX Horizontal fling velocity in pixels per second 23589 * @param velocityY Vertical fling velocity in pixels per second 23590 * @return true if a nested scrolling parent consumed the fling 23591 */ 23592 public boolean dispatchNestedPreFling(float velocityX, float velocityY) { 23593 if (isNestedScrollingEnabled() && mNestedScrollingParent != null) { 23594 return mNestedScrollingParent.onNestedPreFling(this, velocityX, velocityY); 23595 } 23596 return false; 23597 } 23598 23599 /** 23600 * Gets a scale factor that determines the distance the view should scroll 23601 * vertically in response to {@link MotionEvent#ACTION_SCROLL}. 23602 * @return The vertical scroll scale factor. 23603 * @hide 23604 */ 23605 protected float getVerticalScrollFactor() { 23606 if (mVerticalScrollFactor == 0) { 23607 TypedValue outValue = new TypedValue(); 23608 if (!mContext.getTheme().resolveAttribute( 23609 com.android.internal.R.attr.listPreferredItemHeight, outValue, true)) { 23610 throw new IllegalStateException( 23611 "Expected theme to define listPreferredItemHeight."); 23612 } 23613 mVerticalScrollFactor = outValue.getDimension( 23614 mContext.getResources().getDisplayMetrics()); 23615 } 23616 return mVerticalScrollFactor; 23617 } 23618 23619 /** 23620 * Gets a scale factor that determines the distance the view should scroll 23621 * horizontally in response to {@link MotionEvent#ACTION_SCROLL}. 23622 * @return The horizontal scroll scale factor. 23623 * @hide 23624 */ 23625 protected float getHorizontalScrollFactor() { 23626 // TODO: Should use something else. 23627 return getVerticalScrollFactor(); 23628 } 23629 23630 /** 23631 * Return the value specifying the text direction or policy that was set with 23632 * {@link #setTextDirection(int)}. 23633 * 23634 * @return the defined text direction. It can be one of: 23635 * 23636 * {@link #TEXT_DIRECTION_INHERIT}, 23637 * {@link #TEXT_DIRECTION_FIRST_STRONG}, 23638 * {@link #TEXT_DIRECTION_ANY_RTL}, 23639 * {@link #TEXT_DIRECTION_LTR}, 23640 * {@link #TEXT_DIRECTION_RTL}, 23641 * {@link #TEXT_DIRECTION_LOCALE}, 23642 * {@link #TEXT_DIRECTION_FIRST_STRONG_LTR}, 23643 * {@link #TEXT_DIRECTION_FIRST_STRONG_RTL} 23644 * 23645 * @attr ref android.R.styleable#View_textDirection 23646 * 23647 * @hide 23648 */ 23649 @ViewDebug.ExportedProperty(category = "text", mapping = { 23650 @ViewDebug.IntToString(from = TEXT_DIRECTION_INHERIT, to = "INHERIT"), 23651 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG, to = "FIRST_STRONG"), 23652 @ViewDebug.IntToString(from = TEXT_DIRECTION_ANY_RTL, to = "ANY_RTL"), 23653 @ViewDebug.IntToString(from = TEXT_DIRECTION_LTR, to = "LTR"), 23654 @ViewDebug.IntToString(from = TEXT_DIRECTION_RTL, to = "RTL"), 23655 @ViewDebug.IntToString(from = TEXT_DIRECTION_LOCALE, to = "LOCALE"), 23656 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_LTR, to = "FIRST_STRONG_LTR"), 23657 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_RTL, to = "FIRST_STRONG_RTL") 23658 }) 23659 public int getRawTextDirection() { 23660 return (mPrivateFlags2 & PFLAG2_TEXT_DIRECTION_MASK) >> PFLAG2_TEXT_DIRECTION_MASK_SHIFT; 23661 } 23662 23663 /** 23664 * Set the text direction. 23665 * 23666 * @param textDirection the direction to set. Should be one of: 23667 * 23668 * {@link #TEXT_DIRECTION_INHERIT}, 23669 * {@link #TEXT_DIRECTION_FIRST_STRONG}, 23670 * {@link #TEXT_DIRECTION_ANY_RTL}, 23671 * {@link #TEXT_DIRECTION_LTR}, 23672 * {@link #TEXT_DIRECTION_RTL}, 23673 * {@link #TEXT_DIRECTION_LOCALE} 23674 * {@link #TEXT_DIRECTION_FIRST_STRONG_LTR}, 23675 * {@link #TEXT_DIRECTION_FIRST_STRONG_RTL}, 23676 * 23677 * Resolution will be done if the value is set to TEXT_DIRECTION_INHERIT. The resolution 23678 * proceeds up the parent chain of the view to get the value. If there is no parent, then it will 23679 * return the default {@link #TEXT_DIRECTION_FIRST_STRONG}. 23680 * 23681 * @attr ref android.R.styleable#View_textDirection 23682 */ 23683 public void setTextDirection(int textDirection) { 23684 if (getRawTextDirection() != textDirection) { 23685 // Reset the current text direction and the resolved one 23686 mPrivateFlags2 &= ~PFLAG2_TEXT_DIRECTION_MASK; 23687 resetResolvedTextDirection(); 23688 // Set the new text direction 23689 mPrivateFlags2 |= ((textDirection << PFLAG2_TEXT_DIRECTION_MASK_SHIFT) & PFLAG2_TEXT_DIRECTION_MASK); 23690 // Do resolution 23691 resolveTextDirection(); 23692 // Notify change 23693 onRtlPropertiesChanged(getLayoutDirection()); 23694 // Refresh 23695 requestLayout(); 23696 invalidate(true); 23697 } 23698 } 23699 23700 /** 23701 * Return the resolved text direction. 23702 * 23703 * @return the resolved text direction. Returns one of: 23704 * 23705 * {@link #TEXT_DIRECTION_FIRST_STRONG}, 23706 * {@link #TEXT_DIRECTION_ANY_RTL}, 23707 * {@link #TEXT_DIRECTION_LTR}, 23708 * {@link #TEXT_DIRECTION_RTL}, 23709 * {@link #TEXT_DIRECTION_LOCALE}, 23710 * {@link #TEXT_DIRECTION_FIRST_STRONG_LTR}, 23711 * {@link #TEXT_DIRECTION_FIRST_STRONG_RTL} 23712 * 23713 * @attr ref android.R.styleable#View_textDirection 23714 */ 23715 @ViewDebug.ExportedProperty(category = "text", mapping = { 23716 @ViewDebug.IntToString(from = TEXT_DIRECTION_INHERIT, to = "INHERIT"), 23717 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG, to = "FIRST_STRONG"), 23718 @ViewDebug.IntToString(from = TEXT_DIRECTION_ANY_RTL, to = "ANY_RTL"), 23719 @ViewDebug.IntToString(from = TEXT_DIRECTION_LTR, to = "LTR"), 23720 @ViewDebug.IntToString(from = TEXT_DIRECTION_RTL, to = "RTL"), 23721 @ViewDebug.IntToString(from = TEXT_DIRECTION_LOCALE, to = "LOCALE"), 23722 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_LTR, to = "FIRST_STRONG_LTR"), 23723 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_RTL, to = "FIRST_STRONG_RTL") 23724 }) 23725 public int getTextDirection() { 23726 return (mPrivateFlags2 & PFLAG2_TEXT_DIRECTION_RESOLVED_MASK) >> PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT; 23727 } 23728 23729 /** 23730 * Resolve the text direction. 23731 * 23732 * @return true if resolution has been done, false otherwise. 23733 * 23734 * @hide 23735 */ 23736 public boolean resolveTextDirection() { 23737 // Reset any previous text direction resolution 23738 mPrivateFlags2 &= ~(PFLAG2_TEXT_DIRECTION_RESOLVED | PFLAG2_TEXT_DIRECTION_RESOLVED_MASK); 23739 23740 if (hasRtlSupport()) { 23741 // Set resolved text direction flag depending on text direction flag 23742 final int textDirection = getRawTextDirection(); 23743 switch(textDirection) { 23744 case TEXT_DIRECTION_INHERIT: 23745 if (!canResolveTextDirection()) { 23746 // We cannot do the resolution if there is no parent, so use the default one 23747 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 23748 // Resolution will need to happen again later 23749 return false; 23750 } 23751 23752 // Parent has not yet resolved, so we still return the default 23753 try { 23754 if (!mParent.isTextDirectionResolved()) { 23755 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 23756 // Resolution will need to happen again later 23757 return false; 23758 } 23759 } catch (AbstractMethodError e) { 23760 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 23761 " does not fully implement ViewParent", e); 23762 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED | 23763 PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 23764 return true; 23765 } 23766 23767 // Set current resolved direction to the same value as the parent's one 23768 int parentResolvedDirection; 23769 try { 23770 parentResolvedDirection = mParent.getTextDirection(); 23771 } catch (AbstractMethodError e) { 23772 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 23773 " does not fully implement ViewParent", e); 23774 parentResolvedDirection = TEXT_DIRECTION_LTR; 23775 } 23776 switch (parentResolvedDirection) { 23777 case TEXT_DIRECTION_FIRST_STRONG: 23778 case TEXT_DIRECTION_ANY_RTL: 23779 case TEXT_DIRECTION_LTR: 23780 case TEXT_DIRECTION_RTL: 23781 case TEXT_DIRECTION_LOCALE: 23782 case TEXT_DIRECTION_FIRST_STRONG_LTR: 23783 case TEXT_DIRECTION_FIRST_STRONG_RTL: 23784 mPrivateFlags2 |= 23785 (parentResolvedDirection << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT); 23786 break; 23787 default: 23788 // Default resolved direction is "first strong" heuristic 23789 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 23790 } 23791 break; 23792 case TEXT_DIRECTION_FIRST_STRONG: 23793 case TEXT_DIRECTION_ANY_RTL: 23794 case TEXT_DIRECTION_LTR: 23795 case TEXT_DIRECTION_RTL: 23796 case TEXT_DIRECTION_LOCALE: 23797 case TEXT_DIRECTION_FIRST_STRONG_LTR: 23798 case TEXT_DIRECTION_FIRST_STRONG_RTL: 23799 // Resolved direction is the same as text direction 23800 mPrivateFlags2 |= (textDirection << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT); 23801 break; 23802 default: 23803 // Default resolved direction is "first strong" heuristic 23804 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 23805 } 23806 } else { 23807 // Default resolved direction is "first strong" heuristic 23808 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 23809 } 23810 23811 // Set to resolved 23812 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED; 23813 return true; 23814 } 23815 23816 /** 23817 * Check if text direction resolution can be done. 23818 * 23819 * @return true if text direction resolution can be done otherwise return false. 23820 */ 23821 public boolean canResolveTextDirection() { 23822 switch (getRawTextDirection()) { 23823 case TEXT_DIRECTION_INHERIT: 23824 if (mParent != null) { 23825 try { 23826 return mParent.canResolveTextDirection(); 23827 } catch (AbstractMethodError e) { 23828 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 23829 " does not fully implement ViewParent", e); 23830 } 23831 } 23832 return false; 23833 23834 default: 23835 return true; 23836 } 23837 } 23838 23839 /** 23840 * Reset resolved text direction. Text direction will be resolved during a call to 23841 * {@link #onMeasure(int, int)}. 23842 * 23843 * @hide 23844 */ 23845 public void resetResolvedTextDirection() { 23846 // Reset any previous text direction resolution 23847 mPrivateFlags2 &= ~(PFLAG2_TEXT_DIRECTION_RESOLVED | PFLAG2_TEXT_DIRECTION_RESOLVED_MASK); 23848 // Set to default value 23849 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 23850 } 23851 23852 /** 23853 * @return true if text direction is inherited. 23854 * 23855 * @hide 23856 */ 23857 public boolean isTextDirectionInherited() { 23858 return (getRawTextDirection() == TEXT_DIRECTION_INHERIT); 23859 } 23860 23861 /** 23862 * @return true if text direction is resolved. 23863 */ 23864 public boolean isTextDirectionResolved() { 23865 return (mPrivateFlags2 & PFLAG2_TEXT_DIRECTION_RESOLVED) == PFLAG2_TEXT_DIRECTION_RESOLVED; 23866 } 23867 23868 /** 23869 * Return the value specifying the text alignment or policy that was set with 23870 * {@link #setTextAlignment(int)}. 23871 * 23872 * @return the defined text alignment. It can be one of: 23873 * 23874 * {@link #TEXT_ALIGNMENT_INHERIT}, 23875 * {@link #TEXT_ALIGNMENT_GRAVITY}, 23876 * {@link #TEXT_ALIGNMENT_CENTER}, 23877 * {@link #TEXT_ALIGNMENT_TEXT_START}, 23878 * {@link #TEXT_ALIGNMENT_TEXT_END}, 23879 * {@link #TEXT_ALIGNMENT_VIEW_START}, 23880 * {@link #TEXT_ALIGNMENT_VIEW_END} 23881 * 23882 * @attr ref android.R.styleable#View_textAlignment 23883 * 23884 * @hide 23885 */ 23886 @ViewDebug.ExportedProperty(category = "text", mapping = { 23887 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_INHERIT, to = "INHERIT"), 23888 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_GRAVITY, to = "GRAVITY"), 23889 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_TEXT_START, to = "TEXT_START"), 23890 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_TEXT_END, to = "TEXT_END"), 23891 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_CENTER, to = "CENTER"), 23892 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_START, to = "VIEW_START"), 23893 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_END, to = "VIEW_END") 23894 }) 23895 @TextAlignment 23896 public int getRawTextAlignment() { 23897 return (mPrivateFlags2 & PFLAG2_TEXT_ALIGNMENT_MASK) >> PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT; 23898 } 23899 23900 /** 23901 * Set the text alignment. 23902 * 23903 * @param textAlignment The text alignment to set. Should be one of 23904 * 23905 * {@link #TEXT_ALIGNMENT_INHERIT}, 23906 * {@link #TEXT_ALIGNMENT_GRAVITY}, 23907 * {@link #TEXT_ALIGNMENT_CENTER}, 23908 * {@link #TEXT_ALIGNMENT_TEXT_START}, 23909 * {@link #TEXT_ALIGNMENT_TEXT_END}, 23910 * {@link #TEXT_ALIGNMENT_VIEW_START}, 23911 * {@link #TEXT_ALIGNMENT_VIEW_END} 23912 * 23913 * Resolution will be done if the value is set to TEXT_ALIGNMENT_INHERIT. The resolution 23914 * proceeds up the parent chain of the view to get the value. If there is no parent, then it 23915 * will return the default {@link #TEXT_ALIGNMENT_GRAVITY}. 23916 * 23917 * @attr ref android.R.styleable#View_textAlignment 23918 */ 23919 public void setTextAlignment(@TextAlignment int textAlignment) { 23920 if (textAlignment != getRawTextAlignment()) { 23921 // Reset the current and resolved text alignment 23922 mPrivateFlags2 &= ~PFLAG2_TEXT_ALIGNMENT_MASK; 23923 resetResolvedTextAlignment(); 23924 // Set the new text alignment 23925 mPrivateFlags2 |= 23926 ((textAlignment << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT) & PFLAG2_TEXT_ALIGNMENT_MASK); 23927 // Do resolution 23928 resolveTextAlignment(); 23929 // Notify change 23930 onRtlPropertiesChanged(getLayoutDirection()); 23931 // Refresh 23932 requestLayout(); 23933 invalidate(true); 23934 } 23935 } 23936 23937 /** 23938 * Return the resolved text alignment. 23939 * 23940 * @return the resolved text alignment. Returns one of: 23941 * 23942 * {@link #TEXT_ALIGNMENT_GRAVITY}, 23943 * {@link #TEXT_ALIGNMENT_CENTER}, 23944 * {@link #TEXT_ALIGNMENT_TEXT_START}, 23945 * {@link #TEXT_ALIGNMENT_TEXT_END}, 23946 * {@link #TEXT_ALIGNMENT_VIEW_START}, 23947 * {@link #TEXT_ALIGNMENT_VIEW_END} 23948 * 23949 * @attr ref android.R.styleable#View_textAlignment 23950 */ 23951 @ViewDebug.ExportedProperty(category = "text", mapping = { 23952 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_INHERIT, to = "INHERIT"), 23953 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_GRAVITY, to = "GRAVITY"), 23954 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_TEXT_START, to = "TEXT_START"), 23955 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_TEXT_END, to = "TEXT_END"), 23956 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_CENTER, to = "CENTER"), 23957 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_START, to = "VIEW_START"), 23958 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_END, to = "VIEW_END") 23959 }) 23960 @TextAlignment 23961 public int getTextAlignment() { 23962 return (mPrivateFlags2 & PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK) >> 23963 PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT; 23964 } 23965 23966 /** 23967 * Resolve the text alignment. 23968 * 23969 * @return true if resolution has been done, false otherwise. 23970 * 23971 * @hide 23972 */ 23973 public boolean resolveTextAlignment() { 23974 // Reset any previous text alignment resolution 23975 mPrivateFlags2 &= ~(PFLAG2_TEXT_ALIGNMENT_RESOLVED | PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK); 23976 23977 if (hasRtlSupport()) { 23978 // Set resolved text alignment flag depending on text alignment flag 23979 final int textAlignment = getRawTextAlignment(); 23980 switch (textAlignment) { 23981 case TEXT_ALIGNMENT_INHERIT: 23982 // Check if we can resolve the text alignment 23983 if (!canResolveTextAlignment()) { 23984 // We cannot do the resolution if there is no parent so use the default 23985 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 23986 // Resolution will need to happen again later 23987 return false; 23988 } 23989 23990 // Parent has not yet resolved, so we still return the default 23991 try { 23992 if (!mParent.isTextAlignmentResolved()) { 23993 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 23994 // Resolution will need to happen again later 23995 return false; 23996 } 23997 } catch (AbstractMethodError e) { 23998 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 23999 " does not fully implement ViewParent", e); 24000 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED | 24001 PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 24002 return true; 24003 } 24004 24005 int parentResolvedTextAlignment; 24006 try { 24007 parentResolvedTextAlignment = mParent.getTextAlignment(); 24008 } catch (AbstractMethodError e) { 24009 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 24010 " does not fully implement ViewParent", e); 24011 parentResolvedTextAlignment = TEXT_ALIGNMENT_GRAVITY; 24012 } 24013 switch (parentResolvedTextAlignment) { 24014 case TEXT_ALIGNMENT_GRAVITY: 24015 case TEXT_ALIGNMENT_TEXT_START: 24016 case TEXT_ALIGNMENT_TEXT_END: 24017 case TEXT_ALIGNMENT_CENTER: 24018 case TEXT_ALIGNMENT_VIEW_START: 24019 case TEXT_ALIGNMENT_VIEW_END: 24020 // Resolved text alignment is the same as the parent resolved 24021 // text alignment 24022 mPrivateFlags2 |= 24023 (parentResolvedTextAlignment << PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT); 24024 break; 24025 default: 24026 // Use default resolved text alignment 24027 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 24028 } 24029 break; 24030 case TEXT_ALIGNMENT_GRAVITY: 24031 case TEXT_ALIGNMENT_TEXT_START: 24032 case TEXT_ALIGNMENT_TEXT_END: 24033 case TEXT_ALIGNMENT_CENTER: 24034 case TEXT_ALIGNMENT_VIEW_START: 24035 case TEXT_ALIGNMENT_VIEW_END: 24036 // Resolved text alignment is the same as text alignment 24037 mPrivateFlags2 |= (textAlignment << PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT); 24038 break; 24039 default: 24040 // Use default resolved text alignment 24041 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 24042 } 24043 } else { 24044 // Use default resolved text alignment 24045 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 24046 } 24047 24048 // Set the resolved 24049 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED; 24050 return true; 24051 } 24052 24053 /** 24054 * Check if text alignment resolution can be done. 24055 * 24056 * @return true if text alignment resolution can be done otherwise return false. 24057 */ 24058 public boolean canResolveTextAlignment() { 24059 switch (getRawTextAlignment()) { 24060 case TEXT_DIRECTION_INHERIT: 24061 if (mParent != null) { 24062 try { 24063 return mParent.canResolveTextAlignment(); 24064 } catch (AbstractMethodError e) { 24065 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 24066 " does not fully implement ViewParent", e); 24067 } 24068 } 24069 return false; 24070 24071 default: 24072 return true; 24073 } 24074 } 24075 24076 /** 24077 * Reset resolved text alignment. Text alignment will be resolved during a call to 24078 * {@link #onMeasure(int, int)}. 24079 * 24080 * @hide 24081 */ 24082 public void resetResolvedTextAlignment() { 24083 // Reset any previous text alignment resolution 24084 mPrivateFlags2 &= ~(PFLAG2_TEXT_ALIGNMENT_RESOLVED | PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK); 24085 // Set to default 24086 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 24087 } 24088 24089 /** 24090 * @return true if text alignment is inherited. 24091 * 24092 * @hide 24093 */ 24094 public boolean isTextAlignmentInherited() { 24095 return (getRawTextAlignment() == TEXT_ALIGNMENT_INHERIT); 24096 } 24097 24098 /** 24099 * @return true if text alignment is resolved. 24100 */ 24101 public boolean isTextAlignmentResolved() { 24102 return (mPrivateFlags2 & PFLAG2_TEXT_ALIGNMENT_RESOLVED) == PFLAG2_TEXT_ALIGNMENT_RESOLVED; 24103 } 24104 24105 /** 24106 * Generate a value suitable for use in {@link #setId(int)}. 24107 * This value will not collide with ID values generated at build time by aapt for R.id. 24108 * 24109 * @return a generated ID value 24110 */ 24111 public static int generateViewId() { 24112 for (;;) { 24113 final int result = sNextGeneratedId.get(); 24114 // aapt-generated IDs have the high byte nonzero; clamp to the range under that. 24115 int newValue = result + 1; 24116 if (newValue > 0x00FFFFFF) newValue = 1; // Roll over to 1, not 0. 24117 if (sNextGeneratedId.compareAndSet(result, newValue)) { 24118 return result; 24119 } 24120 } 24121 } 24122 24123 private static boolean isViewIdGenerated(int id) { 24124 return (id & 0xFF000000) == 0 && (id & 0x00FFFFFF) != 0; 24125 } 24126 24127 /** 24128 * Gets the Views in the hierarchy affected by entering and exiting Activity Scene transitions. 24129 * @param transitioningViews This View will be added to transitioningViews if it is VISIBLE and 24130 * a normal View or a ViewGroup with 24131 * {@link android.view.ViewGroup#isTransitionGroup()} true. 24132 * @hide 24133 */ 24134 public void captureTransitioningViews(List<View> transitioningViews) { 24135 if (getVisibility() == View.VISIBLE) { 24136 transitioningViews.add(this); 24137 } 24138 } 24139 24140 /** 24141 * Adds all Views that have {@link #getTransitionName()} non-null to namedElements. 24142 * @param namedElements Will contain all Views in the hierarchy having a transitionName. 24143 * @hide 24144 */ 24145 public void findNamedViews(Map<String, View> namedElements) { 24146 if (getVisibility() == VISIBLE || mGhostView != null) { 24147 String transitionName = getTransitionName(); 24148 if (transitionName != null) { 24149 namedElements.put(transitionName, this); 24150 } 24151 } 24152 } 24153 24154 /** 24155 * Returns the pointer icon for the motion event, or null if it doesn't specify the icon. 24156 * The default implementation does not care the location or event types, but some subclasses 24157 * may use it (such as WebViews). 24158 * @param event The MotionEvent from a mouse 24159 * @param pointerIndex The index of the pointer for which to retrieve the {@link PointerIcon}. 24160 * This will be between 0 and {@link MotionEvent#getPointerCount()}. 24161 * @see PointerIcon 24162 */ 24163 public PointerIcon onResolvePointerIcon(MotionEvent event, int pointerIndex) { 24164 final float x = event.getX(pointerIndex); 24165 final float y = event.getY(pointerIndex); 24166 if (isDraggingScrollBar() || isOnScrollbarThumb(x, y)) { 24167 return PointerIcon.getSystemIcon(mContext, PointerIcon.TYPE_ARROW); 24168 } 24169 return mPointerIcon; 24170 } 24171 24172 /** 24173 * Set the pointer icon for the current view. 24174 * Passing {@code null} will restore the pointer icon to its default value. 24175 * @param pointerIcon A PointerIcon instance which will be shown when the mouse hovers. 24176 */ 24177 public void setPointerIcon(PointerIcon pointerIcon) { 24178 mPointerIcon = pointerIcon; 24179 if (mAttachInfo == null || mAttachInfo.mHandlingPointerEvent) { 24180 return; 24181 } 24182 try { 24183 mAttachInfo.mSession.updatePointerIcon(mAttachInfo.mWindow); 24184 } catch (RemoteException e) { 24185 } 24186 } 24187 24188 /** 24189 * Gets the pointer icon for the current view. 24190 */ 24191 public PointerIcon getPointerIcon() { 24192 return mPointerIcon; 24193 } 24194 24195 /** 24196 * Checks pointer capture status. 24197 * 24198 * @return true if the view has pointer capture. 24199 * @see #requestPointerCapture() 24200 * @see #hasPointerCapture() 24201 */ 24202 public boolean hasPointerCapture() { 24203 final ViewRootImpl viewRootImpl = getViewRootImpl(); 24204 if (viewRootImpl == null) { 24205 return false; 24206 } 24207 return viewRootImpl.hasPointerCapture(); 24208 } 24209 24210 /** 24211 * Requests pointer capture mode. 24212 * <p> 24213 * When the window has pointer capture, the mouse pointer icon will disappear and will not 24214 * change its position. Further mouse will be dispatched with the source 24215 * {@link InputDevice#SOURCE_MOUSE_RELATIVE}, and relative position changes will be available 24216 * through {@link MotionEvent#getX} and {@link MotionEvent#getY}. Non-mouse events 24217 * (touchscreens, or stylus) will not be affected. 24218 * <p> 24219 * If the window already has pointer capture, this call does nothing. 24220 * <p> 24221 * The capture may be released through {@link #releasePointerCapture()}, or will be lost 24222 * automatically when the window loses focus. 24223 * 24224 * @see #releasePointerCapture() 24225 * @see #hasPointerCapture() 24226 */ 24227 public void requestPointerCapture() { 24228 final ViewRootImpl viewRootImpl = getViewRootImpl(); 24229 if (viewRootImpl != null) { 24230 viewRootImpl.requestPointerCapture(true); 24231 } 24232 } 24233 24234 24235 /** 24236 * Releases the pointer capture. 24237 * <p> 24238 * If the window does not have pointer capture, this call will do nothing. 24239 * @see #requestPointerCapture() 24240 * @see #hasPointerCapture() 24241 */ 24242 public void releasePointerCapture() { 24243 final ViewRootImpl viewRootImpl = getViewRootImpl(); 24244 if (viewRootImpl != null) { 24245 viewRootImpl.requestPointerCapture(false); 24246 } 24247 } 24248 24249 /** 24250 * Called when the window has just acquired or lost pointer capture. 24251 * 24252 * @param hasCapture True if the view now has pointerCapture, false otherwise. 24253 */ 24254 @CallSuper 24255 public void onPointerCaptureChange(boolean hasCapture) { 24256 } 24257 24258 /** 24259 * @see #onPointerCaptureChange 24260 */ 24261 public void dispatchPointerCaptureChanged(boolean hasCapture) { 24262 onPointerCaptureChange(hasCapture); 24263 } 24264 24265 /** 24266 * Implement this method to handle captured pointer events 24267 * 24268 * @param event The captured pointer event. 24269 * @return True if the event was handled, false otherwise. 24270 * @see #requestPointerCapture() 24271 */ 24272 public boolean onCapturedPointerEvent(MotionEvent event) { 24273 return false; 24274 } 24275 24276 /** 24277 * Interface definition for a callback to be invoked when a captured pointer event 24278 * is being dispatched this view. The callback will be invoked before the event is 24279 * given to the view. 24280 */ 24281 public interface OnCapturedPointerListener { 24282 /** 24283 * Called when a captured pointer event is dispatched to a view. 24284 * @param view The view this event has been dispatched to. 24285 * @param event The captured event. 24286 * @return True if the listener has consumed the event, false otherwise. 24287 */ 24288 boolean onCapturedPointer(View view, MotionEvent event); 24289 } 24290 24291 /** 24292 * Set a listener to receive callbacks when the pointer capture state of a view changes. 24293 * @param l The {@link OnCapturedPointerListener} to receive callbacks. 24294 */ 24295 public void setOnCapturedPointerListener(OnCapturedPointerListener l) { 24296 getListenerInfo().mOnCapturedPointerListener = l; 24297 } 24298 24299 // Properties 24300 // 24301 /** 24302 * A Property wrapper around the <code>alpha</code> functionality handled by the 24303 * {@link View#setAlpha(float)} and {@link View#getAlpha()} methods. 24304 */ 24305 public static final Property<View, Float> ALPHA = new FloatProperty<View>("alpha") { 24306 @Override 24307 public void setValue(View object, float value) { 24308 object.setAlpha(value); 24309 } 24310 24311 @Override 24312 public Float get(View object) { 24313 return object.getAlpha(); 24314 } 24315 }; 24316 24317 /** 24318 * A Property wrapper around the <code>translationX</code> functionality handled by the 24319 * {@link View#setTranslationX(float)} and {@link View#getTranslationX()} methods. 24320 */ 24321 public static final Property<View, Float> TRANSLATION_X = new FloatProperty<View>("translationX") { 24322 @Override 24323 public void setValue(View object, float value) { 24324 object.setTranslationX(value); 24325 } 24326 24327 @Override 24328 public Float get(View object) { 24329 return object.getTranslationX(); 24330 } 24331 }; 24332 24333 /** 24334 * A Property wrapper around the <code>translationY</code> functionality handled by the 24335 * {@link View#setTranslationY(float)} and {@link View#getTranslationY()} methods. 24336 */ 24337 public static final Property<View, Float> TRANSLATION_Y = new FloatProperty<View>("translationY") { 24338 @Override 24339 public void setValue(View object, float value) { 24340 object.setTranslationY(value); 24341 } 24342 24343 @Override 24344 public Float get(View object) { 24345 return object.getTranslationY(); 24346 } 24347 }; 24348 24349 /** 24350 * A Property wrapper around the <code>translationZ</code> functionality handled by the 24351 * {@link View#setTranslationZ(float)} and {@link View#getTranslationZ()} methods. 24352 */ 24353 public static final Property<View, Float> TRANSLATION_Z = new FloatProperty<View>("translationZ") { 24354 @Override 24355 public void setValue(View object, float value) { 24356 object.setTranslationZ(value); 24357 } 24358 24359 @Override 24360 public Float get(View object) { 24361 return object.getTranslationZ(); 24362 } 24363 }; 24364 24365 /** 24366 * A Property wrapper around the <code>x</code> functionality handled by the 24367 * {@link View#setX(float)} and {@link View#getX()} methods. 24368 */ 24369 public static final Property<View, Float> X = new FloatProperty<View>("x") { 24370 @Override 24371 public void setValue(View object, float value) { 24372 object.setX(value); 24373 } 24374 24375 @Override 24376 public Float get(View object) { 24377 return object.getX(); 24378 } 24379 }; 24380 24381 /** 24382 * A Property wrapper around the <code>y</code> functionality handled by the 24383 * {@link View#setY(float)} and {@link View#getY()} methods. 24384 */ 24385 public static final Property<View, Float> Y = new FloatProperty<View>("y") { 24386 @Override 24387 public void setValue(View object, float value) { 24388 object.setY(value); 24389 } 24390 24391 @Override 24392 public Float get(View object) { 24393 return object.getY(); 24394 } 24395 }; 24396 24397 /** 24398 * A Property wrapper around the <code>z</code> functionality handled by the 24399 * {@link View#setZ(float)} and {@link View#getZ()} methods. 24400 */ 24401 public static final Property<View, Float> Z = new FloatProperty<View>("z") { 24402 @Override 24403 public void setValue(View object, float value) { 24404 object.setZ(value); 24405 } 24406 24407 @Override 24408 public Float get(View object) { 24409 return object.getZ(); 24410 } 24411 }; 24412 24413 /** 24414 * A Property wrapper around the <code>rotation</code> functionality handled by the 24415 * {@link View#setRotation(float)} and {@link View#getRotation()} methods. 24416 */ 24417 public static final Property<View, Float> ROTATION = new FloatProperty<View>("rotation") { 24418 @Override 24419 public void setValue(View object, float value) { 24420 object.setRotation(value); 24421 } 24422 24423 @Override 24424 public Float get(View object) { 24425 return object.getRotation(); 24426 } 24427 }; 24428 24429 /** 24430 * A Property wrapper around the <code>rotationX</code> functionality handled by the 24431 * {@link View#setRotationX(float)} and {@link View#getRotationX()} methods. 24432 */ 24433 public static final Property<View, Float> ROTATION_X = new FloatProperty<View>("rotationX") { 24434 @Override 24435 public void setValue(View object, float value) { 24436 object.setRotationX(value); 24437 } 24438 24439 @Override 24440 public Float get(View object) { 24441 return object.getRotationX(); 24442 } 24443 }; 24444 24445 /** 24446 * A Property wrapper around the <code>rotationY</code> functionality handled by the 24447 * {@link View#setRotationY(float)} and {@link View#getRotationY()} methods. 24448 */ 24449 public static final Property<View, Float> ROTATION_Y = new FloatProperty<View>("rotationY") { 24450 @Override 24451 public void setValue(View object, float value) { 24452 object.setRotationY(value); 24453 } 24454 24455 @Override 24456 public Float get(View object) { 24457 return object.getRotationY(); 24458 } 24459 }; 24460 24461 /** 24462 * A Property wrapper around the <code>scaleX</code> functionality handled by the 24463 * {@link View#setScaleX(float)} and {@link View#getScaleX()} methods. 24464 */ 24465 public static final Property<View, Float> SCALE_X = new FloatProperty<View>("scaleX") { 24466 @Override 24467 public void setValue(View object, float value) { 24468 object.setScaleX(value); 24469 } 24470 24471 @Override 24472 public Float get(View object) { 24473 return object.getScaleX(); 24474 } 24475 }; 24476 24477 /** 24478 * A Property wrapper around the <code>scaleY</code> functionality handled by the 24479 * {@link View#setScaleY(float)} and {@link View#getScaleY()} methods. 24480 */ 24481 public static final Property<View, Float> SCALE_Y = new FloatProperty<View>("scaleY") { 24482 @Override 24483 public void setValue(View object, float value) { 24484 object.setScaleY(value); 24485 } 24486 24487 @Override 24488 public Float get(View object) { 24489 return object.getScaleY(); 24490 } 24491 }; 24492 24493 /** 24494 * A MeasureSpec encapsulates the layout requirements passed from parent to child. 24495 * Each MeasureSpec represents a requirement for either the width or the height. 24496 * A MeasureSpec is comprised of a size and a mode. There are three possible 24497 * modes: 24498 * <dl> 24499 * <dt>UNSPECIFIED</dt> 24500 * <dd> 24501 * The parent has not imposed any constraint on the child. It can be whatever size 24502 * it wants. 24503 * </dd> 24504 * 24505 * <dt>EXACTLY</dt> 24506 * <dd> 24507 * The parent has determined an exact size for the child. The child is going to be 24508 * given those bounds regardless of how big it wants to be. 24509 * </dd> 24510 * 24511 * <dt>AT_MOST</dt> 24512 * <dd> 24513 * The child can be as large as it wants up to the specified size. 24514 * </dd> 24515 * </dl> 24516 * 24517 * MeasureSpecs are implemented as ints to reduce object allocation. This class 24518 * is provided to pack and unpack the <size, mode> tuple into the int. 24519 */ 24520 public static class MeasureSpec { 24521 private static final int MODE_SHIFT = 30; 24522 private static final int MODE_MASK = 0x3 << MODE_SHIFT; 24523 24524 /** @hide */ 24525 @IntDef({UNSPECIFIED, EXACTLY, AT_MOST}) 24526 @Retention(RetentionPolicy.SOURCE) 24527 public @interface MeasureSpecMode {} 24528 24529 /** 24530 * Measure specification mode: The parent has not imposed any constraint 24531 * on the child. It can be whatever size it wants. 24532 */ 24533 public static final int UNSPECIFIED = 0 << MODE_SHIFT; 24534 24535 /** 24536 * Measure specification mode: The parent has determined an exact size 24537 * for the child. The child is going to be given those bounds regardless 24538 * of how big it wants to be. 24539 */ 24540 public static final int EXACTLY = 1 << MODE_SHIFT; 24541 24542 /** 24543 * Measure specification mode: The child can be as large as it wants up 24544 * to the specified size. 24545 */ 24546 public static final int AT_MOST = 2 << MODE_SHIFT; 24547 24548 /** 24549 * Creates a measure specification based on the supplied size and mode. 24550 * 24551 * The mode must always be one of the following: 24552 * <ul> 24553 * <li>{@link android.view.View.MeasureSpec#UNSPECIFIED}</li> 24554 * <li>{@link android.view.View.MeasureSpec#EXACTLY}</li> 24555 * <li>{@link android.view.View.MeasureSpec#AT_MOST}</li> 24556 * </ul> 24557 * 24558 * <p><strong>Note:</strong> On API level 17 and lower, makeMeasureSpec's 24559 * implementation was such that the order of arguments did not matter 24560 * and overflow in either value could impact the resulting MeasureSpec. 24561 * {@link android.widget.RelativeLayout} was affected by this bug. 24562 * Apps targeting API levels greater than 17 will get the fixed, more strict 24563 * behavior.</p> 24564 * 24565 * @param size the size of the measure specification 24566 * @param mode the mode of the measure specification 24567 * @return the measure specification based on size and mode 24568 */ 24569 public static int makeMeasureSpec(@IntRange(from = 0, to = (1 << MeasureSpec.MODE_SHIFT) - 1) int size, 24570 @MeasureSpecMode int mode) { 24571 if (sUseBrokenMakeMeasureSpec) { 24572 return size + mode; 24573 } else { 24574 return (size & ~MODE_MASK) | (mode & MODE_MASK); 24575 } 24576 } 24577 24578 /** 24579 * Like {@link #makeMeasureSpec(int, int)}, but any spec with a mode of UNSPECIFIED 24580 * will automatically get a size of 0. Older apps expect this. 24581 * 24582 * @hide internal use only for compatibility with system widgets and older apps 24583 */ 24584 public static int makeSafeMeasureSpec(int size, int mode) { 24585 if (sUseZeroUnspecifiedMeasureSpec && mode == UNSPECIFIED) { 24586 return 0; 24587 } 24588 return makeMeasureSpec(size, mode); 24589 } 24590 24591 /** 24592 * Extracts the mode from the supplied measure specification. 24593 * 24594 * @param measureSpec the measure specification to extract the mode from 24595 * @return {@link android.view.View.MeasureSpec#UNSPECIFIED}, 24596 * {@link android.view.View.MeasureSpec#AT_MOST} or 24597 * {@link android.view.View.MeasureSpec#EXACTLY} 24598 */ 24599 @MeasureSpecMode 24600 public static int getMode(int measureSpec) { 24601 //noinspection ResourceType 24602 return (measureSpec & MODE_MASK); 24603 } 24604 24605 /** 24606 * Extracts the size from the supplied measure specification. 24607 * 24608 * @param measureSpec the measure specification to extract the size from 24609 * @return the size in pixels defined in the supplied measure specification 24610 */ 24611 public static int getSize(int measureSpec) { 24612 return (measureSpec & ~MODE_MASK); 24613 } 24614 24615 static int adjust(int measureSpec, int delta) { 24616 final int mode = getMode(measureSpec); 24617 int size = getSize(measureSpec); 24618 if (mode == UNSPECIFIED) { 24619 // No need to adjust size for UNSPECIFIED mode. 24620 return makeMeasureSpec(size, UNSPECIFIED); 24621 } 24622 size += delta; 24623 if (size < 0) { 24624 Log.e(VIEW_LOG_TAG, "MeasureSpec.adjust: new size would be negative! (" + size + 24625 ") spec: " + toString(measureSpec) + " delta: " + delta); 24626 size = 0; 24627 } 24628 return makeMeasureSpec(size, mode); 24629 } 24630 24631 /** 24632 * Returns a String representation of the specified measure 24633 * specification. 24634 * 24635 * @param measureSpec the measure specification to convert to a String 24636 * @return a String with the following format: "MeasureSpec: MODE SIZE" 24637 */ 24638 public static String toString(int measureSpec) { 24639 int mode = getMode(measureSpec); 24640 int size = getSize(measureSpec); 24641 24642 StringBuilder sb = new StringBuilder("MeasureSpec: "); 24643 24644 if (mode == UNSPECIFIED) 24645 sb.append("UNSPECIFIED "); 24646 else if (mode == EXACTLY) 24647 sb.append("EXACTLY "); 24648 else if (mode == AT_MOST) 24649 sb.append("AT_MOST "); 24650 else 24651 sb.append(mode).append(" "); 24652 24653 sb.append(size); 24654 return sb.toString(); 24655 } 24656 } 24657 24658 private final class CheckForLongPress implements Runnable { 24659 private int mOriginalWindowAttachCount; 24660 private float mX; 24661 private float mY; 24662 private boolean mOriginalPressedState; 24663 24664 @Override 24665 public void run() { 24666 if ((mOriginalPressedState == isPressed()) && (mParent != null) 24667 && mOriginalWindowAttachCount == mWindowAttachCount) { 24668 if (performLongClick(mX, mY)) { 24669 mHasPerformedLongPress = true; 24670 } 24671 } 24672 } 24673 24674 public void setAnchor(float x, float y) { 24675 mX = x; 24676 mY = y; 24677 } 24678 24679 public void rememberWindowAttachCount() { 24680 mOriginalWindowAttachCount = mWindowAttachCount; 24681 } 24682 24683 public void rememberPressedState() { 24684 mOriginalPressedState = isPressed(); 24685 } 24686 } 24687 24688 private final class CheckForTap implements Runnable { 24689 public float x; 24690 public float y; 24691 24692 @Override 24693 public void run() { 24694 mPrivateFlags &= ~PFLAG_PREPRESSED; 24695 setPressed(true, x, y); 24696 checkForLongClick(ViewConfiguration.getTapTimeout(), x, y); 24697 } 24698 } 24699 24700 private final class PerformClick implements Runnable { 24701 @Override 24702 public void run() { 24703 performClick(); 24704 } 24705 } 24706 24707 /** 24708 * This method returns a ViewPropertyAnimator object, which can be used to animate 24709 * specific properties on this View. 24710 * 24711 * @return ViewPropertyAnimator The ViewPropertyAnimator associated with this View. 24712 */ 24713 public ViewPropertyAnimator animate() { 24714 if (mAnimator == null) { 24715 mAnimator = new ViewPropertyAnimator(this); 24716 } 24717 return mAnimator; 24718 } 24719 24720 /** 24721 * Sets the name of the View to be used to identify Views in Transitions. 24722 * Names should be unique in the View hierarchy. 24723 * 24724 * @param transitionName The name of the View to uniquely identify it for Transitions. 24725 */ 24726 public final void setTransitionName(String transitionName) { 24727 mTransitionName = transitionName; 24728 } 24729 24730 /** 24731 * Returns the name of the View to be used to identify Views in Transitions. 24732 * Names should be unique in the View hierarchy. 24733 * 24734 * <p>This returns null if the View has not been given a name.</p> 24735 * 24736 * @return The name used of the View to be used to identify Views in Transitions or null 24737 * if no name has been given. 24738 */ 24739 @ViewDebug.ExportedProperty 24740 public String getTransitionName() { 24741 return mTransitionName; 24742 } 24743 24744 /** 24745 * @hide 24746 */ 24747 public void requestKeyboardShortcuts(List<KeyboardShortcutGroup> data, int deviceId) { 24748 // Do nothing. 24749 } 24750 24751 /** 24752 * Interface definition for a callback to be invoked when a hardware key event is 24753 * dispatched to this view. The callback will be invoked before the key event is 24754 * given to the view. This is only useful for hardware keyboards; a software input 24755 * method has no obligation to trigger this listener. 24756 */ 24757 public interface OnKeyListener { 24758 /** 24759 * Called when a hardware key is dispatched to a view. This allows listeners to 24760 * get a chance to respond before the target view. 24761 * <p>Key presses in software keyboards will generally NOT trigger this method, 24762 * although some may elect to do so in some situations. Do not assume a 24763 * software input method has to be key-based; even if it is, it may use key presses 24764 * in a different way than you expect, so there is no way to reliably catch soft 24765 * input key presses. 24766 * 24767 * @param v The view the key has been dispatched to. 24768 * @param keyCode The code for the physical key that was pressed 24769 * @param event The KeyEvent object containing full information about 24770 * the event. 24771 * @return True if the listener has consumed the event, false otherwise. 24772 */ 24773 boolean onKey(View v, int keyCode, KeyEvent event); 24774 } 24775 24776 /** 24777 * Interface definition for a callback to be invoked when a touch event is 24778 * dispatched to this view. The callback will be invoked before the touch 24779 * event is given to the view. 24780 */ 24781 public interface OnTouchListener { 24782 /** 24783 * Called when a touch event is dispatched to a view. This allows listeners to 24784 * get a chance to respond before the target view. 24785 * 24786 * @param v The view the touch event has been dispatched to. 24787 * @param event The MotionEvent object containing full information about 24788 * the event. 24789 * @return True if the listener has consumed the event, false otherwise. 24790 */ 24791 boolean onTouch(View v, MotionEvent event); 24792 } 24793 24794 /** 24795 * Interface definition for a callback to be invoked when a hover event is 24796 * dispatched to this view. The callback will be invoked before the hover 24797 * event is given to the view. 24798 */ 24799 public interface OnHoverListener { 24800 /** 24801 * Called when a hover event is dispatched to a view. This allows listeners to 24802 * get a chance to respond before the target view. 24803 * 24804 * @param v The view the hover event has been dispatched to. 24805 * @param event The MotionEvent object containing full information about 24806 * the event. 24807 * @return True if the listener has consumed the event, false otherwise. 24808 */ 24809 boolean onHover(View v, MotionEvent event); 24810 } 24811 24812 /** 24813 * Interface definition for a callback to be invoked when a generic motion event is 24814 * dispatched to this view. The callback will be invoked before the generic motion 24815 * event is given to the view. 24816 */ 24817 public interface OnGenericMotionListener { 24818 /** 24819 * Called when a generic motion event is dispatched to a view. This allows listeners to 24820 * get a chance to respond before the target view. 24821 * 24822 * @param v The view the generic motion event has been dispatched to. 24823 * @param event The MotionEvent object containing full information about 24824 * the event. 24825 * @return True if the listener has consumed the event, false otherwise. 24826 */ 24827 boolean onGenericMotion(View v, MotionEvent event); 24828 } 24829 24830 /** 24831 * Interface definition for a callback to be invoked when a view has been clicked and held. 24832 */ 24833 public interface OnLongClickListener { 24834 /** 24835 * Called when a view has been clicked and held. 24836 * 24837 * @param v The view that was clicked and held. 24838 * 24839 * @return true if the callback consumed the long click, false otherwise. 24840 */ 24841 boolean onLongClick(View v); 24842 } 24843 24844 /** 24845 * Interface definition for a callback to be invoked when a drag is being dispatched 24846 * to this view. The callback will be invoked before the hosting view's own 24847 * onDrag(event) method. If the listener wants to fall back to the hosting view's 24848 * onDrag(event) behavior, it should return 'false' from this callback. 24849 * 24850 * <div class="special reference"> 24851 * <h3>Developer Guides</h3> 24852 * <p>For a guide to implementing drag and drop features, read the 24853 * <a href="{@docRoot}guide/topics/ui/drag-drop.html">Drag and Drop</a> developer guide.</p> 24854 * </div> 24855 */ 24856 public interface OnDragListener { 24857 /** 24858 * Called when a drag event is dispatched to a view. This allows listeners 24859 * to get a chance to override base View behavior. 24860 * 24861 * @param v The View that received the drag event. 24862 * @param event The {@link android.view.DragEvent} object for the drag event. 24863 * @return {@code true} if the drag event was handled successfully, or {@code false} 24864 * if the drag event was not handled. Note that {@code false} will trigger the View 24865 * to call its {@link #onDragEvent(DragEvent) onDragEvent()} handler. 24866 */ 24867 boolean onDrag(View v, DragEvent event); 24868 } 24869 24870 /** 24871 * Interface definition for a callback to be invoked when the focus state of 24872 * a view changed. 24873 */ 24874 public interface OnFocusChangeListener { 24875 /** 24876 * Called when the focus state of a view has changed. 24877 * 24878 * @param v The view whose state has changed. 24879 * @param hasFocus The new focus state of v. 24880 */ 24881 void onFocusChange(View v, boolean hasFocus); 24882 } 24883 24884 /** 24885 * Interface definition for a callback to be invoked when a view is clicked. 24886 */ 24887 public interface OnClickListener { 24888 /** 24889 * Called when a view has been clicked. 24890 * 24891 * @param v The view that was clicked. 24892 */ 24893 void onClick(View v); 24894 } 24895 24896 /** 24897 * Interface definition for a callback to be invoked when a view is context clicked. 24898 */ 24899 public interface OnContextClickListener { 24900 /** 24901 * Called when a view is context clicked. 24902 * 24903 * @param v The view that has been context clicked. 24904 * @return true if the callback consumed the context click, false otherwise. 24905 */ 24906 boolean onContextClick(View v); 24907 } 24908 24909 /** 24910 * Interface definition for a callback to be invoked when the context menu 24911 * for this view is being built. 24912 */ 24913 public interface OnCreateContextMenuListener { 24914 /** 24915 * Called when the context menu for this view is being built. It is not 24916 * safe to hold onto the menu after this method returns. 24917 * 24918 * @param menu The context menu that is being built 24919 * @param v The view for which the context menu is being built 24920 * @param menuInfo Extra information about the item for which the 24921 * context menu should be shown. This information will vary 24922 * depending on the class of v. 24923 */ 24924 void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo); 24925 } 24926 24927 /** 24928 * Interface definition for a callback to be invoked when the status bar changes 24929 * visibility. This reports <strong>global</strong> changes to the system UI 24930 * state, not what the application is requesting. 24931 * 24932 * @see View#setOnSystemUiVisibilityChangeListener(android.view.View.OnSystemUiVisibilityChangeListener) 24933 */ 24934 public interface OnSystemUiVisibilityChangeListener { 24935 /** 24936 * Called when the status bar changes visibility because of a call to 24937 * {@link View#setSystemUiVisibility(int)}. 24938 * 24939 * @param visibility Bitwise-or of flags {@link #SYSTEM_UI_FLAG_LOW_PROFILE}, 24940 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, and {@link #SYSTEM_UI_FLAG_FULLSCREEN}. 24941 * This tells you the <strong>global</strong> state of these UI visibility 24942 * flags, not what your app is currently applying. 24943 */ 24944 public void onSystemUiVisibilityChange(int visibility); 24945 } 24946 24947 /** 24948 * Interface definition for a callback to be invoked when this view is attached 24949 * or detached from its window. 24950 */ 24951 public interface OnAttachStateChangeListener { 24952 /** 24953 * Called when the view is attached to a window. 24954 * @param v The view that was attached 24955 */ 24956 public void onViewAttachedToWindow(View v); 24957 /** 24958 * Called when the view is detached from a window. 24959 * @param v The view that was detached 24960 */ 24961 public void onViewDetachedFromWindow(View v); 24962 } 24963 24964 /** 24965 * Listener for applying window insets on a view in a custom way. 24966 * 24967 * <p>Apps may choose to implement this interface if they want to apply custom policy 24968 * to the way that window insets are treated for a view. If an OnApplyWindowInsetsListener 24969 * is set, its 24970 * {@link OnApplyWindowInsetsListener#onApplyWindowInsets(View, WindowInsets) onApplyWindowInsets} 24971 * method will be called instead of the View's own 24972 * {@link #onApplyWindowInsets(WindowInsets) onApplyWindowInsets} method. The listener 24973 * may optionally call the parameter View's <code>onApplyWindowInsets</code> method to apply 24974 * the View's normal behavior as part of its own.</p> 24975 */ 24976 public interface OnApplyWindowInsetsListener { 24977 /** 24978 * When {@link View#setOnApplyWindowInsetsListener(View.OnApplyWindowInsetsListener) set} 24979 * on a View, this listener method will be called instead of the view's own 24980 * {@link View#onApplyWindowInsets(WindowInsets) onApplyWindowInsets} method. 24981 * 24982 * @param v The view applying window insets 24983 * @param insets The insets to apply 24984 * @return The insets supplied, minus any insets that were consumed 24985 */ 24986 public WindowInsets onApplyWindowInsets(View v, WindowInsets insets); 24987 } 24988 24989 private final class UnsetPressedState implements Runnable { 24990 @Override 24991 public void run() { 24992 setPressed(false); 24993 } 24994 } 24995 24996 /** 24997 * When a view becomes invisible checks if autofill considers the view invisible too. This 24998 * happens after the regular removal operation to make sure the operation is finished by the 24999 * time this is called. 25000 */ 25001 private static class VisibilityChangeForAutofillHandler extends Handler { 25002 private final AutofillManager mAfm; 25003 private final View mView; 25004 25005 private VisibilityChangeForAutofillHandler(@NonNull AutofillManager afm, 25006 @NonNull View view) { 25007 mAfm = afm; 25008 mView = view; 25009 } 25010 25011 @Override 25012 public void handleMessage(Message msg) { 25013 mAfm.notifyViewVisibilityChange(mView, mView.isShown()); 25014 } 25015 } 25016 25017 /** 25018 * Base class for derived classes that want to save and restore their own 25019 * state in {@link android.view.View#onSaveInstanceState()}. 25020 */ 25021 public static class BaseSavedState extends AbsSavedState { 25022 static final int START_ACTIVITY_REQUESTED_WHO_SAVED = 0b1; 25023 static final int IS_AUTOFILLED = 0b10; 25024 static final int AUTOFILL_ID = 0b100; 25025 25026 // Flags that describe what data in this state is valid 25027 int mSavedData; 25028 String mStartActivityRequestWhoSaved; 25029 boolean mIsAutofilled; 25030 int mAutofillViewId; 25031 25032 /** 25033 * Constructor used when reading from a parcel. Reads the state of the superclass. 25034 * 25035 * @param source parcel to read from 25036 */ 25037 public BaseSavedState(Parcel source) { 25038 this(source, null); 25039 } 25040 25041 /** 25042 * Constructor used when reading from a parcel using a given class loader. 25043 * Reads the state of the superclass. 25044 * 25045 * @param source parcel to read from 25046 * @param loader ClassLoader to use for reading 25047 */ 25048 public BaseSavedState(Parcel source, ClassLoader loader) { 25049 super(source, loader); 25050 mSavedData = source.readInt(); 25051 mStartActivityRequestWhoSaved = source.readString(); 25052 mIsAutofilled = source.readBoolean(); 25053 mAutofillViewId = source.readInt(); 25054 } 25055 25056 /** 25057 * Constructor called by derived classes when creating their SavedState objects 25058 * 25059 * @param superState The state of the superclass of this view 25060 */ 25061 public BaseSavedState(Parcelable superState) { 25062 super(superState); 25063 } 25064 25065 @Override 25066 public void writeToParcel(Parcel out, int flags) { 25067 super.writeToParcel(out, flags); 25068 25069 out.writeInt(mSavedData); 25070 out.writeString(mStartActivityRequestWhoSaved); 25071 out.writeBoolean(mIsAutofilled); 25072 out.writeInt(mAutofillViewId); 25073 } 25074 25075 public static final Parcelable.Creator<BaseSavedState> CREATOR 25076 = new Parcelable.ClassLoaderCreator<BaseSavedState>() { 25077 @Override 25078 public BaseSavedState createFromParcel(Parcel in) { 25079 return new BaseSavedState(in); 25080 } 25081 25082 @Override 25083 public BaseSavedState createFromParcel(Parcel in, ClassLoader loader) { 25084 return new BaseSavedState(in, loader); 25085 } 25086 25087 @Override 25088 public BaseSavedState[] newArray(int size) { 25089 return new BaseSavedState[size]; 25090 } 25091 }; 25092 } 25093 25094 /** 25095 * A set of information given to a view when it is attached to its parent 25096 * window. 25097 */ 25098 final static class AttachInfo { 25099 interface Callbacks { 25100 void playSoundEffect(int effectId); 25101 boolean performHapticFeedback(int effectId, boolean always); 25102 } 25103 25104 /** 25105 * InvalidateInfo is used to post invalidate(int, int, int, int) messages 25106 * to a Handler. This class contains the target (View) to invalidate and 25107 * the coordinates of the dirty rectangle. 25108 * 25109 * For performance purposes, this class also implements a pool of up to 25110 * POOL_LIMIT objects that get reused. This reduces memory allocations 25111 * whenever possible. 25112 */ 25113 static class InvalidateInfo { 25114 private static final int POOL_LIMIT = 10; 25115 25116 private static final SynchronizedPool<InvalidateInfo> sPool = 25117 new SynchronizedPool<InvalidateInfo>(POOL_LIMIT); 25118 25119 View target; 25120 25121 int left; 25122 int top; 25123 int right; 25124 int bottom; 25125 25126 public static InvalidateInfo obtain() { 25127 InvalidateInfo instance = sPool.acquire(); 25128 return (instance != null) ? instance : new InvalidateInfo(); 25129 } 25130 25131 public void recycle() { 25132 target = null; 25133 sPool.release(this); 25134 } 25135 } 25136 25137 final IWindowSession mSession; 25138 25139 final IWindow mWindow; 25140 25141 final IBinder mWindowToken; 25142 25143 Display mDisplay; 25144 25145 final Callbacks mRootCallbacks; 25146 25147 IWindowId mIWindowId; 25148 WindowId mWindowId; 25149 25150 /** 25151 * The top view of the hierarchy. 25152 */ 25153 View mRootView; 25154 25155 IBinder mPanelParentWindowToken; 25156 25157 boolean mHardwareAccelerated; 25158 boolean mHardwareAccelerationRequested; 25159 ThreadedRenderer mThreadedRenderer; 25160 List<RenderNode> mPendingAnimatingRenderNodes; 25161 25162 /** 25163 * The state of the display to which the window is attached, as reported 25164 * by {@link Display#getState()}. Note that the display state constants 25165 * declared by {@link Display} do not exactly line up with the screen state 25166 * constants declared by {@link View} (there are more display states than 25167 * screen states). 25168 */ 25169 int mDisplayState = Display.STATE_UNKNOWN; 25170 25171 /** 25172 * Scale factor used by the compatibility mode 25173 */ 25174 float mApplicationScale; 25175 25176 /** 25177 * Indicates whether the application is in compatibility mode 25178 */ 25179 boolean mScalingRequired; 25180 25181 /** 25182 * Left position of this view's window 25183 */ 25184 int mWindowLeft; 25185 25186 /** 25187 * Top position of this view's window 25188 */ 25189 int mWindowTop; 25190 25191 /** 25192 * Indicates whether views need to use 32-bit drawing caches 25193 */ 25194 boolean mUse32BitDrawingCache; 25195 25196 /** 25197 * For windows that are full-screen but using insets to layout inside 25198 * of the screen areas, these are the current insets to appear inside 25199 * the overscan area of the display. 25200 */ 25201 final Rect mOverscanInsets = new Rect(); 25202 25203 /** 25204 * For windows that are full-screen but using insets to layout inside 25205 * of the screen decorations, these are the current insets for the 25206 * content of the window. 25207 */ 25208 final Rect mContentInsets = new Rect(); 25209 25210 /** 25211 * For windows that are full-screen but using insets to layout inside 25212 * of the screen decorations, these are the current insets for the 25213 * actual visible parts of the window. 25214 */ 25215 final Rect mVisibleInsets = new Rect(); 25216 25217 /** 25218 * For windows that are full-screen but using insets to layout inside 25219 * of the screen decorations, these are the current insets for the 25220 * stable system windows. 25221 */ 25222 final Rect mStableInsets = new Rect(); 25223 25224 /** 25225 * For windows that include areas that are not covered by real surface these are the outsets 25226 * for real surface. 25227 */ 25228 final Rect mOutsets = new Rect(); 25229 25230 /** 25231 * In multi-window we force show the navigation bar. Because we don't want that the surface 25232 * size changes in this mode, we instead have a flag whether the navigation bar size should 25233 * always be consumed, so the app is treated like there is no virtual navigation bar at all. 25234 */ 25235 boolean mAlwaysConsumeNavBar; 25236 25237 /** 25238 * The internal insets given by this window. This value is 25239 * supplied by the client (through 25240 * {@link ViewTreeObserver.OnComputeInternalInsetsListener}) and will 25241 * be given to the window manager when changed to be used in laying 25242 * out windows behind it. 25243 */ 25244 final ViewTreeObserver.InternalInsetsInfo mGivenInternalInsets 25245 = new ViewTreeObserver.InternalInsetsInfo(); 25246 25247 /** 25248 * Set to true when mGivenInternalInsets is non-empty. 25249 */ 25250 boolean mHasNonEmptyGivenInternalInsets; 25251 25252 /** 25253 * All views in the window's hierarchy that serve as scroll containers, 25254 * used to determine if the window can be resized or must be panned 25255 * to adjust for a soft input area. 25256 */ 25257 final ArrayList<View> mScrollContainers = new ArrayList<View>(); 25258 25259 final KeyEvent.DispatcherState mKeyDispatchState 25260 = new KeyEvent.DispatcherState(); 25261 25262 /** 25263 * Indicates whether the view's window currently has the focus. 25264 */ 25265 boolean mHasWindowFocus; 25266 25267 /** 25268 * The current visibility of the window. 25269 */ 25270 int mWindowVisibility; 25271 25272 /** 25273 * Indicates the time at which drawing started to occur. 25274 */ 25275 long mDrawingTime; 25276 25277 /** 25278 * Indicates whether or not ignoring the DIRTY_MASK flags. 25279 */ 25280 boolean mIgnoreDirtyState; 25281 25282 /** 25283 * This flag tracks when the mIgnoreDirtyState flag is set during draw(), 25284 * to avoid clearing that flag prematurely. 25285 */ 25286 boolean mSetIgnoreDirtyState = false; 25287 25288 /** 25289 * Indicates whether the view's window is currently in touch mode. 25290 */ 25291 boolean mInTouchMode; 25292 25293 /** 25294 * Indicates whether the view has requested unbuffered input dispatching for the current 25295 * event stream. 25296 */ 25297 boolean mUnbufferedDispatchRequested; 25298 25299 /** 25300 * Indicates that ViewAncestor should trigger a global layout change 25301 * the next time it performs a traversal 25302 */ 25303 boolean mRecomputeGlobalAttributes; 25304 25305 /** 25306 * Always report new attributes at next traversal. 25307 */ 25308 boolean mForceReportNewAttributes; 25309 25310 /** 25311 * Set during a traveral if any views want to keep the screen on. 25312 */ 25313 boolean mKeepScreenOn; 25314 25315 /** 25316 * Set during a traveral if the light center needs to be updated. 25317 */ 25318 boolean mNeedsUpdateLightCenter; 25319 25320 /** 25321 * Bitwise-or of all of the values that views have passed to setSystemUiVisibility(). 25322 */ 25323 int mSystemUiVisibility; 25324 25325 /** 25326 * Hack to force certain system UI visibility flags to be cleared. 25327 */ 25328 int mDisabledSystemUiVisibility; 25329 25330 /** 25331 * Last global system UI visibility reported by the window manager. 25332 */ 25333 int mGlobalSystemUiVisibility = -1; 25334 25335 /** 25336 * True if a view in this hierarchy has an OnSystemUiVisibilityChangeListener 25337 * attached. 25338 */ 25339 boolean mHasSystemUiListeners; 25340 25341 /** 25342 * Set if the window has requested to extend into the overscan region 25343 * via WindowManager.LayoutParams.FLAG_LAYOUT_IN_OVERSCAN. 25344 */ 25345 boolean mOverscanRequested; 25346 25347 /** 25348 * Set if the visibility of any views has changed. 25349 */ 25350 boolean mViewVisibilityChanged; 25351 25352 /** 25353 * Set to true if a view has been scrolled. 25354 */ 25355 boolean mViewScrollChanged; 25356 25357 /** 25358 * Set to true if high contrast mode enabled 25359 */ 25360 boolean mHighContrastText; 25361 25362 /** 25363 * Set to true if a pointer event is currently being handled. 25364 */ 25365 boolean mHandlingPointerEvent; 25366 25367 /** 25368 * Global to the view hierarchy used as a temporary for dealing with 25369 * x/y points in the transparent region computations. 25370 */ 25371 final int[] mTransparentLocation = new int[2]; 25372 25373 /** 25374 * Global to the view hierarchy used as a temporary for dealing with 25375 * x/y points in the ViewGroup.invalidateChild implementation. 25376 */ 25377 final int[] mInvalidateChildLocation = new int[2]; 25378 25379 /** 25380 * Global to the view hierarchy used as a temporary for dealing with 25381 * computing absolute on-screen location. 25382 */ 25383 final int[] mTmpLocation = new int[2]; 25384 25385 /** 25386 * Global to the view hierarchy used as a temporary for dealing with 25387 * x/y location when view is transformed. 25388 */ 25389 final float[] mTmpTransformLocation = new float[2]; 25390 25391 /** 25392 * The view tree observer used to dispatch global events like 25393 * layout, pre-draw, touch mode change, etc. 25394 */ 25395 final ViewTreeObserver mTreeObserver; 25396 25397 /** 25398 * A Canvas used by the view hierarchy to perform bitmap caching. 25399 */ 25400 Canvas mCanvas; 25401 25402 /** 25403 * The view root impl. 25404 */ 25405 final ViewRootImpl mViewRootImpl; 25406 25407 /** 25408 * A Handler supplied by a view's {@link android.view.ViewRootImpl}. This 25409 * handler can be used to pump events in the UI events queue. 25410 */ 25411 final Handler mHandler; 25412 25413 /** 25414 * Temporary for use in computing invalidate rectangles while 25415 * calling up the hierarchy. 25416 */ 25417 final Rect mTmpInvalRect = new Rect(); 25418 25419 /** 25420 * Temporary for use in computing hit areas with transformed views 25421 */ 25422 final RectF mTmpTransformRect = new RectF(); 25423 25424 /** 25425 * Temporary for use in computing hit areas with transformed views 25426 */ 25427 final RectF mTmpTransformRect1 = new RectF(); 25428 25429 /** 25430 * Temporary list of rectanges. 25431 */ 25432 final List<RectF> mTmpRectList = new ArrayList<>(); 25433 25434 /** 25435 * Temporary for use in transforming invalidation rect 25436 */ 25437 final Matrix mTmpMatrix = new Matrix(); 25438 25439 /** 25440 * Temporary for use in transforming invalidation rect 25441 */ 25442 final Transformation mTmpTransformation = new Transformation(); 25443 25444 /** 25445 * Temporary for use in querying outlines from OutlineProviders 25446 */ 25447 final Outline mTmpOutline = new Outline(); 25448 25449 /** 25450 * Temporary list for use in collecting focusable descendents of a view. 25451 */ 25452 final ArrayList<View> mTempArrayList = new ArrayList<View>(24); 25453 25454 /** 25455 * The id of the window for accessibility purposes. 25456 */ 25457 int mAccessibilityWindowId = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID; 25458 25459 /** 25460 * Flags related to accessibility processing. 25461 * 25462 * @see AccessibilityNodeInfo#FLAG_INCLUDE_NOT_IMPORTANT_VIEWS 25463 * @see AccessibilityNodeInfo#FLAG_REPORT_VIEW_IDS 25464 */ 25465 int mAccessibilityFetchFlags; 25466 25467 /** 25468 * The drawable for highlighting accessibility focus. 25469 */ 25470 Drawable mAccessibilityFocusDrawable; 25471 25472 /** 25473 * The drawable for highlighting autofilled views. 25474 * 25475 * @see #isAutofilled() 25476 */ 25477 Drawable mAutofilledDrawable; 25478 25479 /** 25480 * Show where the margins, bounds and layout bounds are for each view. 25481 */ 25482 boolean mDebugLayout = SystemProperties.getBoolean(DEBUG_LAYOUT_PROPERTY, false); 25483 25484 /** 25485 * Point used to compute visible regions. 25486 */ 25487 final Point mPoint = new Point(); 25488 25489 /** 25490 * Used to track which View originated a requestLayout() call, used when 25491 * requestLayout() is called during layout. 25492 */ 25493 View mViewRequestingLayout; 25494 25495 /** 25496 * Used to track views that need (at least) a partial relayout at their current size 25497 * during the next traversal. 25498 */ 25499 List<View> mPartialLayoutViews = new ArrayList<>(); 25500 25501 /** 25502 * Swapped with mPartialLayoutViews during layout to avoid concurrent 25503 * modification. Lazily assigned during ViewRootImpl layout. 25504 */ 25505 List<View> mEmptyPartialLayoutViews; 25506 25507 /** 25508 * Used to track the identity of the current drag operation. 25509 */ 25510 IBinder mDragToken; 25511 25512 /** 25513 * The drag shadow surface for the current drag operation. 25514 */ 25515 public Surface mDragSurface; 25516 25517 25518 /** 25519 * The view that currently has a tooltip displayed. 25520 */ 25521 View mTooltipHost; 25522 25523 /** 25524 * Creates a new set of attachment information with the specified 25525 * events handler and thread. 25526 * 25527 * @param handler the events handler the view must use 25528 */ 25529 AttachInfo(IWindowSession session, IWindow window, Display display, 25530 ViewRootImpl viewRootImpl, Handler handler, Callbacks effectPlayer, 25531 Context context) { 25532 mSession = session; 25533 mWindow = window; 25534 mWindowToken = window.asBinder(); 25535 mDisplay = display; 25536 mViewRootImpl = viewRootImpl; 25537 mHandler = handler; 25538 mRootCallbacks = effectPlayer; 25539 mTreeObserver = new ViewTreeObserver(context); 25540 } 25541 } 25542 25543 /** 25544 * <p>ScrollabilityCache holds various fields used by a View when scrolling 25545 * is supported. This avoids keeping too many unused fields in most 25546 * instances of View.</p> 25547 */ 25548 private static class ScrollabilityCache implements Runnable { 25549 25550 /** 25551 * Scrollbars are not visible 25552 */ 25553 public static final int OFF = 0; 25554 25555 /** 25556 * Scrollbars are visible 25557 */ 25558 public static final int ON = 1; 25559 25560 /** 25561 * Scrollbars are fading away 25562 */ 25563 public static final int FADING = 2; 25564 25565 public boolean fadeScrollBars; 25566 25567 public int fadingEdgeLength; 25568 public int scrollBarDefaultDelayBeforeFade; 25569 public int scrollBarFadeDuration; 25570 25571 public int scrollBarSize; 25572 public int scrollBarMinTouchTarget; 25573 public ScrollBarDrawable scrollBar; 25574 public float[] interpolatorValues; 25575 public View host; 25576 25577 public final Paint paint; 25578 public final Matrix matrix; 25579 public Shader shader; 25580 25581 public final Interpolator scrollBarInterpolator = new Interpolator(1, 2); 25582 25583 private static final float[] OPAQUE = { 255 }; 25584 private static final float[] TRANSPARENT = { 0.0f }; 25585 25586 /** 25587 * When fading should start. This time moves into the future every time 25588 * a new scroll happens. Measured based on SystemClock.uptimeMillis() 25589 */ 25590 public long fadeStartTime; 25591 25592 25593 /** 25594 * The current state of the scrollbars: ON, OFF, or FADING 25595 */ 25596 public int state = OFF; 25597 25598 private int mLastColor; 25599 25600 public final Rect mScrollBarBounds = new Rect(); 25601 public final Rect mScrollBarTouchBounds = new Rect(); 25602 25603 public static final int NOT_DRAGGING = 0; 25604 public static final int DRAGGING_VERTICAL_SCROLL_BAR = 1; 25605 public static final int DRAGGING_HORIZONTAL_SCROLL_BAR = 2; 25606 public int mScrollBarDraggingState = NOT_DRAGGING; 25607 25608 public float mScrollBarDraggingPos = 0; 25609 25610 public ScrollabilityCache(ViewConfiguration configuration, View host) { 25611 fadingEdgeLength = configuration.getScaledFadingEdgeLength(); 25612 scrollBarSize = configuration.getScaledScrollBarSize(); 25613 scrollBarMinTouchTarget = configuration.getScaledMinScrollbarTouchTarget(); 25614 scrollBarDefaultDelayBeforeFade = ViewConfiguration.getScrollDefaultDelay(); 25615 scrollBarFadeDuration = ViewConfiguration.getScrollBarFadeDuration(); 25616 25617 paint = new Paint(); 25618 matrix = new Matrix(); 25619 // use use a height of 1, and then wack the matrix each time we 25620 // actually use it. 25621 shader = new LinearGradient(0, 0, 0, 1, 0xFF000000, 0, Shader.TileMode.CLAMP); 25622 paint.setShader(shader); 25623 paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); 25624 25625 this.host = host; 25626 } 25627 25628 public void setFadeColor(int color) { 25629 if (color != mLastColor) { 25630 mLastColor = color; 25631 25632 if (color != 0) { 25633 shader = new LinearGradient(0, 0, 0, 1, color | 0xFF000000, 25634 color & 0x00FFFFFF, Shader.TileMode.CLAMP); 25635 paint.setShader(shader); 25636 // Restore the default transfer mode (src_over) 25637 paint.setXfermode(null); 25638 } else { 25639 shader = new LinearGradient(0, 0, 0, 1, 0xFF000000, 0, Shader.TileMode.CLAMP); 25640 paint.setShader(shader); 25641 paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); 25642 } 25643 } 25644 } 25645 25646 public void run() { 25647 long now = AnimationUtils.currentAnimationTimeMillis(); 25648 if (now >= fadeStartTime) { 25649 25650 // the animation fades the scrollbars out by changing 25651 // the opacity (alpha) from fully opaque to fully 25652 // transparent 25653 int nextFrame = (int) now; 25654 int framesCount = 0; 25655 25656 Interpolator interpolator = scrollBarInterpolator; 25657 25658 // Start opaque 25659 interpolator.setKeyFrame(framesCount++, nextFrame, OPAQUE); 25660 25661 // End transparent 25662 nextFrame += scrollBarFadeDuration; 25663 interpolator.setKeyFrame(framesCount, nextFrame, TRANSPARENT); 25664 25665 state = FADING; 25666 25667 // Kick off the fade animation 25668 host.invalidate(true); 25669 } 25670 } 25671 } 25672 25673 /** 25674 * Resuable callback for sending 25675 * {@link AccessibilityEvent#TYPE_VIEW_SCROLLED} accessibility event. 25676 */ 25677 private class SendViewScrolledAccessibilityEvent implements Runnable { 25678 public volatile boolean mIsPending; 25679 25680 public void run() { 25681 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SCROLLED); 25682 mIsPending = false; 25683 } 25684 } 25685 25686 /** 25687 * <p> 25688 * This class represents a delegate that can be registered in a {@link View} 25689 * to enhance accessibility support via composition rather via inheritance. 25690 * It is specifically targeted to widget developers that extend basic View 25691 * classes i.e. classes in package android.view, that would like their 25692 * applications to be backwards compatible. 25693 * </p> 25694 * <div class="special reference"> 25695 * <h3>Developer Guides</h3> 25696 * <p>For more information about making applications accessible, read the 25697 * <a href="{@docRoot}guide/topics/ui/accessibility/index.html">Accessibility</a> 25698 * developer guide.</p> 25699 * </div> 25700 * <p> 25701 * A scenario in which a developer would like to use an accessibility delegate 25702 * is overriding a method introduced in a later API version than the minimal API 25703 * version supported by the application. For example, the method 25704 * {@link View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} is not available 25705 * in API version 4 when the accessibility APIs were first introduced. If a 25706 * developer would like his application to run on API version 4 devices (assuming 25707 * all other APIs used by the application are version 4 or lower) and take advantage 25708 * of this method, instead of overriding the method which would break the application's 25709 * backwards compatibility, he can override the corresponding method in this 25710 * delegate and register the delegate in the target View if the API version of 25711 * the system is high enough, i.e. the API version is the same as or higher than the API 25712 * version that introduced 25713 * {@link View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)}. 25714 * </p> 25715 * <p> 25716 * Here is an example implementation: 25717 * </p> 25718 * <code><pre><p> 25719 * if (Build.VERSION.SDK_INT >= 14) { 25720 * // If the API version is equal of higher than the version in 25721 * // which onInitializeAccessibilityNodeInfo was introduced we 25722 * // register a delegate with a customized implementation. 25723 * View view = findViewById(R.id.view_id); 25724 * view.setAccessibilityDelegate(new AccessibilityDelegate() { 25725 * public void onInitializeAccessibilityNodeInfo(View host, 25726 * AccessibilityNodeInfo info) { 25727 * // Let the default implementation populate the info. 25728 * super.onInitializeAccessibilityNodeInfo(host, info); 25729 * // Set some other information. 25730 * info.setEnabled(host.isEnabled()); 25731 * } 25732 * }); 25733 * } 25734 * </code></pre></p> 25735 * <p> 25736 * This delegate contains methods that correspond to the accessibility methods 25737 * in View. If a delegate has been specified the implementation in View hands 25738 * off handling to the corresponding method in this delegate. The default 25739 * implementation the delegate methods behaves exactly as the corresponding 25740 * method in View for the case of no accessibility delegate been set. Hence, 25741 * to customize the behavior of a View method, clients can override only the 25742 * corresponding delegate method without altering the behavior of the rest 25743 * accessibility related methods of the host view. 25744 * </p> 25745 * <p> 25746 * <strong>Note:</strong> On platform versions prior to 25747 * {@link android.os.Build.VERSION_CODES#M API 23}, delegate methods on 25748 * views in the {@code android.widget.*} package are called <i>before</i> 25749 * host methods. This prevents certain properties such as class name from 25750 * being modified by overriding 25751 * {@link AccessibilityDelegate#onInitializeAccessibilityNodeInfo(View, AccessibilityNodeInfo)}, 25752 * as any changes will be overwritten by the host class. 25753 * <p> 25754 * Starting in {@link android.os.Build.VERSION_CODES#M API 23}, delegate 25755 * methods are called <i>after</i> host methods, which all properties to be 25756 * modified without being overwritten by the host class. 25757 */ 25758 public static class AccessibilityDelegate { 25759 25760 /** 25761 * Sends an accessibility event of the given type. If accessibility is not 25762 * enabled this method has no effect. 25763 * <p> 25764 * The default implementation behaves as {@link View#sendAccessibilityEvent(int) 25765 * View#sendAccessibilityEvent(int)} for the case of no accessibility delegate 25766 * been set. 25767 * </p> 25768 * 25769 * @param host The View hosting the delegate. 25770 * @param eventType The type of the event to send. 25771 * 25772 * @see View#sendAccessibilityEvent(int) View#sendAccessibilityEvent(int) 25773 */ 25774 public void sendAccessibilityEvent(View host, int eventType) { 25775 host.sendAccessibilityEventInternal(eventType); 25776 } 25777 25778 /** 25779 * Performs the specified accessibility action on the view. For 25780 * possible accessibility actions look at {@link AccessibilityNodeInfo}. 25781 * <p> 25782 * The default implementation behaves as 25783 * {@link View#performAccessibilityAction(int, Bundle) 25784 * View#performAccessibilityAction(int, Bundle)} for the case of 25785 * no accessibility delegate been set. 25786 * </p> 25787 * 25788 * @param action The action to perform. 25789 * @return Whether the action was performed. 25790 * 25791 * @see View#performAccessibilityAction(int, Bundle) 25792 * View#performAccessibilityAction(int, Bundle) 25793 */ 25794 public boolean performAccessibilityAction(View host, int action, Bundle args) { 25795 return host.performAccessibilityActionInternal(action, args); 25796 } 25797 25798 /** 25799 * Sends an accessibility event. This method behaves exactly as 25800 * {@link #sendAccessibilityEvent(View, int)} but takes as an argument an 25801 * empty {@link AccessibilityEvent} and does not perform a check whether 25802 * accessibility is enabled. 25803 * <p> 25804 * The default implementation behaves as 25805 * {@link View#sendAccessibilityEventUnchecked(AccessibilityEvent) 25806 * View#sendAccessibilityEventUnchecked(AccessibilityEvent)} for 25807 * the case of no accessibility delegate been set. 25808 * </p> 25809 * 25810 * @param host The View hosting the delegate. 25811 * @param event The event to send. 25812 * 25813 * @see View#sendAccessibilityEventUnchecked(AccessibilityEvent) 25814 * View#sendAccessibilityEventUnchecked(AccessibilityEvent) 25815 */ 25816 public void sendAccessibilityEventUnchecked(View host, AccessibilityEvent event) { 25817 host.sendAccessibilityEventUncheckedInternal(event); 25818 } 25819 25820 /** 25821 * Dispatches an {@link AccessibilityEvent} to the host {@link View} first and then 25822 * to its children for adding their text content to the event. 25823 * <p> 25824 * The default implementation behaves as 25825 * {@link View#dispatchPopulateAccessibilityEvent(AccessibilityEvent) 25826 * View#dispatchPopulateAccessibilityEvent(AccessibilityEvent)} for 25827 * the case of no accessibility delegate been set. 25828 * </p> 25829 * 25830 * @param host The View hosting the delegate. 25831 * @param event The event. 25832 * @return True if the event population was completed. 25833 * 25834 * @see View#dispatchPopulateAccessibilityEvent(AccessibilityEvent) 25835 * View#dispatchPopulateAccessibilityEvent(AccessibilityEvent) 25836 */ 25837 public boolean dispatchPopulateAccessibilityEvent(View host, AccessibilityEvent event) { 25838 return host.dispatchPopulateAccessibilityEventInternal(event); 25839 } 25840 25841 /** 25842 * Gives a chance to the host View to populate the accessibility event with its 25843 * text content. 25844 * <p> 25845 * The default implementation behaves as 25846 * {@link View#onPopulateAccessibilityEvent(AccessibilityEvent) 25847 * View#onPopulateAccessibilityEvent(AccessibilityEvent)} for 25848 * the case of no accessibility delegate been set. 25849 * </p> 25850 * 25851 * @param host The View hosting the delegate. 25852 * @param event The accessibility event which to populate. 25853 * 25854 * @see View#onPopulateAccessibilityEvent(AccessibilityEvent) 25855 * View#onPopulateAccessibilityEvent(AccessibilityEvent) 25856 */ 25857 public void onPopulateAccessibilityEvent(View host, AccessibilityEvent event) { 25858 host.onPopulateAccessibilityEventInternal(event); 25859 } 25860 25861 /** 25862 * Initializes an {@link AccessibilityEvent} with information about the 25863 * the host View which is the event source. 25864 * <p> 25865 * The default implementation behaves as 25866 * {@link View#onInitializeAccessibilityEvent(AccessibilityEvent) 25867 * View#onInitializeAccessibilityEvent(AccessibilityEvent)} for 25868 * the case of no accessibility delegate been set. 25869 * </p> 25870 * 25871 * @param host The View hosting the delegate. 25872 * @param event The event to initialize. 25873 * 25874 * @see View#onInitializeAccessibilityEvent(AccessibilityEvent) 25875 * View#onInitializeAccessibilityEvent(AccessibilityEvent) 25876 */ 25877 public void onInitializeAccessibilityEvent(View host, AccessibilityEvent event) { 25878 host.onInitializeAccessibilityEventInternal(event); 25879 } 25880 25881 /** 25882 * Initializes an {@link AccessibilityNodeInfo} with information about the host view. 25883 * <p> 25884 * The default implementation behaves as 25885 * {@link View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo) 25886 * View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} for 25887 * the case of no accessibility delegate been set. 25888 * </p> 25889 * 25890 * @param host The View hosting the delegate. 25891 * @param info The instance to initialize. 25892 * 25893 * @see View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo) 25894 * View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo) 25895 */ 25896 public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) { 25897 host.onInitializeAccessibilityNodeInfoInternal(info); 25898 } 25899 25900 /** 25901 * Adds extra data to an {@link AccessibilityNodeInfo} based on an explicit request for the 25902 * additional data. 25903 * <p> 25904 * This method only needs to be implemented if the View offers to provide additional data. 25905 * </p> 25906 * <p> 25907 * The default implementation behaves as 25908 * {@link View#addExtraDataToAccessibilityNodeInfo(AccessibilityNodeInfo, String, Bundle) 25909 * for the case where no accessibility delegate is set. 25910 * </p> 25911 * 25912 * @param host The View hosting the delegate. Never {@code null}. 25913 * @param info The info to which to add the extra data. Never {@code null}. 25914 * @param extraDataKey A key specifying the type of extra data to add to the info. The 25915 * extra data should be added to the {@link Bundle} returned by 25916 * the info's {@link AccessibilityNodeInfo#getExtras} method. Never 25917 * {@code null}. 25918 * @param arguments A {@link Bundle} holding any arguments relevant for this request. 25919 * May be {@code null} if the if the service provided no arguments. 25920 * 25921 * @see AccessibilityNodeInfo#setExtraAvailableData 25922 */ 25923 public void addExtraDataToAccessibilityNodeInfo(@NonNull View host, 25924 @NonNull AccessibilityNodeInfo info, @NonNull String extraDataKey, 25925 @Nullable Bundle arguments) { 25926 host.addExtraDataToAccessibilityNodeInfo(info, extraDataKey, arguments); 25927 } 25928 25929 /** 25930 * Called when a child of the host View has requested sending an 25931 * {@link AccessibilityEvent} and gives an opportunity to the parent (the host) 25932 * to augment the event. 25933 * <p> 25934 * The default implementation behaves as 25935 * {@link ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent) 25936 * ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent)} for 25937 * the case of no accessibility delegate been set. 25938 * </p> 25939 * 25940 * @param host The View hosting the delegate. 25941 * @param child The child which requests sending the event. 25942 * @param event The event to be sent. 25943 * @return True if the event should be sent 25944 * 25945 * @see ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent) 25946 * ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent) 25947 */ 25948 public boolean onRequestSendAccessibilityEvent(ViewGroup host, View child, 25949 AccessibilityEvent event) { 25950 return host.onRequestSendAccessibilityEventInternal(child, event); 25951 } 25952 25953 /** 25954 * Gets the provider for managing a virtual view hierarchy rooted at this View 25955 * and reported to {@link android.accessibilityservice.AccessibilityService}s 25956 * that explore the window content. 25957 * <p> 25958 * The default implementation behaves as 25959 * {@link View#getAccessibilityNodeProvider() View#getAccessibilityNodeProvider()} for 25960 * the case of no accessibility delegate been set. 25961 * </p> 25962 * 25963 * @return The provider. 25964 * 25965 * @see AccessibilityNodeProvider 25966 */ 25967 public AccessibilityNodeProvider getAccessibilityNodeProvider(View host) { 25968 return null; 25969 } 25970 25971 /** 25972 * Returns an {@link AccessibilityNodeInfo} representing the host view from the 25973 * point of view of an {@link android.accessibilityservice.AccessibilityService}. 25974 * This method is responsible for obtaining an accessibility node info from a 25975 * pool of reusable instances and calling 25976 * {@link #onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} on the host 25977 * view to initialize the former. 25978 * <p> 25979 * <strong>Note:</strong> The client is responsible for recycling the obtained 25980 * instance by calling {@link AccessibilityNodeInfo#recycle()} to minimize object 25981 * creation. 25982 * </p> 25983 * <p> 25984 * The default implementation behaves as 25985 * {@link View#createAccessibilityNodeInfo() View#createAccessibilityNodeInfo()} for 25986 * the case of no accessibility delegate been set. 25987 * </p> 25988 * @return A populated {@link AccessibilityNodeInfo}. 25989 * 25990 * @see AccessibilityNodeInfo 25991 * 25992 * @hide 25993 */ 25994 public AccessibilityNodeInfo createAccessibilityNodeInfo(View host) { 25995 return host.createAccessibilityNodeInfoInternal(); 25996 } 25997 } 25998 25999 private static class MatchIdPredicate implements Predicate<View> { 26000 public int mId; 26001 26002 @Override 26003 public boolean test(View view) { 26004 return (view.mID == mId); 26005 } 26006 } 26007 26008 private static class MatchLabelForPredicate implements Predicate<View> { 26009 private int mLabeledId; 26010 26011 @Override 26012 public boolean test(View view) { 26013 return (view.mLabelForId == mLabeledId); 26014 } 26015 } 26016 26017 /** 26018 * Dump all private flags in readable format, useful for documentation and 26019 * sanity checking. 26020 */ 26021 private static void dumpFlags() { 26022 final HashMap<String, String> found = Maps.newHashMap(); 26023 try { 26024 for (Field field : View.class.getDeclaredFields()) { 26025 final int modifiers = field.getModifiers(); 26026 if (Modifier.isStatic(modifiers) && Modifier.isFinal(modifiers)) { 26027 if (field.getType().equals(int.class)) { 26028 final int value = field.getInt(null); 26029 dumpFlag(found, field.getName(), value); 26030 } else if (field.getType().equals(int[].class)) { 26031 final int[] values = (int[]) field.get(null); 26032 for (int i = 0; i < values.length; i++) { 26033 dumpFlag(found, field.getName() + "[" + i + "]", values[i]); 26034 } 26035 } 26036 } 26037 } 26038 } catch (IllegalAccessException e) { 26039 throw new RuntimeException(e); 26040 } 26041 26042 final ArrayList<String> keys = Lists.newArrayList(); 26043 keys.addAll(found.keySet()); 26044 Collections.sort(keys); 26045 for (String key : keys) { 26046 Log.d(VIEW_LOG_TAG, found.get(key)); 26047 } 26048 } 26049 26050 private static void dumpFlag(HashMap<String, String> found, String name, int value) { 26051 // Sort flags by prefix, then by bits, always keeping unique keys 26052 final String bits = String.format("%32s", Integer.toBinaryString(value)).replace('0', ' '); 26053 final int prefix = name.indexOf('_'); 26054 final String key = (prefix > 0 ? name.substring(0, prefix) : name) + bits + name; 26055 final String output = bits + " " + name; 26056 found.put(key, output); 26057 } 26058 26059 /** {@hide} */ 26060 public void encode(@NonNull ViewHierarchyEncoder stream) { 26061 stream.beginObject(this); 26062 encodeProperties(stream); 26063 stream.endObject(); 26064 } 26065 26066 /** {@hide} */ 26067 @CallSuper 26068 protected void encodeProperties(@NonNull ViewHierarchyEncoder stream) { 26069 Object resolveId = ViewDebug.resolveId(getContext(), mID); 26070 if (resolveId instanceof String) { 26071 stream.addProperty("id", (String) resolveId); 26072 } else { 26073 stream.addProperty("id", mID); 26074 } 26075 26076 stream.addProperty("misc:transformation.alpha", 26077 mTransformationInfo != null ? mTransformationInfo.mAlpha : 0); 26078 stream.addProperty("misc:transitionName", getTransitionName()); 26079 26080 // layout 26081 stream.addProperty("layout:left", mLeft); 26082 stream.addProperty("layout:right", mRight); 26083 stream.addProperty("layout:top", mTop); 26084 stream.addProperty("layout:bottom", mBottom); 26085 stream.addProperty("layout:width", getWidth()); 26086 stream.addProperty("layout:height", getHeight()); 26087 stream.addProperty("layout:layoutDirection", getLayoutDirection()); 26088 stream.addProperty("layout:layoutRtl", isLayoutRtl()); 26089 stream.addProperty("layout:hasTransientState", hasTransientState()); 26090 stream.addProperty("layout:baseline", getBaseline()); 26091 26092 // layout params 26093 ViewGroup.LayoutParams layoutParams = getLayoutParams(); 26094 if (layoutParams != null) { 26095 stream.addPropertyKey("layoutParams"); 26096 layoutParams.encode(stream); 26097 } 26098 26099 // scrolling 26100 stream.addProperty("scrolling:scrollX", mScrollX); 26101 stream.addProperty("scrolling:scrollY", mScrollY); 26102 26103 // padding 26104 stream.addProperty("padding:paddingLeft", mPaddingLeft); 26105 stream.addProperty("padding:paddingRight", mPaddingRight); 26106 stream.addProperty("padding:paddingTop", mPaddingTop); 26107 stream.addProperty("padding:paddingBottom", mPaddingBottom); 26108 stream.addProperty("padding:userPaddingRight", mUserPaddingRight); 26109 stream.addProperty("padding:userPaddingLeft", mUserPaddingLeft); 26110 stream.addProperty("padding:userPaddingBottom", mUserPaddingBottom); 26111 stream.addProperty("padding:userPaddingStart", mUserPaddingStart); 26112 stream.addProperty("padding:userPaddingEnd", mUserPaddingEnd); 26113 26114 // measurement 26115 stream.addProperty("measurement:minHeight", mMinHeight); 26116 stream.addProperty("measurement:minWidth", mMinWidth); 26117 stream.addProperty("measurement:measuredWidth", mMeasuredWidth); 26118 stream.addProperty("measurement:measuredHeight", mMeasuredHeight); 26119 26120 // drawing 26121 stream.addProperty("drawing:elevation", getElevation()); 26122 stream.addProperty("drawing:translationX", getTranslationX()); 26123 stream.addProperty("drawing:translationY", getTranslationY()); 26124 stream.addProperty("drawing:translationZ", getTranslationZ()); 26125 stream.addProperty("drawing:rotation", getRotation()); 26126 stream.addProperty("drawing:rotationX", getRotationX()); 26127 stream.addProperty("drawing:rotationY", getRotationY()); 26128 stream.addProperty("drawing:scaleX", getScaleX()); 26129 stream.addProperty("drawing:scaleY", getScaleY()); 26130 stream.addProperty("drawing:pivotX", getPivotX()); 26131 stream.addProperty("drawing:pivotY", getPivotY()); 26132 stream.addProperty("drawing:opaque", isOpaque()); 26133 stream.addProperty("drawing:alpha", getAlpha()); 26134 stream.addProperty("drawing:transitionAlpha", getTransitionAlpha()); 26135 stream.addProperty("drawing:shadow", hasShadow()); 26136 stream.addProperty("drawing:solidColor", getSolidColor()); 26137 stream.addProperty("drawing:layerType", mLayerType); 26138 stream.addProperty("drawing:willNotDraw", willNotDraw()); 26139 stream.addProperty("drawing:hardwareAccelerated", isHardwareAccelerated()); 26140 stream.addProperty("drawing:willNotCacheDrawing", willNotCacheDrawing()); 26141 stream.addProperty("drawing:drawingCacheEnabled", isDrawingCacheEnabled()); 26142 stream.addProperty("drawing:overlappingRendering", hasOverlappingRendering()); 26143 26144 // focus 26145 stream.addProperty("focus:hasFocus", hasFocus()); 26146 stream.addProperty("focus:isFocused", isFocused()); 26147 stream.addProperty("focus:focusable", getFocusable()); 26148 stream.addProperty("focus:isFocusable", isFocusable()); 26149 stream.addProperty("focus:isFocusableInTouchMode", isFocusableInTouchMode()); 26150 26151 stream.addProperty("misc:clickable", isClickable()); 26152 stream.addProperty("misc:pressed", isPressed()); 26153 stream.addProperty("misc:selected", isSelected()); 26154 stream.addProperty("misc:touchMode", isInTouchMode()); 26155 stream.addProperty("misc:hovered", isHovered()); 26156 stream.addProperty("misc:activated", isActivated()); 26157 26158 stream.addProperty("misc:visibility", getVisibility()); 26159 stream.addProperty("misc:fitsSystemWindows", getFitsSystemWindows()); 26160 stream.addProperty("misc:filterTouchesWhenObscured", getFilterTouchesWhenObscured()); 26161 26162 stream.addProperty("misc:enabled", isEnabled()); 26163 stream.addProperty("misc:soundEffectsEnabled", isSoundEffectsEnabled()); 26164 stream.addProperty("misc:hapticFeedbackEnabled", isHapticFeedbackEnabled()); 26165 26166 // theme attributes 26167 Resources.Theme theme = getContext().getTheme(); 26168 if (theme != null) { 26169 stream.addPropertyKey("theme"); 26170 theme.encode(stream); 26171 } 26172 26173 // view attribute information 26174 int n = mAttributes != null ? mAttributes.length : 0; 26175 stream.addProperty("meta:__attrCount__", n/2); 26176 for (int i = 0; i < n; i += 2) { 26177 stream.addProperty("meta:__attr__" + mAttributes[i], mAttributes[i+1]); 26178 } 26179 26180 stream.addProperty("misc:scrollBarStyle", getScrollBarStyle()); 26181 26182 // text 26183 stream.addProperty("text:textDirection", getTextDirection()); 26184 stream.addProperty("text:textAlignment", getTextAlignment()); 26185 26186 // accessibility 26187 CharSequence contentDescription = getContentDescription(); 26188 stream.addProperty("accessibility:contentDescription", 26189 contentDescription == null ? "" : contentDescription.toString()); 26190 stream.addProperty("accessibility:labelFor", getLabelFor()); 26191 stream.addProperty("accessibility:importantForAccessibility", getImportantForAccessibility()); 26192 } 26193 26194 /** 26195 * Determine if this view is rendered on a round wearable device and is the main view 26196 * on the screen. 26197 */ 26198 boolean shouldDrawRoundScrollbar() { 26199 if (!mResources.getConfiguration().isScreenRound() || mAttachInfo == null) { 26200 return false; 26201 } 26202 26203 final View rootView = getRootView(); 26204 final WindowInsets insets = getRootWindowInsets(); 26205 26206 int height = getHeight(); 26207 int width = getWidth(); 26208 int displayHeight = rootView.getHeight(); 26209 int displayWidth = rootView.getWidth(); 26210 26211 if (height != displayHeight || width != displayWidth) { 26212 return false; 26213 } 26214 26215 getLocationInWindow(mAttachInfo.mTmpLocation); 26216 return mAttachInfo.mTmpLocation[0] == insets.getStableInsetLeft() 26217 && mAttachInfo.mTmpLocation[1] == insets.getStableInsetTop(); 26218 } 26219 26220 /** 26221 * Sets the tooltip text which will be displayed in a small popup next to the view. 26222 * <p> 26223 * The tooltip will be displayed: 26224 * <ul> 26225 * <li>On long click, unless it is handled otherwise (by OnLongClickListener or a context 26226 * menu). </li> 26227 * <li>On hover, after a brief delay since the pointer has stopped moving </li> 26228 * </ul> 26229 * <p> 26230 * <strong>Note:</strong> Do not override this method, as it will have no 26231 * effect on the text displayed in the tooltip. 26232 * 26233 * @param tooltipText the tooltip text, or null if no tooltip is required 26234 * @see #getTooltipText() 26235 * @attr ref android.R.styleable#View_tooltipText 26236 */ 26237 public void setTooltipText(@Nullable CharSequence tooltipText) { 26238 if (TextUtils.isEmpty(tooltipText)) { 26239 setFlags(0, TOOLTIP); 26240 hideTooltip(); 26241 mTooltipInfo = null; 26242 } else { 26243 setFlags(TOOLTIP, TOOLTIP); 26244 if (mTooltipInfo == null) { 26245 mTooltipInfo = new TooltipInfo(); 26246 mTooltipInfo.mShowTooltipRunnable = this::showHoverTooltip; 26247 mTooltipInfo.mHideTooltipRunnable = this::hideTooltip; 26248 } 26249 mTooltipInfo.mTooltipText = tooltipText; 26250 } 26251 } 26252 26253 /** 26254 * @hide Binary compatibility stub. To be removed when we finalize O APIs. 26255 */ 26256 public void setTooltip(@Nullable CharSequence tooltipText) { 26257 setTooltipText(tooltipText); 26258 } 26259 26260 /** 26261 * Returns the view's tooltip text. 26262 * 26263 * <strong>Note:</strong> Do not override this method, as it will have no 26264 * effect on the text displayed in the tooltip. You must call 26265 * {@link #setTooltipText(CharSequence)} to modify the tooltip text. 26266 * 26267 * @return the tooltip text 26268 * @see #setTooltipText(CharSequence) 26269 * @attr ref android.R.styleable#View_tooltipText 26270 */ 26271 @Nullable 26272 public CharSequence getTooltipText() { 26273 return mTooltipInfo != null ? mTooltipInfo.mTooltipText : null; 26274 } 26275 26276 /** 26277 * @hide Binary compatibility stub. To be removed when we finalize O APIs. 26278 */ 26279 @Nullable 26280 public CharSequence getTooltip() { 26281 return getTooltipText(); 26282 } 26283 26284 private boolean showTooltip(int x, int y, boolean fromLongClick) { 26285 if (mAttachInfo == null || mTooltipInfo == null) { 26286 return false; 26287 } 26288 if ((mViewFlags & ENABLED_MASK) != ENABLED) { 26289 return false; 26290 } 26291 if (TextUtils.isEmpty(mTooltipInfo.mTooltipText)) { 26292 return false; 26293 } 26294 hideTooltip(); 26295 mTooltipInfo.mTooltipFromLongClick = fromLongClick; 26296 mTooltipInfo.mTooltipPopup = new TooltipPopup(getContext()); 26297 final boolean fromTouch = (mPrivateFlags3 & PFLAG3_FINGER_DOWN) == PFLAG3_FINGER_DOWN; 26298 mTooltipInfo.mTooltipPopup.show(this, x, y, fromTouch, mTooltipInfo.mTooltipText); 26299 mAttachInfo.mTooltipHost = this; 26300 return true; 26301 } 26302 26303 void hideTooltip() { 26304 if (mTooltipInfo == null) { 26305 return; 26306 } 26307 removeCallbacks(mTooltipInfo.mShowTooltipRunnable); 26308 if (mTooltipInfo.mTooltipPopup == null) { 26309 return; 26310 } 26311 mTooltipInfo.mTooltipPopup.hide(); 26312 mTooltipInfo.mTooltipPopup = null; 26313 mTooltipInfo.mTooltipFromLongClick = false; 26314 if (mAttachInfo != null) { 26315 mAttachInfo.mTooltipHost = null; 26316 } 26317 } 26318 26319 private boolean showLongClickTooltip(int x, int y) { 26320 removeCallbacks(mTooltipInfo.mShowTooltipRunnable); 26321 removeCallbacks(mTooltipInfo.mHideTooltipRunnable); 26322 return showTooltip(x, y, true); 26323 } 26324 26325 private void showHoverTooltip() { 26326 showTooltip(mTooltipInfo.mAnchorX, mTooltipInfo.mAnchorY, false); 26327 } 26328 26329 boolean dispatchTooltipHoverEvent(MotionEvent event) { 26330 if (mTooltipInfo == null) { 26331 return false; 26332 } 26333 switch(event.getAction()) { 26334 case MotionEvent.ACTION_HOVER_MOVE: 26335 if ((mViewFlags & TOOLTIP) != TOOLTIP || (mViewFlags & ENABLED_MASK) != ENABLED) { 26336 break; 26337 } 26338 if (!mTooltipInfo.mTooltipFromLongClick) { 26339 if (mTooltipInfo.mTooltipPopup == null) { 26340 // Schedule showing the tooltip after a timeout. 26341 mTooltipInfo.mAnchorX = (int) event.getX(); 26342 mTooltipInfo.mAnchorY = (int) event.getY(); 26343 removeCallbacks(mTooltipInfo.mShowTooltipRunnable); 26344 postDelayed(mTooltipInfo.mShowTooltipRunnable, 26345 ViewConfiguration.getHoverTooltipShowTimeout()); 26346 } 26347 26348 // Hide hover-triggered tooltip after a period of inactivity. 26349 // Match the timeout used by NativeInputManager to hide the mouse pointer 26350 // (depends on SYSTEM_UI_FLAG_LOW_PROFILE being set). 26351 final int timeout; 26352 if ((getWindowSystemUiVisibility() & SYSTEM_UI_FLAG_LOW_PROFILE) 26353 == SYSTEM_UI_FLAG_LOW_PROFILE) { 26354 timeout = ViewConfiguration.getHoverTooltipHideShortTimeout(); 26355 } else { 26356 timeout = ViewConfiguration.getHoverTooltipHideTimeout(); 26357 } 26358 removeCallbacks(mTooltipInfo.mHideTooltipRunnable); 26359 postDelayed(mTooltipInfo.mHideTooltipRunnable, timeout); 26360 } 26361 return true; 26362 26363 case MotionEvent.ACTION_HOVER_EXIT: 26364 if (!mTooltipInfo.mTooltipFromLongClick) { 26365 hideTooltip(); 26366 } 26367 break; 26368 } 26369 return false; 26370 } 26371 26372 void handleTooltipKey(KeyEvent event) { 26373 switch (event.getAction()) { 26374 case KeyEvent.ACTION_DOWN: 26375 if (event.getRepeatCount() == 0) { 26376 hideTooltip(); 26377 } 26378 break; 26379 26380 case KeyEvent.ACTION_UP: 26381 handleTooltipUp(); 26382 break; 26383 } 26384 } 26385 26386 private void handleTooltipUp() { 26387 if (mTooltipInfo == null || mTooltipInfo.mTooltipPopup == null) { 26388 return; 26389 } 26390 removeCallbacks(mTooltipInfo.mHideTooltipRunnable); 26391 postDelayed(mTooltipInfo.mHideTooltipRunnable, 26392 ViewConfiguration.getLongPressTooltipHideTimeout()); 26393 } 26394 26395 private int getFocusableAttribute(TypedArray attributes) { 26396 TypedValue val = new TypedValue(); 26397 if (attributes.getValue(com.android.internal.R.styleable.View_focusable, val)) { 26398 if (val.type == TypedValue.TYPE_INT_BOOLEAN) { 26399 return (val.data == 0 ? NOT_FOCUSABLE : FOCUSABLE); 26400 } else { 26401 return val.data; 26402 } 26403 } else { 26404 return FOCUSABLE_AUTO; 26405 } 26406 } 26407 26408 /** 26409 * @return The content view of the tooltip popup currently being shown, or null if the tooltip 26410 * is not showing. 26411 * @hide 26412 */ 26413 @TestApi 26414 public View getTooltipView() { 26415 if (mTooltipInfo == null || mTooltipInfo.mTooltipPopup == null) { 26416 return null; 26417 } 26418 return mTooltipInfo.mTooltipPopup.getContentView(); 26419 } 26420} 26421