View.java revision 1228e2cb8350ba202836660927c194f39e074e6f
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.os.Build; 65import android.os.Bundle; 66import android.os.Handler; 67import android.os.IBinder; 68import android.os.Parcel; 69import android.os.Parcelable; 70import android.os.RemoteException; 71import android.os.SystemClock; 72import android.os.SystemProperties; 73import android.os.Trace; 74import android.text.TextUtils; 75import android.util.AttributeSet; 76import android.util.FloatProperty; 77import android.util.LayoutDirection; 78import android.util.Log; 79import android.util.LongSparseLongArray; 80import android.util.Pools.SynchronizedPool; 81import android.util.Property; 82import android.util.SparseArray; 83import android.util.StateSet; 84import android.util.SuperNotCalledException; 85import android.util.TypedValue; 86import android.view.AccessibilityIterators.CharacterTextSegmentIterator; 87import android.view.AccessibilityIterators.ParagraphTextSegmentIterator; 88import android.view.AccessibilityIterators.TextSegmentIterator; 89import android.view.AccessibilityIterators.WordTextSegmentIterator; 90import android.view.ContextMenu.ContextMenuInfo; 91import android.view.accessibility.AccessibilityEvent; 92import android.view.accessibility.AccessibilityEventSource; 93import android.view.accessibility.AccessibilityManager; 94import android.view.accessibility.AccessibilityNodeInfo; 95import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction; 96import android.view.accessibility.AccessibilityNodeProvider; 97import android.view.animation.Animation; 98import android.view.animation.AnimationUtils; 99import android.view.animation.Transformation; 100import android.view.autofill.AutoFillManager; 101import android.view.autofill.AutoFillType; 102import android.view.autofill.AutoFillValue; 103import android.view.inputmethod.EditorInfo; 104import android.view.inputmethod.InputConnection; 105import android.view.inputmethod.InputMethodManager; 106import android.widget.Checkable; 107import android.widget.FrameLayout; 108import android.widget.ScrollBarDrawable; 109 110import com.android.internal.R; 111import com.android.internal.view.TooltipPopup; 112import com.android.internal.view.menu.MenuBuilder; 113import com.android.internal.widget.ScrollBarUtils; 114 115import com.google.android.collect.Lists; 116import com.google.android.collect.Maps; 117 118import java.lang.annotation.Retention; 119import java.lang.annotation.RetentionPolicy; 120import java.lang.ref.WeakReference; 121import java.lang.reflect.Field; 122import java.lang.reflect.InvocationTargetException; 123import java.lang.reflect.Method; 124import java.lang.reflect.Modifier; 125import java.util.ArrayList; 126import java.util.Arrays; 127import java.util.Collection; 128import java.util.Collections; 129import java.util.HashMap; 130import java.util.List; 131import java.util.Locale; 132import java.util.Map; 133import java.util.concurrent.CopyOnWriteArrayList; 134import java.util.concurrent.atomic.AtomicInteger; 135import java.util.function.Predicate; 136 137/** 138 * <p> 139 * This class represents the basic building block for user interface components. A View 140 * occupies a rectangular area on the screen and is responsible for drawing and 141 * event handling. View is the base class for <em>widgets</em>, which are 142 * used to create interactive UI components (buttons, text fields, etc.). The 143 * {@link android.view.ViewGroup} subclass is the base class for <em>layouts</em>, which 144 * are invisible containers that hold other Views (or other ViewGroups) and define 145 * their layout properties. 146 * </p> 147 * 148 * <div class="special reference"> 149 * <h3>Developer Guides</h3> 150 * <p>For information about using this class to develop your application's user interface, 151 * read the <a href="{@docRoot}guide/topics/ui/index.html">User Interface</a> developer guide. 152 * </div> 153 * 154 * <a name="Using"></a> 155 * <h3>Using Views</h3> 156 * <p> 157 * All of the views in a window are arranged in a single tree. You can add views 158 * either from code or by specifying a tree of views in one or more XML layout 159 * files. There are many specialized subclasses of views that act as controls or 160 * are capable of displaying text, images, or other content. 161 * </p> 162 * <p> 163 * Once you have created a tree of views, there are typically a few types of 164 * common operations you may wish to perform: 165 * <ul> 166 * <li><strong>Set properties:</strong> for example setting the text of a 167 * {@link android.widget.TextView}. The available properties and the methods 168 * that set them will vary among the different subclasses of views. Note that 169 * properties that are known at build time can be set in the XML layout 170 * files.</li> 171 * <li><strong>Set focus:</strong> The framework will handle moving focus in 172 * response to user input. To force focus to a specific view, call 173 * {@link #requestFocus}.</li> 174 * <li><strong>Set up listeners:</strong> Views allow clients to set listeners 175 * that will be notified when something interesting happens to the view. For 176 * example, all views will let you set a listener to be notified when the view 177 * gains or loses focus. You can register such a listener using 178 * {@link #setOnFocusChangeListener(android.view.View.OnFocusChangeListener)}. 179 * Other view subclasses offer more specialized listeners. For example, a Button 180 * exposes a listener to notify clients when the button is clicked.</li> 181 * <li><strong>Set visibility:</strong> You can hide or show views using 182 * {@link #setVisibility(int)}.</li> 183 * </ul> 184 * </p> 185 * <p><em> 186 * Note: The Android framework is responsible for measuring, laying out and 187 * drawing views. You should not call methods that perform these actions on 188 * views yourself unless you are actually implementing a 189 * {@link android.view.ViewGroup}. 190 * </em></p> 191 * 192 * <a name="Lifecycle"></a> 193 * <h3>Implementing a Custom View</h3> 194 * 195 * <p> 196 * To implement a custom view, you will usually begin by providing overrides for 197 * some of the standard methods that the framework calls on all views. You do 198 * not need to override all of these methods. In fact, you can start by just 199 * overriding {@link #onDraw(android.graphics.Canvas)}. 200 * <table border="2" width="85%" align="center" cellpadding="5"> 201 * <thead> 202 * <tr><th>Category</th> <th>Methods</th> <th>Description</th></tr> 203 * </thead> 204 * 205 * <tbody> 206 * <tr> 207 * <td rowspan="2">Creation</td> 208 * <td>Constructors</td> 209 * <td>There is a form of the constructor that are called when the view 210 * is created from code and a form that is called when the view is 211 * inflated from a layout file. The second form should parse and apply 212 * any attributes defined in the layout file. 213 * </td> 214 * </tr> 215 * <tr> 216 * <td><code>{@link #onFinishInflate()}</code></td> 217 * <td>Called after a view and all of its children has been inflated 218 * from XML.</td> 219 * </tr> 220 * 221 * <tr> 222 * <td rowspan="3">Layout</td> 223 * <td><code>{@link #onMeasure(int, int)}</code></td> 224 * <td>Called to determine the size requirements for this view and all 225 * of its children. 226 * </td> 227 * </tr> 228 * <tr> 229 * <td><code>{@link #onLayout(boolean, int, int, int, int)}</code></td> 230 * <td>Called when this view should assign a size and position to all 231 * of its children. 232 * </td> 233 * </tr> 234 * <tr> 235 * <td><code>{@link #onSizeChanged(int, int, int, int)}</code></td> 236 * <td>Called when the size of this view has changed. 237 * </td> 238 * </tr> 239 * 240 * <tr> 241 * <td>Drawing</td> 242 * <td><code>{@link #onDraw(android.graphics.Canvas)}</code></td> 243 * <td>Called when the view should render its content. 244 * </td> 245 * </tr> 246 * 247 * <tr> 248 * <td rowspan="4">Event processing</td> 249 * <td><code>{@link #onKeyDown(int, KeyEvent)}</code></td> 250 * <td>Called when a new hardware key event occurs. 251 * </td> 252 * </tr> 253 * <tr> 254 * <td><code>{@link #onKeyUp(int, KeyEvent)}</code></td> 255 * <td>Called when a hardware key up event occurs. 256 * </td> 257 * </tr> 258 * <tr> 259 * <td><code>{@link #onTrackballEvent(MotionEvent)}</code></td> 260 * <td>Called when a trackball motion event occurs. 261 * </td> 262 * </tr> 263 * <tr> 264 * <td><code>{@link #onTouchEvent(MotionEvent)}</code></td> 265 * <td>Called when a touch screen motion event occurs. 266 * </td> 267 * </tr> 268 * 269 * <tr> 270 * <td rowspan="2">Focus</td> 271 * <td><code>{@link #onFocusChanged(boolean, int, android.graphics.Rect)}</code></td> 272 * <td>Called when the view gains or loses focus. 273 * </td> 274 * </tr> 275 * 276 * <tr> 277 * <td><code>{@link #onWindowFocusChanged(boolean)}</code></td> 278 * <td>Called when the window containing the view gains or loses focus. 279 * </td> 280 * </tr> 281 * 282 * <tr> 283 * <td rowspan="3">Attaching</td> 284 * <td><code>{@link #onAttachedToWindow()}</code></td> 285 * <td>Called when the view is attached to a window. 286 * </td> 287 * </tr> 288 * 289 * <tr> 290 * <td><code>{@link #onDetachedFromWindow}</code></td> 291 * <td>Called when the view is detached from its window. 292 * </td> 293 * </tr> 294 * 295 * <tr> 296 * <td><code>{@link #onWindowVisibilityChanged(int)}</code></td> 297 * <td>Called when the visibility of the window containing the view 298 * has changed. 299 * </td> 300 * </tr> 301 * </tbody> 302 * 303 * </table> 304 * </p> 305 * 306 * <a name="IDs"></a> 307 * <h3>IDs</h3> 308 * Views may have an integer id associated with them. These ids are typically 309 * assigned in the layout XML files, and are used to find specific views within 310 * the view tree. A common pattern is to: 311 * <ul> 312 * <li>Define a Button in the layout file and assign it a unique ID. 313 * <pre> 314 * <Button 315 * android:id="@+id/my_button" 316 * android:layout_width="wrap_content" 317 * android:layout_height="wrap_content" 318 * android:text="@string/my_button_text"/> 319 * </pre></li> 320 * <li>From the onCreate method of an Activity, find the Button 321 * <pre class="prettyprint"> 322 * Button myButton = (Button) findViewById(R.id.my_button); 323 * </pre></li> 324 * </ul> 325 * <p> 326 * View IDs need not be unique throughout the tree, but it is good practice to 327 * ensure that they are at least unique within the part of the tree you are 328 * searching. 329 * </p> 330 * 331 * <a name="Position"></a> 332 * <h3>Position</h3> 333 * <p> 334 * The geometry of a view is that of a rectangle. A view has a location, 335 * expressed as a pair of <em>left</em> and <em>top</em> coordinates, and 336 * two dimensions, expressed as a width and a height. The unit for location 337 * and dimensions is the pixel. 338 * </p> 339 * 340 * <p> 341 * It is possible to retrieve the location of a view by invoking the methods 342 * {@link #getLeft()} and {@link #getTop()}. The former returns the left, or X, 343 * coordinate of the rectangle representing the view. The latter returns the 344 * top, or Y, coordinate of the rectangle representing the view. These methods 345 * both return the location of the view relative to its parent. For instance, 346 * when getLeft() returns 20, that means the view is located 20 pixels to the 347 * right of the left edge of its direct parent. 348 * </p> 349 * 350 * <p> 351 * In addition, several convenience methods are offered to avoid unnecessary 352 * computations, namely {@link #getRight()} and {@link #getBottom()}. 353 * These methods return the coordinates of the right and bottom edges of the 354 * rectangle representing the view. For instance, calling {@link #getRight()} 355 * is similar to the following computation: <code>getLeft() + getWidth()</code> 356 * (see <a href="#SizePaddingMargins">Size</a> for more information about the width.) 357 * </p> 358 * 359 * <a name="SizePaddingMargins"></a> 360 * <h3>Size, padding and margins</h3> 361 * <p> 362 * The size of a view is expressed with a width and a height. A view actually 363 * possess two pairs of width and height values. 364 * </p> 365 * 366 * <p> 367 * The first pair is known as <em>measured width</em> and 368 * <em>measured height</em>. These dimensions define how big a view wants to be 369 * within its parent (see <a href="#Layout">Layout</a> for more details.) The 370 * measured dimensions can be obtained by calling {@link #getMeasuredWidth()} 371 * and {@link #getMeasuredHeight()}. 372 * </p> 373 * 374 * <p> 375 * The second pair is simply known as <em>width</em> and <em>height</em>, or 376 * sometimes <em>drawing width</em> and <em>drawing height</em>. These 377 * dimensions define the actual size of the view on screen, at drawing time and 378 * after layout. These values may, but do not have to, be different from the 379 * measured width and height. The width and height can be obtained by calling 380 * {@link #getWidth()} and {@link #getHeight()}. 381 * </p> 382 * 383 * <p> 384 * To measure its dimensions, a view takes into account its padding. The padding 385 * is expressed in pixels for the left, top, right and bottom parts of the view. 386 * Padding can be used to offset the content of the view by a specific amount of 387 * pixels. For instance, a left padding of 2 will push the view's content by 388 * 2 pixels to the right of the left edge. Padding can be set using the 389 * {@link #setPadding(int, int, int, int)} or {@link #setPaddingRelative(int, int, int, int)} 390 * method and queried by calling {@link #getPaddingLeft()}, {@link #getPaddingTop()}, 391 * {@link #getPaddingRight()}, {@link #getPaddingBottom()}, {@link #getPaddingStart()}, 392 * {@link #getPaddingEnd()}. 393 * </p> 394 * 395 * <p> 396 * Even though a view can define a padding, it does not provide any support for 397 * margins. However, view groups provide such a support. Refer to 398 * {@link android.view.ViewGroup} and 399 * {@link android.view.ViewGroup.MarginLayoutParams} for further information. 400 * </p> 401 * 402 * <a name="Layout"></a> 403 * <h3>Layout</h3> 404 * <p> 405 * Layout is a two pass process: a measure pass and a layout pass. The measuring 406 * pass is implemented in {@link #measure(int, int)} and is a top-down traversal 407 * of the view tree. Each view pushes dimension specifications down the tree 408 * during the recursion. At the end of the measure pass, every view has stored 409 * its measurements. The second pass happens in 410 * {@link #layout(int,int,int,int)} and is also top-down. During 411 * this pass each parent is responsible for positioning all of its children 412 * using the sizes computed in the measure pass. 413 * </p> 414 * 415 * <p> 416 * When a view's measure() method returns, its {@link #getMeasuredWidth()} and 417 * {@link #getMeasuredHeight()} values must be set, along with those for all of 418 * that view's descendants. A view's measured width and measured height values 419 * must respect the constraints imposed by the view's parents. This guarantees 420 * that at the end of the measure pass, all parents accept all of their 421 * children's measurements. A parent view may call measure() more than once on 422 * its children. For example, the parent may measure each child once with 423 * unspecified dimensions to find out how big they want to be, then call 424 * measure() on them again with actual numbers if the sum of all the children's 425 * unconstrained sizes is too big or too small. 426 * </p> 427 * 428 * <p> 429 * The measure pass uses two classes to communicate dimensions. The 430 * {@link MeasureSpec} class is used by views to tell their parents how they 431 * want to be measured and positioned. The base LayoutParams class just 432 * describes how big the view wants to be for both width and height. For each 433 * dimension, it can specify one of: 434 * <ul> 435 * <li> an exact number 436 * <li>MATCH_PARENT, which means the view wants to be as big as its parent 437 * (minus padding) 438 * <li> WRAP_CONTENT, which means that the view wants to be just big enough to 439 * enclose its content (plus padding). 440 * </ul> 441 * There are subclasses of LayoutParams for different subclasses of ViewGroup. 442 * For example, AbsoluteLayout has its own subclass of LayoutParams which adds 443 * an X and Y value. 444 * </p> 445 * 446 * <p> 447 * MeasureSpecs are used to push requirements down the tree from parent to 448 * child. A MeasureSpec can be in one of three modes: 449 * <ul> 450 * <li>UNSPECIFIED: This is used by a parent to determine the desired dimension 451 * of a child view. For example, a LinearLayout may call measure() on its child 452 * with the height set to UNSPECIFIED and a width of EXACTLY 240 to find out how 453 * tall the child view wants to be given a width of 240 pixels. 454 * <li>EXACTLY: This is used by the parent to impose an exact size on the 455 * child. The child must use this size, and guarantee that all of its 456 * descendants will fit within this size. 457 * <li>AT_MOST: This is used by the parent to impose a maximum size on the 458 * child. The child must guarantee that it and all of its descendants will fit 459 * within this size. 460 * </ul> 461 * </p> 462 * 463 * <p> 464 * To initiate a layout, call {@link #requestLayout}. This method is typically 465 * called by a view on itself when it believes that is can no longer fit within 466 * its current bounds. 467 * </p> 468 * 469 * <a name="Drawing"></a> 470 * <h3>Drawing</h3> 471 * <p> 472 * Drawing is handled by walking the tree and recording the drawing commands of 473 * any View that needs to update. After this, the drawing commands of the 474 * entire tree are issued to screen, clipped to the newly damaged area. 475 * </p> 476 * 477 * <p> 478 * The tree is largely recorded and drawn in order, with parents drawn before 479 * (i.e., behind) their children, with siblings drawn in the order they appear 480 * in the tree. If you set a background drawable for a View, then the View will 481 * draw it before calling back to its <code>onDraw()</code> method. The child 482 * drawing order can be overridden with 483 * {@link ViewGroup#setChildrenDrawingOrderEnabled(boolean) custom child drawing order} 484 * in a ViewGroup, and with {@link #setZ(float)} custom Z values} set on Views. 485 * </p> 486 * 487 * <p> 488 * To force a view to draw, call {@link #invalidate()}. 489 * </p> 490 * 491 * <a name="EventHandlingThreading"></a> 492 * <h3>Event Handling and Threading</h3> 493 * <p> 494 * The basic cycle of a view is as follows: 495 * <ol> 496 * <li>An event comes in and is dispatched to the appropriate view. The view 497 * handles the event and notifies any listeners.</li> 498 * <li>If in the course of processing the event, the view's bounds may need 499 * to be changed, the view will call {@link #requestLayout()}.</li> 500 * <li>Similarly, if in the course of processing the event the view's appearance 501 * may need to be changed, the view will call {@link #invalidate()}.</li> 502 * <li>If either {@link #requestLayout()} or {@link #invalidate()} were called, 503 * the framework will take care of measuring, laying out, and drawing the tree 504 * as appropriate.</li> 505 * </ol> 506 * </p> 507 * 508 * <p><em>Note: The entire view tree is single threaded. You must always be on 509 * the UI thread when calling any method on any view.</em> 510 * If you are doing work on other threads and want to update the state of a view 511 * from that thread, you should use a {@link Handler}. 512 * </p> 513 * 514 * <a name="FocusHandling"></a> 515 * <h3>Focus Handling</h3> 516 * <p> 517 * The framework will handle routine focus movement in response to user input. 518 * This includes changing the focus as views are removed or hidden, or as new 519 * views become available. Views indicate their willingness to take focus 520 * through the {@link #isFocusable} method. To change whether a view can take 521 * focus, call {@link #setFocusable(boolean)}. When in touch mode (see notes below) 522 * views indicate whether they still would like focus via {@link #isFocusableInTouchMode} 523 * and can change this via {@link #setFocusableInTouchMode(boolean)}. 524 * </p> 525 * <p> 526 * Focus movement is based on an algorithm which finds the nearest neighbor in a 527 * given direction. In rare cases, the default algorithm may not match the 528 * intended behavior of the developer. In these situations, you can provide 529 * explicit overrides by using these XML attributes in the layout file: 530 * <pre> 531 * nextFocusDown 532 * nextFocusLeft 533 * nextFocusRight 534 * nextFocusUp 535 * </pre> 536 * </p> 537 * 538 * 539 * <p> 540 * To get a particular view to take focus, call {@link #requestFocus()}. 541 * </p> 542 * 543 * <a name="TouchMode"></a> 544 * <h3>Touch Mode</h3> 545 * <p> 546 * When a user is navigating a user interface via directional keys such as a D-pad, it is 547 * necessary to give focus to actionable items such as buttons so the user can see 548 * what will take input. If the device has touch capabilities, however, and the user 549 * begins interacting with the interface by touching it, it is no longer necessary to 550 * always highlight, or give focus to, a particular view. This motivates a mode 551 * for interaction named 'touch mode'. 552 * </p> 553 * <p> 554 * For a touch capable device, once the user touches the screen, the device 555 * will enter touch mode. From this point onward, only views for which 556 * {@link #isFocusableInTouchMode} is true will be focusable, such as text editing widgets. 557 * Other views that are touchable, like buttons, will not take focus when touched; they will 558 * only fire the on click listeners. 559 * </p> 560 * <p> 561 * Any time a user hits a directional key, such as a D-pad direction, the view device will 562 * exit touch mode, and find a view to take focus, so that the user may resume interacting 563 * with the user interface without touching the screen again. 564 * </p> 565 * <p> 566 * The touch mode state is maintained across {@link android.app.Activity}s. Call 567 * {@link #isInTouchMode} to see whether the device is currently in touch mode. 568 * </p> 569 * 570 * <a name="Scrolling"></a> 571 * <h3>Scrolling</h3> 572 * <p> 573 * The framework provides basic support for views that wish to internally 574 * scroll their content. This includes keeping track of the X and Y scroll 575 * offset as well as mechanisms for drawing scrollbars. See 576 * {@link #scrollBy(int, int)}, {@link #scrollTo(int, int)}, and 577 * {@link #awakenScrollBars()} for more details. 578 * </p> 579 * 580 * <a name="Tags"></a> 581 * <h3>Tags</h3> 582 * <p> 583 * Unlike IDs, tags are not used to identify views. Tags are essentially an 584 * extra piece of information that can be associated with a view. They are most 585 * often used as a convenience to store data related to views in the views 586 * themselves rather than by putting them in a separate structure. 587 * </p> 588 * <p> 589 * Tags may be specified with character sequence values in layout XML as either 590 * a single tag using the {@link android.R.styleable#View_tag android:tag} 591 * attribute or multiple tags using the {@code <tag>} child element: 592 * <pre> 593 * <View ... 594 * android:tag="@string/mytag_value" /> 595 * <View ...> 596 * <tag android:id="@+id/mytag" 597 * android:value="@string/mytag_value" /> 598 * </View> 599 * </pre> 600 * </p> 601 * <p> 602 * Tags may also be specified with arbitrary objects from code using 603 * {@link #setTag(Object)} or {@link #setTag(int, Object)}. 604 * </p> 605 * 606 * <a name="Themes"></a> 607 * <h3>Themes</h3> 608 * <p> 609 * By default, Views are created using the theme of the Context object supplied 610 * to their constructor; however, a different theme may be specified by using 611 * the {@link android.R.styleable#View_theme android:theme} attribute in layout 612 * XML or by passing a {@link ContextThemeWrapper} to the constructor from 613 * code. 614 * </p> 615 * <p> 616 * When the {@link android.R.styleable#View_theme android:theme} attribute is 617 * used in XML, the specified theme is applied on top of the inflation 618 * context's theme (see {@link LayoutInflater}) and used for the view itself as 619 * well as any child elements. 620 * </p> 621 * <p> 622 * In the following example, both views will be created using the Material dark 623 * color scheme; however, because an overlay theme is used which only defines a 624 * subset of attributes, the value of 625 * {@link android.R.styleable#Theme_colorAccent android:colorAccent} defined on 626 * the inflation context's theme (e.g. the Activity theme) will be preserved. 627 * <pre> 628 * <LinearLayout 629 * ... 630 * android:theme="@android:theme/ThemeOverlay.Material.Dark"> 631 * <View ...> 632 * </LinearLayout> 633 * </pre> 634 * </p> 635 * 636 * <a name="Properties"></a> 637 * <h3>Properties</h3> 638 * <p> 639 * The View class exposes an {@link #ALPHA} property, as well as several transform-related 640 * properties, such as {@link #TRANSLATION_X} and {@link #TRANSLATION_Y}. These properties are 641 * available both in the {@link Property} form as well as in similarly-named setter/getter 642 * methods (such as {@link #setAlpha(float)} for {@link #ALPHA}). These properties can 643 * be used to set persistent state associated with these rendering-related properties on the view. 644 * The properties and methods can also be used in conjunction with 645 * {@link android.animation.Animator Animator}-based animations, described more in the 646 * <a href="#Animation">Animation</a> section. 647 * </p> 648 * 649 * <a name="Animation"></a> 650 * <h3>Animation</h3> 651 * <p> 652 * Starting with Android 3.0, the preferred way of animating views is to use the 653 * {@link android.animation} package APIs. These {@link android.animation.Animator Animator}-based 654 * classes change actual properties of the View object, such as {@link #setAlpha(float) alpha} and 655 * {@link #setTranslationX(float) translationX}. This behavior is contrasted to that of the pre-3.0 656 * {@link android.view.animation.Animation Animation}-based classes, which instead animate only 657 * how the view is drawn on the display. In particular, the {@link ViewPropertyAnimator} class 658 * makes animating these View properties particularly easy and efficient. 659 * </p> 660 * <p> 661 * Alternatively, you can use the pre-3.0 animation classes to animate how Views are rendered. 662 * You can attach an {@link Animation} object to a view using 663 * {@link #setAnimation(Animation)} or 664 * {@link #startAnimation(Animation)}. The animation can alter the scale, 665 * rotation, translation and alpha of a view over time. If the animation is 666 * attached to a view that has children, the animation will affect the entire 667 * subtree rooted by that node. When an animation is started, the framework will 668 * take care of redrawing the appropriate views until the animation completes. 669 * </p> 670 * 671 * <a name="Security"></a> 672 * <h3>Security</h3> 673 * <p> 674 * Sometimes it is essential that an application be able to verify that an action 675 * is being performed with the full knowledge and consent of the user, such as 676 * granting a permission request, making a purchase or clicking on an advertisement. 677 * Unfortunately, a malicious application could try to spoof the user into 678 * performing these actions, unaware, by concealing the intended purpose of the view. 679 * As a remedy, the framework offers a touch filtering mechanism that can be used to 680 * improve the security of views that provide access to sensitive functionality. 681 * </p><p> 682 * To enable touch filtering, call {@link #setFilterTouchesWhenObscured(boolean)} or set the 683 * android:filterTouchesWhenObscured layout attribute to true. When enabled, the framework 684 * will discard touches that are received whenever the view's window is obscured by 685 * another visible window. As a result, the view will not receive touches whenever a 686 * toast, dialog or other window appears above the view's window. 687 * </p><p> 688 * For more fine-grained control over security, consider overriding the 689 * {@link #onFilterTouchEventForSecurity(MotionEvent)} method to implement your own 690 * security policy. See also {@link MotionEvent#FLAG_WINDOW_IS_OBSCURED}. 691 * </p> 692 * 693 * @attr ref android.R.styleable#View_alpha 694 * @attr ref android.R.styleable#View_background 695 * @attr ref android.R.styleable#View_clickable 696 * @attr ref android.R.styleable#View_contentDescription 697 * @attr ref android.R.styleable#View_drawingCacheQuality 698 * @attr ref android.R.styleable#View_duplicateParentState 699 * @attr ref android.R.styleable#View_id 700 * @attr ref android.R.styleable#View_requiresFadingEdge 701 * @attr ref android.R.styleable#View_fadeScrollbars 702 * @attr ref android.R.styleable#View_fadingEdgeLength 703 * @attr ref android.R.styleable#View_filterTouchesWhenObscured 704 * @attr ref android.R.styleable#View_fitsSystemWindows 705 * @attr ref android.R.styleable#View_isScrollContainer 706 * @attr ref android.R.styleable#View_focusable 707 * @attr ref android.R.styleable#View_focusableInTouchMode 708 * @attr ref android.R.styleable#View_hapticFeedbackEnabled 709 * @attr ref android.R.styleable#View_keepScreenOn 710 * @attr ref android.R.styleable#View_layerType 711 * @attr ref android.R.styleable#View_layoutDirection 712 * @attr ref android.R.styleable#View_longClickable 713 * @attr ref android.R.styleable#View_minHeight 714 * @attr ref android.R.styleable#View_minWidth 715 * @attr ref android.R.styleable#View_nextFocusDown 716 * @attr ref android.R.styleable#View_nextFocusLeft 717 * @attr ref android.R.styleable#View_nextFocusRight 718 * @attr ref android.R.styleable#View_nextFocusUp 719 * @attr ref android.R.styleable#View_onClick 720 * @attr ref android.R.styleable#View_padding 721 * @attr ref android.R.styleable#View_paddingBottom 722 * @attr ref android.R.styleable#View_paddingLeft 723 * @attr ref android.R.styleable#View_paddingRight 724 * @attr ref android.R.styleable#View_paddingTop 725 * @attr ref android.R.styleable#View_paddingStart 726 * @attr ref android.R.styleable#View_paddingEnd 727 * @attr ref android.R.styleable#View_saveEnabled 728 * @attr ref android.R.styleable#View_rotation 729 * @attr ref android.R.styleable#View_rotationX 730 * @attr ref android.R.styleable#View_rotationY 731 * @attr ref android.R.styleable#View_scaleX 732 * @attr ref android.R.styleable#View_scaleY 733 * @attr ref android.R.styleable#View_scrollX 734 * @attr ref android.R.styleable#View_scrollY 735 * @attr ref android.R.styleable#View_scrollbarSize 736 * @attr ref android.R.styleable#View_scrollbarStyle 737 * @attr ref android.R.styleable#View_scrollbars 738 * @attr ref android.R.styleable#View_scrollbarDefaultDelayBeforeFade 739 * @attr ref android.R.styleable#View_scrollbarFadeDuration 740 * @attr ref android.R.styleable#View_scrollbarTrackHorizontal 741 * @attr ref android.R.styleable#View_scrollbarThumbHorizontal 742 * @attr ref android.R.styleable#View_scrollbarThumbVertical 743 * @attr ref android.R.styleable#View_scrollbarTrackVertical 744 * @attr ref android.R.styleable#View_scrollbarAlwaysDrawHorizontalTrack 745 * @attr ref android.R.styleable#View_scrollbarAlwaysDrawVerticalTrack 746 * @attr ref android.R.styleable#View_stateListAnimator 747 * @attr ref android.R.styleable#View_transitionName 748 * @attr ref android.R.styleable#View_soundEffectsEnabled 749 * @attr ref android.R.styleable#View_tag 750 * @attr ref android.R.styleable#View_textAlignment 751 * @attr ref android.R.styleable#View_textDirection 752 * @attr ref android.R.styleable#View_transformPivotX 753 * @attr ref android.R.styleable#View_transformPivotY 754 * @attr ref android.R.styleable#View_translationX 755 * @attr ref android.R.styleable#View_translationY 756 * @attr ref android.R.styleable#View_translationZ 757 * @attr ref android.R.styleable#View_visibility 758 * @attr ref android.R.styleable#View_theme 759 * 760 * @see android.view.ViewGroup 761 */ 762@UiThread 763public class View implements Drawable.Callback, KeyEvent.Callback, 764 AccessibilityEventSource { 765 private static final boolean DBG = false; 766 767 /** @hide */ 768 public static boolean DEBUG_DRAW = false; 769 770 /** 771 * The logging tag used by this class with android.util.Log. 772 */ 773 protected static final String VIEW_LOG_TAG = "View"; 774 775 /** 776 * When set to true, apps will draw debugging information about their layouts. 777 * 778 * @hide 779 */ 780 public static final String DEBUG_LAYOUT_PROPERTY = "debug.layout"; 781 782 /** 783 * When set to true, this view will save its attribute data. 784 * 785 * @hide 786 */ 787 public static boolean mDebugViewAttributes = false; 788 789 /** 790 * Used to mark a View that has no ID. 791 */ 792 public static final int NO_ID = -1; 793 794 /** 795 * Signals that compatibility booleans have been initialized according to 796 * target SDK versions. 797 */ 798 private static boolean sCompatibilityDone = false; 799 800 /** 801 * Use the old (broken) way of building MeasureSpecs. 802 */ 803 private static boolean sUseBrokenMakeMeasureSpec = false; 804 805 /** 806 * Always return a size of 0 for MeasureSpec values with a mode of UNSPECIFIED 807 */ 808 static boolean sUseZeroUnspecifiedMeasureSpec = false; 809 810 /** 811 * Ignore any optimizations using the measure cache. 812 */ 813 private static boolean sIgnoreMeasureCache = false; 814 815 /** 816 * Ignore an optimization that skips unnecessary EXACTLY layout passes. 817 */ 818 private static boolean sAlwaysRemeasureExactly = false; 819 820 /** 821 * Relax constraints around whether setLayoutParams() must be called after 822 * modifying the layout params. 823 */ 824 private static boolean sLayoutParamsAlwaysChanged = false; 825 826 /** 827 * Allow setForeground/setBackground to be called (and ignored) on a textureview, 828 * without throwing 829 */ 830 static boolean sTextureViewIgnoresDrawableSetters = false; 831 832 /** 833 * Prior to N, some ViewGroups would not convert LayoutParams properly even though both extend 834 * MarginLayoutParams. For instance, converting LinearLayout.LayoutParams to 835 * RelativeLayout.LayoutParams would lose margin information. This is fixed on N but target API 836 * check is implemented for backwards compatibility. 837 * 838 * {@hide} 839 */ 840 protected static boolean sPreserveMarginParamsInLayoutParamConversion; 841 842 /** 843 * Prior to N, when drag enters into child of a view that has already received an 844 * ACTION_DRAG_ENTERED event, the parent doesn't get a ACTION_DRAG_EXITED event. 845 * ACTION_DRAG_LOCATION and ACTION_DROP were delivered to the parent of a view that returned 846 * false from its event handler for these events. 847 * Starting from N, the parent will get ACTION_DRAG_EXITED event before the child gets its 848 * ACTION_DRAG_ENTERED. ACTION_DRAG_LOCATION and ACTION_DROP are never propagated to the parent. 849 * sCascadedDragDrop is true for pre-N apps for backwards compatibility implementation. 850 */ 851 static boolean sCascadedDragDrop; 852 853 /** 854 * Prior to O, auto-focusable didn't exist and widgets such as ListView use hasFocusable 855 * to determine things like whether or not to permit item click events. We can't break 856 * apps that do this just because more things (clickable things) are now auto-focusable 857 * and they would get different results, so give old behavior to old apps. 858 */ 859 static boolean sHasFocusableExcludeAutoFocusable; 860 861 /** 862 * Prior to O, auto-focusable didn't exist and views marked as clickable weren't implicitly 863 * made focusable by default. As a result, apps could (incorrectly) change the clickable 864 * setting of views off the UI thread. Now that clickable can effect the focusable state, 865 * changing the clickable attribute off the UI thread will cause an exception (since changing 866 * the focusable state checks). In order to prevent apps from crashing, we will handle this 867 * specific case and just not notify parents on new focusables resulting from marking views 868 * clickable from outside the UI thread. 869 */ 870 private static boolean sAutoFocusableOffUIThreadWontNotifyParents; 871 872 /** @hide */ 873 @IntDef({NOT_FOCUSABLE, FOCUSABLE, FOCUSABLE_AUTO}) 874 @Retention(RetentionPolicy.SOURCE) 875 public @interface Focusable {} 876 877 /** 878 * This view does not want keystrokes. 879 * <p> 880 * Use with {@link #setFocusable(int)} and <a href="#attr_android:focusable">{@code 881 * android:focusable}. 882 */ 883 public static final int NOT_FOCUSABLE = 0x00000000; 884 885 /** 886 * This view wants keystrokes. 887 * <p> 888 * Use with {@link #setFocusable(int)} and <a href="#attr_android:focusable">{@code 889 * android:focusable}. 890 */ 891 public static final int FOCUSABLE = 0x00000001; 892 893 /** 894 * This view determines focusability automatically. This is the default. 895 * <p> 896 * Use with {@link #setFocusable(int)} and <a href="#attr_android:focusable">{@code 897 * android:focusable}. 898 */ 899 public static final int FOCUSABLE_AUTO = 0x00000010; 900 901 /** 902 * Mask for use with setFlags indicating bits used for focus. 903 */ 904 private static final int FOCUSABLE_MASK = 0x00000011; 905 906 /** 907 * This view will adjust its padding to fit sytem windows (e.g. status bar) 908 */ 909 private static final int FITS_SYSTEM_WINDOWS = 0x00000002; 910 911 /** @hide */ 912 @IntDef({VISIBLE, INVISIBLE, GONE}) 913 @Retention(RetentionPolicy.SOURCE) 914 public @interface Visibility {} 915 916 /** 917 * This view is visible. 918 * Use with {@link #setVisibility} and <a href="#attr_android:visibility">{@code 919 * android:visibility}. 920 */ 921 public static final int VISIBLE = 0x00000000; 922 923 /** 924 * This view is invisible, but it still takes up space for layout purposes. 925 * Use with {@link #setVisibility} and <a href="#attr_android:visibility">{@code 926 * android:visibility}. 927 */ 928 public static final int INVISIBLE = 0x00000004; 929 930 /** 931 * This view is invisible, and it doesn't take any space for layout 932 * purposes. Use with {@link #setVisibility} and <a href="#attr_android:visibility">{@code 933 * android:visibility}. 934 */ 935 public static final int GONE = 0x00000008; 936 937 /** 938 * Mask for use with setFlags indicating bits used for visibility. 939 * {@hide} 940 */ 941 static final int VISIBILITY_MASK = 0x0000000C; 942 943 private static final int[] VISIBILITY_FLAGS = {VISIBLE, INVISIBLE, GONE}; 944 945 /** 946 * This view is enabled. Interpretation varies by subclass. 947 * Use with ENABLED_MASK when calling setFlags. 948 * {@hide} 949 */ 950 static final int ENABLED = 0x00000000; 951 952 /** 953 * This view is disabled. Interpretation varies by subclass. 954 * Use with ENABLED_MASK when calling setFlags. 955 * {@hide} 956 */ 957 static final int DISABLED = 0x00000020; 958 959 /** 960 * Mask for use with setFlags indicating bits used for indicating whether 961 * this view is enabled 962 * {@hide} 963 */ 964 static final int ENABLED_MASK = 0x00000020; 965 966 /** 967 * This view won't draw. {@link #onDraw(android.graphics.Canvas)} won't be 968 * called and further optimizations will be performed. It is okay to have 969 * this flag set and a background. Use with DRAW_MASK when calling setFlags. 970 * {@hide} 971 */ 972 static final int WILL_NOT_DRAW = 0x00000080; 973 974 /** 975 * Mask for use with setFlags indicating bits used for indicating whether 976 * this view is will draw 977 * {@hide} 978 */ 979 static final int DRAW_MASK = 0x00000080; 980 981 /** 982 * <p>This view doesn't show scrollbars.</p> 983 * {@hide} 984 */ 985 static final int SCROLLBARS_NONE = 0x00000000; 986 987 /** 988 * <p>This view shows horizontal scrollbars.</p> 989 * {@hide} 990 */ 991 static final int SCROLLBARS_HORIZONTAL = 0x00000100; 992 993 /** 994 * <p>This view shows vertical scrollbars.</p> 995 * {@hide} 996 */ 997 static final int SCROLLBARS_VERTICAL = 0x00000200; 998 999 /** 1000 * <p>Mask for use with setFlags indicating bits used for indicating which 1001 * scrollbars are enabled.</p> 1002 * {@hide} 1003 */ 1004 static final int SCROLLBARS_MASK = 0x00000300; 1005 1006 /** 1007 * Indicates that the view should filter touches when its window is obscured. 1008 * Refer to the class comments for more information about this security feature. 1009 * {@hide} 1010 */ 1011 static final int FILTER_TOUCHES_WHEN_OBSCURED = 0x00000400; 1012 1013 /** 1014 * Set for framework elements that use FITS_SYSTEM_WINDOWS, to indicate 1015 * that they are optional and should be skipped if the window has 1016 * requested system UI flags that ignore those insets for layout. 1017 */ 1018 static final int OPTIONAL_FITS_SYSTEM_WINDOWS = 0x00000800; 1019 1020 /** 1021 * <p>This view doesn't show fading edges.</p> 1022 * {@hide} 1023 */ 1024 static final int FADING_EDGE_NONE = 0x00000000; 1025 1026 /** 1027 * <p>This view shows horizontal fading edges.</p> 1028 * {@hide} 1029 */ 1030 static final int FADING_EDGE_HORIZONTAL = 0x00001000; 1031 1032 /** 1033 * <p>This view shows vertical fading edges.</p> 1034 * {@hide} 1035 */ 1036 static final int FADING_EDGE_VERTICAL = 0x00002000; 1037 1038 /** 1039 * <p>Mask for use with setFlags indicating bits used for indicating which 1040 * fading edges are enabled.</p> 1041 * {@hide} 1042 */ 1043 static final int FADING_EDGE_MASK = 0x00003000; 1044 1045 /** 1046 * <p>Indicates this view can be clicked. When clickable, a View reacts 1047 * to clicks by notifying the OnClickListener.<p> 1048 * {@hide} 1049 */ 1050 static final int CLICKABLE = 0x00004000; 1051 1052 /** 1053 * <p>Indicates this view is caching its drawing into a bitmap.</p> 1054 * {@hide} 1055 */ 1056 static final int DRAWING_CACHE_ENABLED = 0x00008000; 1057 1058 /** 1059 * <p>Indicates that no icicle should be saved for this view.<p> 1060 * {@hide} 1061 */ 1062 static final int SAVE_DISABLED = 0x000010000; 1063 1064 /** 1065 * <p>Mask for use with setFlags indicating bits used for the saveEnabled 1066 * property.</p> 1067 * {@hide} 1068 */ 1069 static final int SAVE_DISABLED_MASK = 0x000010000; 1070 1071 /** 1072 * <p>Indicates that no drawing cache should ever be created for this view.<p> 1073 * {@hide} 1074 */ 1075 static final int WILL_NOT_CACHE_DRAWING = 0x000020000; 1076 1077 /** 1078 * <p>Indicates this view can take / keep focus when int touch mode.</p> 1079 * {@hide} 1080 */ 1081 static final int FOCUSABLE_IN_TOUCH_MODE = 0x00040000; 1082 1083 /** @hide */ 1084 @Retention(RetentionPolicy.SOURCE) 1085 @IntDef({DRAWING_CACHE_QUALITY_LOW, DRAWING_CACHE_QUALITY_HIGH, DRAWING_CACHE_QUALITY_AUTO}) 1086 public @interface DrawingCacheQuality {} 1087 1088 /** 1089 * <p>Enables low quality mode for the drawing cache.</p> 1090 */ 1091 public static final int DRAWING_CACHE_QUALITY_LOW = 0x00080000; 1092 1093 /** 1094 * <p>Enables high quality mode for the drawing cache.</p> 1095 */ 1096 public static final int DRAWING_CACHE_QUALITY_HIGH = 0x00100000; 1097 1098 /** 1099 * <p>Enables automatic quality mode for the drawing cache.</p> 1100 */ 1101 public static final int DRAWING_CACHE_QUALITY_AUTO = 0x00000000; 1102 1103 private static final int[] DRAWING_CACHE_QUALITY_FLAGS = { 1104 DRAWING_CACHE_QUALITY_AUTO, DRAWING_CACHE_QUALITY_LOW, DRAWING_CACHE_QUALITY_HIGH 1105 }; 1106 1107 /** 1108 * <p>Mask for use with setFlags indicating bits used for the cache 1109 * quality property.</p> 1110 * {@hide} 1111 */ 1112 static final int DRAWING_CACHE_QUALITY_MASK = 0x00180000; 1113 1114 /** 1115 * <p> 1116 * Indicates this view can be long clicked. When long clickable, a View 1117 * reacts to long clicks by notifying the OnLongClickListener or showing a 1118 * context menu. 1119 * </p> 1120 * {@hide} 1121 */ 1122 static final int LONG_CLICKABLE = 0x00200000; 1123 1124 /** 1125 * <p>Indicates that this view gets its drawable states from its direct parent 1126 * and ignores its original internal states.</p> 1127 * 1128 * @hide 1129 */ 1130 static final int DUPLICATE_PARENT_STATE = 0x00400000; 1131 1132 /** 1133 * <p> 1134 * Indicates this view can be context clicked. When context clickable, a View reacts to a 1135 * context click (e.g. a primary stylus button press or right mouse click) by notifying the 1136 * OnContextClickListener. 1137 * </p> 1138 * {@hide} 1139 */ 1140 static final int CONTEXT_CLICKABLE = 0x00800000; 1141 1142 1143 /** @hide */ 1144 @IntDef({ 1145 SCROLLBARS_INSIDE_OVERLAY, 1146 SCROLLBARS_INSIDE_INSET, 1147 SCROLLBARS_OUTSIDE_OVERLAY, 1148 SCROLLBARS_OUTSIDE_INSET 1149 }) 1150 @Retention(RetentionPolicy.SOURCE) 1151 public @interface ScrollBarStyle {} 1152 1153 /** 1154 * The scrollbar style to display the scrollbars inside the content area, 1155 * without increasing the padding. The scrollbars will be overlaid with 1156 * translucency on the view's content. 1157 */ 1158 public static final int SCROLLBARS_INSIDE_OVERLAY = 0; 1159 1160 /** 1161 * The scrollbar style to display the scrollbars inside the padded area, 1162 * increasing the padding of the view. The scrollbars will not overlap the 1163 * content area of the view. 1164 */ 1165 public static final int SCROLLBARS_INSIDE_INSET = 0x01000000; 1166 1167 /** 1168 * The scrollbar style to display the scrollbars at the edge of the view, 1169 * without increasing the padding. The scrollbars will be overlaid with 1170 * translucency. 1171 */ 1172 public static final int SCROLLBARS_OUTSIDE_OVERLAY = 0x02000000; 1173 1174 /** 1175 * The scrollbar style to display the scrollbars at the edge of the view, 1176 * increasing the padding of the view. The scrollbars will only overlap the 1177 * background, if any. 1178 */ 1179 public static final int SCROLLBARS_OUTSIDE_INSET = 0x03000000; 1180 1181 /** 1182 * Mask to check if the scrollbar style is overlay or inset. 1183 * {@hide} 1184 */ 1185 static final int SCROLLBARS_INSET_MASK = 0x01000000; 1186 1187 /** 1188 * Mask to check if the scrollbar style is inside or outside. 1189 * {@hide} 1190 */ 1191 static final int SCROLLBARS_OUTSIDE_MASK = 0x02000000; 1192 1193 /** 1194 * Mask for scrollbar style. 1195 * {@hide} 1196 */ 1197 static final int SCROLLBARS_STYLE_MASK = 0x03000000; 1198 1199 /** 1200 * View flag indicating that the screen should remain on while the 1201 * window containing this view is visible to the user. This effectively 1202 * takes care of automatically setting the WindowManager's 1203 * {@link WindowManager.LayoutParams#FLAG_KEEP_SCREEN_ON}. 1204 */ 1205 public static final int KEEP_SCREEN_ON = 0x04000000; 1206 1207 /** 1208 * View flag indicating whether this view should have sound effects enabled 1209 * for events such as clicking and touching. 1210 */ 1211 public static final int SOUND_EFFECTS_ENABLED = 0x08000000; 1212 1213 /** 1214 * View flag indicating whether this view should have haptic feedback 1215 * enabled for events such as long presses. 1216 */ 1217 public static final int HAPTIC_FEEDBACK_ENABLED = 0x10000000; 1218 1219 /** 1220 * <p>Indicates that the view hierarchy should stop saving state when 1221 * it reaches this view. If state saving is initiated immediately at 1222 * the view, it will be allowed. 1223 * {@hide} 1224 */ 1225 static final int PARENT_SAVE_DISABLED = 0x20000000; 1226 1227 /** 1228 * <p>Mask for use with setFlags indicating bits used for PARENT_SAVE_DISABLED.</p> 1229 * {@hide} 1230 */ 1231 static final int PARENT_SAVE_DISABLED_MASK = 0x20000000; 1232 1233 private static Paint sDebugPaint; 1234 1235 /** 1236 * <p>Indicates this view can display a tooltip on hover or long press.</p> 1237 * {@hide} 1238 */ 1239 static final int TOOLTIP = 0x40000000; 1240 1241 /** @hide */ 1242 @IntDef(flag = true, 1243 value = { 1244 FOCUSABLES_ALL, 1245 FOCUSABLES_TOUCH_MODE 1246 }) 1247 @Retention(RetentionPolicy.SOURCE) 1248 public @interface FocusableMode {} 1249 1250 /** 1251 * View flag indicating whether {@link #addFocusables(ArrayList, int, int)} 1252 * should add all focusable Views regardless if they are focusable in touch mode. 1253 */ 1254 public static final int FOCUSABLES_ALL = 0x00000000; 1255 1256 /** 1257 * View flag indicating whether {@link #addFocusables(ArrayList, int, int)} 1258 * should add only Views focusable in touch mode. 1259 */ 1260 public static final int FOCUSABLES_TOUCH_MODE = 0x00000001; 1261 1262 /** @hide */ 1263 @IntDef({ 1264 FOCUS_BACKWARD, 1265 FOCUS_FORWARD, 1266 FOCUS_LEFT, 1267 FOCUS_UP, 1268 FOCUS_RIGHT, 1269 FOCUS_DOWN 1270 }) 1271 @Retention(RetentionPolicy.SOURCE) 1272 public @interface FocusDirection {} 1273 1274 /** @hide */ 1275 @IntDef({ 1276 FOCUS_LEFT, 1277 FOCUS_UP, 1278 FOCUS_RIGHT, 1279 FOCUS_DOWN 1280 }) 1281 @Retention(RetentionPolicy.SOURCE) 1282 public @interface FocusRealDirection {} // Like @FocusDirection, but without forward/backward 1283 1284 /** 1285 * Use with {@link #focusSearch(int)}. Move focus to the previous selectable 1286 * item. 1287 */ 1288 public static final int FOCUS_BACKWARD = 0x00000001; 1289 1290 /** 1291 * Use with {@link #focusSearch(int)}. Move focus to the next selectable 1292 * item. 1293 */ 1294 public static final int FOCUS_FORWARD = 0x00000002; 1295 1296 /** 1297 * Use with {@link #focusSearch(int)}. Move focus to the left. 1298 */ 1299 public static final int FOCUS_LEFT = 0x00000011; 1300 1301 /** 1302 * Use with {@link #focusSearch(int)}. Move focus up. 1303 */ 1304 public static final int FOCUS_UP = 0x00000021; 1305 1306 /** 1307 * Use with {@link #focusSearch(int)}. Move focus to the right. 1308 */ 1309 public static final int FOCUS_RIGHT = 0x00000042; 1310 1311 /** 1312 * Use with {@link #focusSearch(int)}. Move focus down. 1313 */ 1314 public static final int FOCUS_DOWN = 0x00000082; 1315 1316 /** 1317 * Bits of {@link #getMeasuredWidthAndState()} and 1318 * {@link #getMeasuredWidthAndState()} that provide the actual measured size. 1319 */ 1320 public static final int MEASURED_SIZE_MASK = 0x00ffffff; 1321 1322 /** 1323 * Bits of {@link #getMeasuredWidthAndState()} and 1324 * {@link #getMeasuredWidthAndState()} that provide the additional state bits. 1325 */ 1326 public static final int MEASURED_STATE_MASK = 0xff000000; 1327 1328 /** 1329 * Bit shift of {@link #MEASURED_STATE_MASK} to get to the height bits 1330 * for functions that combine both width and height into a single int, 1331 * such as {@link #getMeasuredState()} and the childState argument of 1332 * {@link #resolveSizeAndState(int, int, int)}. 1333 */ 1334 public static final int MEASURED_HEIGHT_STATE_SHIFT = 16; 1335 1336 /** 1337 * Bit of {@link #getMeasuredWidthAndState()} and 1338 * {@link #getMeasuredWidthAndState()} that indicates the measured size 1339 * is smaller that the space the view would like to have. 1340 */ 1341 public static final int MEASURED_STATE_TOO_SMALL = 0x01000000; 1342 1343 /** 1344 * Base View state sets 1345 */ 1346 // Singles 1347 /** 1348 * Indicates the view has no states set. States are used with 1349 * {@link android.graphics.drawable.Drawable} to change the drawing of the 1350 * view depending on its state. 1351 * 1352 * @see android.graphics.drawable.Drawable 1353 * @see #getDrawableState() 1354 */ 1355 protected static final int[] EMPTY_STATE_SET; 1356 /** 1357 * Indicates the view is enabled. States are used with 1358 * {@link android.graphics.drawable.Drawable} to change the drawing of the 1359 * view depending on its state. 1360 * 1361 * @see android.graphics.drawable.Drawable 1362 * @see #getDrawableState() 1363 */ 1364 protected static final int[] ENABLED_STATE_SET; 1365 /** 1366 * Indicates the view is focused. States are used with 1367 * {@link android.graphics.drawable.Drawable} to change the drawing of the 1368 * view depending on its state. 1369 * 1370 * @see android.graphics.drawable.Drawable 1371 * @see #getDrawableState() 1372 */ 1373 protected static final int[] FOCUSED_STATE_SET; 1374 /** 1375 * Indicates the view is selected. States are used with 1376 * {@link android.graphics.drawable.Drawable} to change the drawing of the 1377 * view depending on its state. 1378 * 1379 * @see android.graphics.drawable.Drawable 1380 * @see #getDrawableState() 1381 */ 1382 protected static final int[] SELECTED_STATE_SET; 1383 /** 1384 * Indicates the view is pressed. States are used with 1385 * {@link android.graphics.drawable.Drawable} to change the drawing of the 1386 * view depending on its state. 1387 * 1388 * @see android.graphics.drawable.Drawable 1389 * @see #getDrawableState() 1390 */ 1391 protected static final int[] PRESSED_STATE_SET; 1392 /** 1393 * Indicates the view's window has focus. States are used with 1394 * {@link android.graphics.drawable.Drawable} to change the drawing of the 1395 * view depending on its state. 1396 * 1397 * @see android.graphics.drawable.Drawable 1398 * @see #getDrawableState() 1399 */ 1400 protected static final int[] WINDOW_FOCUSED_STATE_SET; 1401 // Doubles 1402 /** 1403 * Indicates the view is enabled and has the focus. 1404 * 1405 * @see #ENABLED_STATE_SET 1406 * @see #FOCUSED_STATE_SET 1407 */ 1408 protected static final int[] ENABLED_FOCUSED_STATE_SET; 1409 /** 1410 * Indicates the view is enabled and selected. 1411 * 1412 * @see #ENABLED_STATE_SET 1413 * @see #SELECTED_STATE_SET 1414 */ 1415 protected static final int[] ENABLED_SELECTED_STATE_SET; 1416 /** 1417 * Indicates the view is enabled and that its window has focus. 1418 * 1419 * @see #ENABLED_STATE_SET 1420 * @see #WINDOW_FOCUSED_STATE_SET 1421 */ 1422 protected static final int[] ENABLED_WINDOW_FOCUSED_STATE_SET; 1423 /** 1424 * Indicates the view is focused and selected. 1425 * 1426 * @see #FOCUSED_STATE_SET 1427 * @see #SELECTED_STATE_SET 1428 */ 1429 protected static final int[] FOCUSED_SELECTED_STATE_SET; 1430 /** 1431 * Indicates the view has the focus and that its window has the focus. 1432 * 1433 * @see #FOCUSED_STATE_SET 1434 * @see #WINDOW_FOCUSED_STATE_SET 1435 */ 1436 protected static final int[] FOCUSED_WINDOW_FOCUSED_STATE_SET; 1437 /** 1438 * Indicates the view is selected and that its window has the focus. 1439 * 1440 * @see #SELECTED_STATE_SET 1441 * @see #WINDOW_FOCUSED_STATE_SET 1442 */ 1443 protected static final int[] SELECTED_WINDOW_FOCUSED_STATE_SET; 1444 // Triples 1445 /** 1446 * Indicates the view is enabled, focused and selected. 1447 * 1448 * @see #ENABLED_STATE_SET 1449 * @see #FOCUSED_STATE_SET 1450 * @see #SELECTED_STATE_SET 1451 */ 1452 protected static final int[] ENABLED_FOCUSED_SELECTED_STATE_SET; 1453 /** 1454 * Indicates the view is enabled, focused and its window has the focus. 1455 * 1456 * @see #ENABLED_STATE_SET 1457 * @see #FOCUSED_STATE_SET 1458 * @see #WINDOW_FOCUSED_STATE_SET 1459 */ 1460 protected static final int[] ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET; 1461 /** 1462 * Indicates the view is enabled, selected and its window has the focus. 1463 * 1464 * @see #ENABLED_STATE_SET 1465 * @see #SELECTED_STATE_SET 1466 * @see #WINDOW_FOCUSED_STATE_SET 1467 */ 1468 protected static final int[] ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET; 1469 /** 1470 * Indicates the view is focused, selected and its window has the focus. 1471 * 1472 * @see #FOCUSED_STATE_SET 1473 * @see #SELECTED_STATE_SET 1474 * @see #WINDOW_FOCUSED_STATE_SET 1475 */ 1476 protected static final int[] FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 1477 /** 1478 * Indicates the view is enabled, focused, selected and its window 1479 * has the focus. 1480 * 1481 * @see #ENABLED_STATE_SET 1482 * @see #FOCUSED_STATE_SET 1483 * @see #SELECTED_STATE_SET 1484 * @see #WINDOW_FOCUSED_STATE_SET 1485 */ 1486 protected static final int[] ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 1487 /** 1488 * Indicates the view is pressed and its window has the focus. 1489 * 1490 * @see #PRESSED_STATE_SET 1491 * @see #WINDOW_FOCUSED_STATE_SET 1492 */ 1493 protected static final int[] PRESSED_WINDOW_FOCUSED_STATE_SET; 1494 /** 1495 * Indicates the view is pressed and selected. 1496 * 1497 * @see #PRESSED_STATE_SET 1498 * @see #SELECTED_STATE_SET 1499 */ 1500 protected static final int[] PRESSED_SELECTED_STATE_SET; 1501 /** 1502 * Indicates the view is pressed, selected and its window has the focus. 1503 * 1504 * @see #PRESSED_STATE_SET 1505 * @see #SELECTED_STATE_SET 1506 * @see #WINDOW_FOCUSED_STATE_SET 1507 */ 1508 protected static final int[] PRESSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 1509 /** 1510 * Indicates the view is pressed and focused. 1511 * 1512 * @see #PRESSED_STATE_SET 1513 * @see #FOCUSED_STATE_SET 1514 */ 1515 protected static final int[] PRESSED_FOCUSED_STATE_SET; 1516 /** 1517 * Indicates the view is pressed, focused and its window has the focus. 1518 * 1519 * @see #PRESSED_STATE_SET 1520 * @see #FOCUSED_STATE_SET 1521 * @see #WINDOW_FOCUSED_STATE_SET 1522 */ 1523 protected static final int[] PRESSED_FOCUSED_WINDOW_FOCUSED_STATE_SET; 1524 /** 1525 * Indicates the view is pressed, focused and selected. 1526 * 1527 * @see #PRESSED_STATE_SET 1528 * @see #SELECTED_STATE_SET 1529 * @see #FOCUSED_STATE_SET 1530 */ 1531 protected static final int[] PRESSED_FOCUSED_SELECTED_STATE_SET; 1532 /** 1533 * Indicates the view is pressed, focused, selected and its window has the focus. 1534 * 1535 * @see #PRESSED_STATE_SET 1536 * @see #FOCUSED_STATE_SET 1537 * @see #SELECTED_STATE_SET 1538 * @see #WINDOW_FOCUSED_STATE_SET 1539 */ 1540 protected static final int[] PRESSED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 1541 /** 1542 * Indicates the view is pressed and enabled. 1543 * 1544 * @see #PRESSED_STATE_SET 1545 * @see #ENABLED_STATE_SET 1546 */ 1547 protected static final int[] PRESSED_ENABLED_STATE_SET; 1548 /** 1549 * Indicates the view is pressed, enabled and its window has the focus. 1550 * 1551 * @see #PRESSED_STATE_SET 1552 * @see #ENABLED_STATE_SET 1553 * @see #WINDOW_FOCUSED_STATE_SET 1554 */ 1555 protected static final int[] PRESSED_ENABLED_WINDOW_FOCUSED_STATE_SET; 1556 /** 1557 * Indicates the view is pressed, enabled and selected. 1558 * 1559 * @see #PRESSED_STATE_SET 1560 * @see #ENABLED_STATE_SET 1561 * @see #SELECTED_STATE_SET 1562 */ 1563 protected static final int[] PRESSED_ENABLED_SELECTED_STATE_SET; 1564 /** 1565 * Indicates the view is pressed, enabled, selected and its window has the 1566 * focus. 1567 * 1568 * @see #PRESSED_STATE_SET 1569 * @see #ENABLED_STATE_SET 1570 * @see #SELECTED_STATE_SET 1571 * @see #WINDOW_FOCUSED_STATE_SET 1572 */ 1573 protected static final int[] PRESSED_ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET; 1574 /** 1575 * Indicates the view is pressed, enabled and focused. 1576 * 1577 * @see #PRESSED_STATE_SET 1578 * @see #ENABLED_STATE_SET 1579 * @see #FOCUSED_STATE_SET 1580 */ 1581 protected static final int[] PRESSED_ENABLED_FOCUSED_STATE_SET; 1582 /** 1583 * Indicates the view is pressed, enabled, focused and its window has the 1584 * focus. 1585 * 1586 * @see #PRESSED_STATE_SET 1587 * @see #ENABLED_STATE_SET 1588 * @see #FOCUSED_STATE_SET 1589 * @see #WINDOW_FOCUSED_STATE_SET 1590 */ 1591 protected static final int[] PRESSED_ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET; 1592 /** 1593 * Indicates the view is pressed, enabled, focused and selected. 1594 * 1595 * @see #PRESSED_STATE_SET 1596 * @see #ENABLED_STATE_SET 1597 * @see #SELECTED_STATE_SET 1598 * @see #FOCUSED_STATE_SET 1599 */ 1600 protected static final int[] PRESSED_ENABLED_FOCUSED_SELECTED_STATE_SET; 1601 /** 1602 * Indicates the view is pressed, enabled, focused, selected and its window 1603 * has the focus. 1604 * 1605 * @see #PRESSED_STATE_SET 1606 * @see #ENABLED_STATE_SET 1607 * @see #SELECTED_STATE_SET 1608 * @see #FOCUSED_STATE_SET 1609 * @see #WINDOW_FOCUSED_STATE_SET 1610 */ 1611 protected static final int[] PRESSED_ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 1612 1613 static { 1614 EMPTY_STATE_SET = StateSet.get(0); 1615 1616 WINDOW_FOCUSED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_WINDOW_FOCUSED); 1617 1618 SELECTED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_SELECTED); 1619 SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1620 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED); 1621 1622 FOCUSED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_FOCUSED); 1623 FOCUSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1624 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_FOCUSED); 1625 FOCUSED_SELECTED_STATE_SET = StateSet.get( 1626 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_FOCUSED); 1627 FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1628 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 1629 | StateSet.VIEW_STATE_FOCUSED); 1630 1631 ENABLED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_ENABLED); 1632 ENABLED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1633 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_ENABLED); 1634 ENABLED_SELECTED_STATE_SET = StateSet.get( 1635 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_ENABLED); 1636 ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1637 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 1638 | StateSet.VIEW_STATE_ENABLED); 1639 ENABLED_FOCUSED_STATE_SET = StateSet.get( 1640 StateSet.VIEW_STATE_FOCUSED | StateSet.VIEW_STATE_ENABLED); 1641 ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1642 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_FOCUSED 1643 | StateSet.VIEW_STATE_ENABLED); 1644 ENABLED_FOCUSED_SELECTED_STATE_SET = StateSet.get( 1645 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_FOCUSED 1646 | StateSet.VIEW_STATE_ENABLED); 1647 ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1648 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 1649 | StateSet.VIEW_STATE_FOCUSED| StateSet.VIEW_STATE_ENABLED); 1650 1651 PRESSED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_PRESSED); 1652 PRESSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1653 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_PRESSED); 1654 PRESSED_SELECTED_STATE_SET = StateSet.get( 1655 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_PRESSED); 1656 PRESSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1657 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 1658 | StateSet.VIEW_STATE_PRESSED); 1659 PRESSED_FOCUSED_STATE_SET = StateSet.get( 1660 StateSet.VIEW_STATE_FOCUSED | StateSet.VIEW_STATE_PRESSED); 1661 PRESSED_FOCUSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1662 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_FOCUSED 1663 | StateSet.VIEW_STATE_PRESSED); 1664 PRESSED_FOCUSED_SELECTED_STATE_SET = StateSet.get( 1665 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_FOCUSED 1666 | StateSet.VIEW_STATE_PRESSED); 1667 PRESSED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1668 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 1669 | StateSet.VIEW_STATE_FOCUSED | StateSet.VIEW_STATE_PRESSED); 1670 PRESSED_ENABLED_STATE_SET = StateSet.get( 1671 StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_PRESSED); 1672 PRESSED_ENABLED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1673 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_ENABLED 1674 | StateSet.VIEW_STATE_PRESSED); 1675 PRESSED_ENABLED_SELECTED_STATE_SET = StateSet.get( 1676 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_ENABLED 1677 | StateSet.VIEW_STATE_PRESSED); 1678 PRESSED_ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1679 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 1680 | StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_PRESSED); 1681 PRESSED_ENABLED_FOCUSED_STATE_SET = StateSet.get( 1682 StateSet.VIEW_STATE_FOCUSED | StateSet.VIEW_STATE_ENABLED 1683 | StateSet.VIEW_STATE_PRESSED); 1684 PRESSED_ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1685 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_FOCUSED 1686 | StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_PRESSED); 1687 PRESSED_ENABLED_FOCUSED_SELECTED_STATE_SET = StateSet.get( 1688 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_FOCUSED 1689 | StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_PRESSED); 1690 PRESSED_ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1691 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 1692 | StateSet.VIEW_STATE_FOCUSED| StateSet.VIEW_STATE_ENABLED 1693 | StateSet.VIEW_STATE_PRESSED); 1694 } 1695 1696 /** 1697 * Accessibility event types that are dispatched for text population. 1698 */ 1699 private static final int POPULATING_ACCESSIBILITY_EVENT_TYPES = 1700 AccessibilityEvent.TYPE_VIEW_CLICKED 1701 | AccessibilityEvent.TYPE_VIEW_LONG_CLICKED 1702 | AccessibilityEvent.TYPE_VIEW_SELECTED 1703 | AccessibilityEvent.TYPE_VIEW_FOCUSED 1704 | AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED 1705 | AccessibilityEvent.TYPE_VIEW_HOVER_ENTER 1706 | AccessibilityEvent.TYPE_VIEW_HOVER_EXIT 1707 | AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED 1708 | AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED 1709 | AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED 1710 | AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY; 1711 1712 static final int DEBUG_CORNERS_COLOR = Color.rgb(63, 127, 255); 1713 1714 static final int DEBUG_CORNERS_SIZE_DIP = 8; 1715 1716 /** 1717 * Temporary Rect currently for use in setBackground(). This will probably 1718 * be extended in the future to hold our own class with more than just 1719 * a Rect. :) 1720 */ 1721 static final ThreadLocal<Rect> sThreadLocal = new ThreadLocal<Rect>(); 1722 1723 /** 1724 * Map used to store views' tags. 1725 */ 1726 private SparseArray<Object> mKeyedTags; 1727 1728 /** 1729 * The next available accessibility id. 1730 */ 1731 private static int sNextAccessibilityViewId; 1732 1733 /** 1734 * The animation currently associated with this view. 1735 * @hide 1736 */ 1737 protected Animation mCurrentAnimation = null; 1738 1739 /** 1740 * Width as measured during measure pass. 1741 * {@hide} 1742 */ 1743 @ViewDebug.ExportedProperty(category = "measurement") 1744 int mMeasuredWidth; 1745 1746 /** 1747 * Height as measured during measure pass. 1748 * {@hide} 1749 */ 1750 @ViewDebug.ExportedProperty(category = "measurement") 1751 int mMeasuredHeight; 1752 1753 /** 1754 * Flag to indicate that this view was marked INVALIDATED, or had its display list 1755 * invalidated, prior to the current drawing iteration. If true, the view must re-draw 1756 * its display list. This flag, used only when hw accelerated, allows us to clear the 1757 * flag while retaining this information until it's needed (at getDisplayList() time and 1758 * in drawChild(), when we decide to draw a view's children's display lists into our own). 1759 * 1760 * {@hide} 1761 */ 1762 boolean mRecreateDisplayList = false; 1763 1764 /** 1765 * The view's identifier. 1766 * {@hide} 1767 * 1768 * @see #setId(int) 1769 * @see #getId() 1770 */ 1771 @IdRes 1772 @ViewDebug.ExportedProperty(resolveId = true) 1773 int mID = NO_ID; 1774 1775 /** 1776 * The stable ID of this view for accessibility purposes. 1777 */ 1778 int mAccessibilityViewId = NO_ID; 1779 1780 private int mAccessibilityCursorPosition = ACCESSIBILITY_CURSOR_POSITION_UNDEFINED; 1781 1782 SendViewStateChangedAccessibilityEvent mSendViewStateChangedAccessibilityEvent; 1783 1784 /** 1785 * The view's tag. 1786 * {@hide} 1787 * 1788 * @see #setTag(Object) 1789 * @see #getTag() 1790 */ 1791 protected Object mTag = null; 1792 1793 // for mPrivateFlags: 1794 /** {@hide} */ 1795 static final int PFLAG_WANTS_FOCUS = 0x00000001; 1796 /** {@hide} */ 1797 static final int PFLAG_FOCUSED = 0x00000002; 1798 /** {@hide} */ 1799 static final int PFLAG_SELECTED = 0x00000004; 1800 /** {@hide} */ 1801 static final int PFLAG_IS_ROOT_NAMESPACE = 0x00000008; 1802 /** {@hide} */ 1803 static final int PFLAG_HAS_BOUNDS = 0x00000010; 1804 /** {@hide} */ 1805 static final int PFLAG_DRAWN = 0x00000020; 1806 /** 1807 * When this flag is set, this view is running an animation on behalf of its 1808 * children and should therefore not cancel invalidate requests, even if they 1809 * lie outside of this view's bounds. 1810 * 1811 * {@hide} 1812 */ 1813 static final int PFLAG_DRAW_ANIMATION = 0x00000040; 1814 /** {@hide} */ 1815 static final int PFLAG_SKIP_DRAW = 0x00000080; 1816 /** {@hide} */ 1817 static final int PFLAG_REQUEST_TRANSPARENT_REGIONS = 0x00000200; 1818 /** {@hide} */ 1819 static final int PFLAG_DRAWABLE_STATE_DIRTY = 0x00000400; 1820 /** {@hide} */ 1821 static final int PFLAG_MEASURED_DIMENSION_SET = 0x00000800; 1822 /** {@hide} */ 1823 static final int PFLAG_FORCE_LAYOUT = 0x00001000; 1824 /** {@hide} */ 1825 static final int PFLAG_LAYOUT_REQUIRED = 0x00002000; 1826 1827 private static final int PFLAG_PRESSED = 0x00004000; 1828 1829 /** {@hide} */ 1830 static final int PFLAG_DRAWING_CACHE_VALID = 0x00008000; 1831 /** 1832 * Flag used to indicate that this view should be drawn once more (and only once 1833 * more) after its animation has completed. 1834 * {@hide} 1835 */ 1836 static final int PFLAG_ANIMATION_STARTED = 0x00010000; 1837 1838 private static final int PFLAG_SAVE_STATE_CALLED = 0x00020000; 1839 1840 /** 1841 * Indicates that the View returned true when onSetAlpha() was called and that 1842 * the alpha must be restored. 1843 * {@hide} 1844 */ 1845 static final int PFLAG_ALPHA_SET = 0x00040000; 1846 1847 /** 1848 * Set by {@link #setScrollContainer(boolean)}. 1849 */ 1850 static final int PFLAG_SCROLL_CONTAINER = 0x00080000; 1851 1852 /** 1853 * Set by {@link #setScrollContainer(boolean)}. 1854 */ 1855 static final int PFLAG_SCROLL_CONTAINER_ADDED = 0x00100000; 1856 1857 /** 1858 * View flag indicating whether this view was invalidated (fully or partially.) 1859 * 1860 * @hide 1861 */ 1862 static final int PFLAG_DIRTY = 0x00200000; 1863 1864 /** 1865 * View flag indicating whether this view was invalidated by an opaque 1866 * invalidate request. 1867 * 1868 * @hide 1869 */ 1870 static final int PFLAG_DIRTY_OPAQUE = 0x00400000; 1871 1872 /** 1873 * Mask for {@link #PFLAG_DIRTY} and {@link #PFLAG_DIRTY_OPAQUE}. 1874 * 1875 * @hide 1876 */ 1877 static final int PFLAG_DIRTY_MASK = 0x00600000; 1878 1879 /** 1880 * Indicates whether the background is opaque. 1881 * 1882 * @hide 1883 */ 1884 static final int PFLAG_OPAQUE_BACKGROUND = 0x00800000; 1885 1886 /** 1887 * Indicates whether the scrollbars are opaque. 1888 * 1889 * @hide 1890 */ 1891 static final int PFLAG_OPAQUE_SCROLLBARS = 0x01000000; 1892 1893 /** 1894 * Indicates whether the view is opaque. 1895 * 1896 * @hide 1897 */ 1898 static final int PFLAG_OPAQUE_MASK = 0x01800000; 1899 1900 /** 1901 * Indicates a prepressed state; 1902 * the short time between ACTION_DOWN and recognizing 1903 * a 'real' press. Prepressed is used to recognize quick taps 1904 * even when they are shorter than ViewConfiguration.getTapTimeout(). 1905 * 1906 * @hide 1907 */ 1908 private static final int PFLAG_PREPRESSED = 0x02000000; 1909 1910 /** 1911 * Indicates whether the view is temporarily detached. 1912 * 1913 * @hide 1914 */ 1915 static final int PFLAG_CANCEL_NEXT_UP_EVENT = 0x04000000; 1916 1917 /** 1918 * Indicates that we should awaken scroll bars once attached 1919 * 1920 * PLEASE NOTE: This flag is now unused as we now send onVisibilityChanged 1921 * during window attachment and it is no longer needed. Feel free to repurpose it. 1922 * 1923 * @hide 1924 */ 1925 private static final int PFLAG_AWAKEN_SCROLL_BARS_ON_ATTACH = 0x08000000; 1926 1927 /** 1928 * Indicates that the view has received HOVER_ENTER. Cleared on HOVER_EXIT. 1929 * @hide 1930 */ 1931 private static final int PFLAG_HOVERED = 0x10000000; 1932 1933 /** 1934 * no longer needed, should be reused 1935 */ 1936 private static final int PFLAG_DOES_NOTHING_REUSE_PLEASE = 0x20000000; 1937 1938 /** {@hide} */ 1939 static final int PFLAG_ACTIVATED = 0x40000000; 1940 1941 /** 1942 * Indicates that this view was specifically invalidated, not just dirtied because some 1943 * child view was invalidated. The flag is used to determine when we need to recreate 1944 * a view's display list (as opposed to just returning a reference to its existing 1945 * display list). 1946 * 1947 * @hide 1948 */ 1949 static final int PFLAG_INVALIDATED = 0x80000000; 1950 1951 /** 1952 * Masks for mPrivateFlags2, as generated by dumpFlags(): 1953 * 1954 * |-------|-------|-------|-------| 1955 * 1 PFLAG2_DRAG_CAN_ACCEPT 1956 * 1 PFLAG2_DRAG_HOVERED 1957 * 11 PFLAG2_LAYOUT_DIRECTION_MASK 1958 * 1 PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL 1959 * 1 PFLAG2_LAYOUT_DIRECTION_RESOLVED 1960 * 11 PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK 1961 * 1 PFLAG2_TEXT_DIRECTION_FLAGS[1] 1962 * 1 PFLAG2_TEXT_DIRECTION_FLAGS[2] 1963 * 11 PFLAG2_TEXT_DIRECTION_FLAGS[3] 1964 * 1 PFLAG2_TEXT_DIRECTION_FLAGS[4] 1965 * 1 1 PFLAG2_TEXT_DIRECTION_FLAGS[5] 1966 * 11 PFLAG2_TEXT_DIRECTION_FLAGS[6] 1967 * 111 PFLAG2_TEXT_DIRECTION_FLAGS[7] 1968 * 111 PFLAG2_TEXT_DIRECTION_MASK 1969 * 1 PFLAG2_TEXT_DIRECTION_RESOLVED 1970 * 1 PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT 1971 * 111 PFLAG2_TEXT_DIRECTION_RESOLVED_MASK 1972 * 1 PFLAG2_TEXT_ALIGNMENT_FLAGS[1] 1973 * 1 PFLAG2_TEXT_ALIGNMENT_FLAGS[2] 1974 * 11 PFLAG2_TEXT_ALIGNMENT_FLAGS[3] 1975 * 1 PFLAG2_TEXT_ALIGNMENT_FLAGS[4] 1976 * 1 1 PFLAG2_TEXT_ALIGNMENT_FLAGS[5] 1977 * 11 PFLAG2_TEXT_ALIGNMENT_FLAGS[6] 1978 * 111 PFLAG2_TEXT_ALIGNMENT_MASK 1979 * 1 PFLAG2_TEXT_ALIGNMENT_RESOLVED 1980 * 1 PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT 1981 * 111 PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK 1982 * 111 PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK 1983 * 11 PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK 1984 * 1 PFLAG2_ACCESSIBILITY_FOCUSED 1985 * 1 PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED 1986 * 1 PFLAG2_VIEW_QUICK_REJECTED 1987 * 1 PFLAG2_PADDING_RESOLVED 1988 * 1 PFLAG2_DRAWABLE_RESOLVED 1989 * 1 PFLAG2_HAS_TRANSIENT_STATE 1990 * |-------|-------|-------|-------| 1991 */ 1992 1993 /** 1994 * Indicates that this view has reported that it can accept the current drag's content. 1995 * Cleared when the drag operation concludes. 1996 * @hide 1997 */ 1998 static final int PFLAG2_DRAG_CAN_ACCEPT = 0x00000001; 1999 2000 /** 2001 * Indicates that this view is currently directly under the drag location in a 2002 * drag-and-drop operation involving content that it can accept. Cleared when 2003 * the drag exits the view, or when the drag operation concludes. 2004 * @hide 2005 */ 2006 static final int PFLAG2_DRAG_HOVERED = 0x00000002; 2007 2008 /** @hide */ 2009 @IntDef({ 2010 LAYOUT_DIRECTION_LTR, 2011 LAYOUT_DIRECTION_RTL, 2012 LAYOUT_DIRECTION_INHERIT, 2013 LAYOUT_DIRECTION_LOCALE 2014 }) 2015 @Retention(RetentionPolicy.SOURCE) 2016 // Not called LayoutDirection to avoid conflict with android.util.LayoutDirection 2017 public @interface LayoutDir {} 2018 2019 /** @hide */ 2020 @IntDef({ 2021 LAYOUT_DIRECTION_LTR, 2022 LAYOUT_DIRECTION_RTL 2023 }) 2024 @Retention(RetentionPolicy.SOURCE) 2025 public @interface ResolvedLayoutDir {} 2026 2027 /** 2028 * A flag to indicate that the layout direction of this view has not been defined yet. 2029 * @hide 2030 */ 2031 public static final int LAYOUT_DIRECTION_UNDEFINED = LayoutDirection.UNDEFINED; 2032 2033 /** 2034 * Horizontal layout direction of this view is from Left to Right. 2035 * Use with {@link #setLayoutDirection}. 2036 */ 2037 public static final int LAYOUT_DIRECTION_LTR = LayoutDirection.LTR; 2038 2039 /** 2040 * Horizontal layout direction of this view is from Right to Left. 2041 * Use with {@link #setLayoutDirection}. 2042 */ 2043 public static final int LAYOUT_DIRECTION_RTL = LayoutDirection.RTL; 2044 2045 /** 2046 * Horizontal layout direction of this view is inherited from its parent. 2047 * Use with {@link #setLayoutDirection}. 2048 */ 2049 public static final int LAYOUT_DIRECTION_INHERIT = LayoutDirection.INHERIT; 2050 2051 /** 2052 * Horizontal layout direction of this view is from deduced from the default language 2053 * script for the locale. Use with {@link #setLayoutDirection}. 2054 */ 2055 public static final int LAYOUT_DIRECTION_LOCALE = LayoutDirection.LOCALE; 2056 2057 /** 2058 * Bit shift to get the horizontal layout direction. (bits after DRAG_HOVERED) 2059 * @hide 2060 */ 2061 static final int PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT = 2; 2062 2063 /** 2064 * Mask for use with private flags indicating bits used for horizontal layout direction. 2065 * @hide 2066 */ 2067 static final int PFLAG2_LAYOUT_DIRECTION_MASK = 0x00000003 << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 2068 2069 /** 2070 * Indicates whether the view horizontal layout direction has been resolved and drawn to the 2071 * right-to-left direction. 2072 * @hide 2073 */ 2074 static final int PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL = 4 << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 2075 2076 /** 2077 * Indicates whether the view horizontal layout direction has been resolved. 2078 * @hide 2079 */ 2080 static final int PFLAG2_LAYOUT_DIRECTION_RESOLVED = 8 << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 2081 2082 /** 2083 * Mask for use with private flags indicating bits used for resolved horizontal layout direction. 2084 * @hide 2085 */ 2086 static final int PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK = 0x0000000C 2087 << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 2088 2089 /* 2090 * Array of horizontal layout direction flags for mapping attribute "layoutDirection" to correct 2091 * flag value. 2092 * @hide 2093 */ 2094 private static final int[] LAYOUT_DIRECTION_FLAGS = { 2095 LAYOUT_DIRECTION_LTR, 2096 LAYOUT_DIRECTION_RTL, 2097 LAYOUT_DIRECTION_INHERIT, 2098 LAYOUT_DIRECTION_LOCALE 2099 }; 2100 2101 /** 2102 * Default horizontal layout direction. 2103 */ 2104 private static final int LAYOUT_DIRECTION_DEFAULT = LAYOUT_DIRECTION_INHERIT; 2105 2106 /** 2107 * Default horizontal layout direction. 2108 * @hide 2109 */ 2110 static final int LAYOUT_DIRECTION_RESOLVED_DEFAULT = LAYOUT_DIRECTION_LTR; 2111 2112 /** 2113 * Text direction is inherited through {@link ViewGroup} 2114 */ 2115 public static final int TEXT_DIRECTION_INHERIT = 0; 2116 2117 /** 2118 * Text direction is using "first strong algorithm". The first strong directional character 2119 * determines the paragraph direction. If there is no strong directional character, the 2120 * paragraph direction is the view's resolved layout direction. 2121 */ 2122 public static final int TEXT_DIRECTION_FIRST_STRONG = 1; 2123 2124 /** 2125 * Text direction is using "any-RTL" algorithm. The paragraph direction is RTL if it contains 2126 * any strong RTL character, otherwise it is LTR if it contains any strong LTR characters. 2127 * If there are neither, the paragraph direction is the view's resolved layout direction. 2128 */ 2129 public static final int TEXT_DIRECTION_ANY_RTL = 2; 2130 2131 /** 2132 * Text direction is forced to LTR. 2133 */ 2134 public static final int TEXT_DIRECTION_LTR = 3; 2135 2136 /** 2137 * Text direction is forced to RTL. 2138 */ 2139 public static final int TEXT_DIRECTION_RTL = 4; 2140 2141 /** 2142 * Text direction is coming from the system Locale. 2143 */ 2144 public static final int TEXT_DIRECTION_LOCALE = 5; 2145 2146 /** 2147 * Text direction is using "first strong algorithm". The first strong directional character 2148 * determines the paragraph direction. If there is no strong directional character, the 2149 * paragraph direction is LTR. 2150 */ 2151 public static final int TEXT_DIRECTION_FIRST_STRONG_LTR = 6; 2152 2153 /** 2154 * Text direction is using "first strong algorithm". The first strong directional character 2155 * determines the paragraph direction. If there is no strong directional character, the 2156 * paragraph direction is RTL. 2157 */ 2158 public static final int TEXT_DIRECTION_FIRST_STRONG_RTL = 7; 2159 2160 /** 2161 * Default text direction is inherited 2162 */ 2163 private static final int TEXT_DIRECTION_DEFAULT = TEXT_DIRECTION_INHERIT; 2164 2165 /** 2166 * Default resolved text direction 2167 * @hide 2168 */ 2169 static final int TEXT_DIRECTION_RESOLVED_DEFAULT = TEXT_DIRECTION_FIRST_STRONG; 2170 2171 /** 2172 * Bit shift to get the horizontal layout direction. (bits after LAYOUT_DIRECTION_RESOLVED) 2173 * @hide 2174 */ 2175 static final int PFLAG2_TEXT_DIRECTION_MASK_SHIFT = 6; 2176 2177 /** 2178 * Mask for use with private flags indicating bits used for text direction. 2179 * @hide 2180 */ 2181 static final int PFLAG2_TEXT_DIRECTION_MASK = 0x00000007 2182 << PFLAG2_TEXT_DIRECTION_MASK_SHIFT; 2183 2184 /** 2185 * Array of text direction flags for mapping attribute "textDirection" to correct 2186 * flag value. 2187 * @hide 2188 */ 2189 private static final int[] PFLAG2_TEXT_DIRECTION_FLAGS = { 2190 TEXT_DIRECTION_INHERIT << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2191 TEXT_DIRECTION_FIRST_STRONG << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2192 TEXT_DIRECTION_ANY_RTL << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2193 TEXT_DIRECTION_LTR << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2194 TEXT_DIRECTION_RTL << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2195 TEXT_DIRECTION_LOCALE << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2196 TEXT_DIRECTION_FIRST_STRONG_LTR << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2197 TEXT_DIRECTION_FIRST_STRONG_RTL << PFLAG2_TEXT_DIRECTION_MASK_SHIFT 2198 }; 2199 2200 /** 2201 * Indicates whether the view text direction has been resolved. 2202 * @hide 2203 */ 2204 static final int PFLAG2_TEXT_DIRECTION_RESOLVED = 0x00000008 2205 << PFLAG2_TEXT_DIRECTION_MASK_SHIFT; 2206 2207 /** 2208 * Bit shift to get the horizontal layout direction. (bits after DRAG_HOVERED) 2209 * @hide 2210 */ 2211 static final int PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT = 10; 2212 2213 /** 2214 * Mask for use with private flags indicating bits used for resolved text direction. 2215 * @hide 2216 */ 2217 static final int PFLAG2_TEXT_DIRECTION_RESOLVED_MASK = 0x00000007 2218 << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT; 2219 2220 /** 2221 * Indicates whether the view text direction has been resolved to the "first strong" heuristic. 2222 * @hide 2223 */ 2224 static final int PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT = 2225 TEXT_DIRECTION_RESOLVED_DEFAULT << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT; 2226 2227 /** @hide */ 2228 @IntDef({ 2229 TEXT_ALIGNMENT_INHERIT, 2230 TEXT_ALIGNMENT_GRAVITY, 2231 TEXT_ALIGNMENT_CENTER, 2232 TEXT_ALIGNMENT_TEXT_START, 2233 TEXT_ALIGNMENT_TEXT_END, 2234 TEXT_ALIGNMENT_VIEW_START, 2235 TEXT_ALIGNMENT_VIEW_END 2236 }) 2237 @Retention(RetentionPolicy.SOURCE) 2238 public @interface TextAlignment {} 2239 2240 /** 2241 * Default text alignment. The text alignment of this View is inherited from its parent. 2242 * Use with {@link #setTextAlignment(int)} 2243 */ 2244 public static final int TEXT_ALIGNMENT_INHERIT = 0; 2245 2246 /** 2247 * Default for the root view. The gravity determines the text alignment, ALIGN_NORMAL, 2248 * ALIGN_CENTER, or ALIGN_OPPOSITE, which are relative to each paragraph’s text direction. 2249 * 2250 * Use with {@link #setTextAlignment(int)} 2251 */ 2252 public static final int TEXT_ALIGNMENT_GRAVITY = 1; 2253 2254 /** 2255 * Align to the start of the paragraph, e.g. ALIGN_NORMAL. 2256 * 2257 * Use with {@link #setTextAlignment(int)} 2258 */ 2259 public static final int TEXT_ALIGNMENT_TEXT_START = 2; 2260 2261 /** 2262 * Align to the end of the paragraph, e.g. ALIGN_OPPOSITE. 2263 * 2264 * Use with {@link #setTextAlignment(int)} 2265 */ 2266 public static final int TEXT_ALIGNMENT_TEXT_END = 3; 2267 2268 /** 2269 * Center the paragraph, e.g. ALIGN_CENTER. 2270 * 2271 * Use with {@link #setTextAlignment(int)} 2272 */ 2273 public static final int TEXT_ALIGNMENT_CENTER = 4; 2274 2275 /** 2276 * Align to the start of the view, which is ALIGN_LEFT if the view’s resolved 2277 * layoutDirection is LTR, and ALIGN_RIGHT otherwise. 2278 * 2279 * Use with {@link #setTextAlignment(int)} 2280 */ 2281 public static final int TEXT_ALIGNMENT_VIEW_START = 5; 2282 2283 /** 2284 * Align to the end of the view, which is ALIGN_RIGHT if the view’s resolved 2285 * layoutDirection is LTR, and ALIGN_LEFT otherwise. 2286 * 2287 * Use with {@link #setTextAlignment(int)} 2288 */ 2289 public static final int TEXT_ALIGNMENT_VIEW_END = 6; 2290 2291 /** 2292 * Default text alignment is inherited 2293 */ 2294 private static final int TEXT_ALIGNMENT_DEFAULT = TEXT_ALIGNMENT_GRAVITY; 2295 2296 /** 2297 * Default resolved text alignment 2298 * @hide 2299 */ 2300 static final int TEXT_ALIGNMENT_RESOLVED_DEFAULT = TEXT_ALIGNMENT_GRAVITY; 2301 2302 /** 2303 * Bit shift to get the horizontal layout direction. (bits after DRAG_HOVERED) 2304 * @hide 2305 */ 2306 static final int PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT = 13; 2307 2308 /** 2309 * Mask for use with private flags indicating bits used for text alignment. 2310 * @hide 2311 */ 2312 static final int PFLAG2_TEXT_ALIGNMENT_MASK = 0x00000007 << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT; 2313 2314 /** 2315 * Array of text direction flags for mapping attribute "textAlignment" to correct 2316 * flag value. 2317 * @hide 2318 */ 2319 private static final int[] PFLAG2_TEXT_ALIGNMENT_FLAGS = { 2320 TEXT_ALIGNMENT_INHERIT << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 2321 TEXT_ALIGNMENT_GRAVITY << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 2322 TEXT_ALIGNMENT_TEXT_START << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 2323 TEXT_ALIGNMENT_TEXT_END << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 2324 TEXT_ALIGNMENT_CENTER << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 2325 TEXT_ALIGNMENT_VIEW_START << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 2326 TEXT_ALIGNMENT_VIEW_END << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT 2327 }; 2328 2329 /** 2330 * Indicates whether the view text alignment has been resolved. 2331 * @hide 2332 */ 2333 static final int PFLAG2_TEXT_ALIGNMENT_RESOLVED = 0x00000008 << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT; 2334 2335 /** 2336 * Bit shift to get the resolved text alignment. 2337 * @hide 2338 */ 2339 static final int PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT = 17; 2340 2341 /** 2342 * Mask for use with private flags indicating bits used for text alignment. 2343 * @hide 2344 */ 2345 static final int PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK = 0x00000007 2346 << PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT; 2347 2348 /** 2349 * Indicates whether if the view text alignment has been resolved to gravity 2350 */ 2351 private static final int PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT = 2352 TEXT_ALIGNMENT_RESOLVED_DEFAULT << PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT; 2353 2354 // Accessiblity constants for mPrivateFlags2 2355 2356 /** 2357 * Shift for the bits in {@link #mPrivateFlags2} related to the 2358 * "importantForAccessibility" attribute. 2359 */ 2360 static final int PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT = 20; 2361 2362 /** 2363 * Automatically determine whether a view is important for accessibility. 2364 */ 2365 public static final int IMPORTANT_FOR_ACCESSIBILITY_AUTO = 0x00000000; 2366 2367 /** 2368 * The view is important for accessibility. 2369 */ 2370 public static final int IMPORTANT_FOR_ACCESSIBILITY_YES = 0x00000001; 2371 2372 /** 2373 * The view is not important for accessibility. 2374 */ 2375 public static final int IMPORTANT_FOR_ACCESSIBILITY_NO = 0x00000002; 2376 2377 /** 2378 * The view is not important for accessibility, nor are any of its 2379 * descendant views. 2380 */ 2381 public static final int IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS = 0x00000004; 2382 2383 /** 2384 * The default whether the view is important for accessibility. 2385 */ 2386 static final int IMPORTANT_FOR_ACCESSIBILITY_DEFAULT = IMPORTANT_FOR_ACCESSIBILITY_AUTO; 2387 2388 /** 2389 * Mask for obtaining the bits which specify how to determine 2390 * whether a view is important for accessibility. 2391 */ 2392 static final int PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK = (IMPORTANT_FOR_ACCESSIBILITY_AUTO 2393 | IMPORTANT_FOR_ACCESSIBILITY_YES | IMPORTANT_FOR_ACCESSIBILITY_NO 2394 | IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS) 2395 << PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT; 2396 2397 /** 2398 * Shift for the bits in {@link #mPrivateFlags2} related to the 2399 * "accessibilityLiveRegion" attribute. 2400 */ 2401 static final int PFLAG2_ACCESSIBILITY_LIVE_REGION_SHIFT = 23; 2402 2403 /** 2404 * Live region mode specifying that accessibility services should not 2405 * automatically announce changes to this view. This is the default live 2406 * region mode for most views. 2407 * <p> 2408 * Use with {@link #setAccessibilityLiveRegion(int)}. 2409 */ 2410 public static final int ACCESSIBILITY_LIVE_REGION_NONE = 0x00000000; 2411 2412 /** 2413 * Live region mode specifying that accessibility services should announce 2414 * changes to this view. 2415 * <p> 2416 * Use with {@link #setAccessibilityLiveRegion(int)}. 2417 */ 2418 public static final int ACCESSIBILITY_LIVE_REGION_POLITE = 0x00000001; 2419 2420 /** 2421 * Live region mode specifying that accessibility services should interrupt 2422 * ongoing speech to immediately announce changes to this view. 2423 * <p> 2424 * Use with {@link #setAccessibilityLiveRegion(int)}. 2425 */ 2426 public static final int ACCESSIBILITY_LIVE_REGION_ASSERTIVE = 0x00000002; 2427 2428 /** 2429 * The default whether the view is important for accessibility. 2430 */ 2431 static final int ACCESSIBILITY_LIVE_REGION_DEFAULT = ACCESSIBILITY_LIVE_REGION_NONE; 2432 2433 /** 2434 * Mask for obtaining the bits which specify a view's accessibility live 2435 * region mode. 2436 */ 2437 static final int PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK = (ACCESSIBILITY_LIVE_REGION_NONE 2438 | ACCESSIBILITY_LIVE_REGION_POLITE | ACCESSIBILITY_LIVE_REGION_ASSERTIVE) 2439 << PFLAG2_ACCESSIBILITY_LIVE_REGION_SHIFT; 2440 2441 /** 2442 * Flag indicating whether a view has accessibility focus. 2443 */ 2444 static final int PFLAG2_ACCESSIBILITY_FOCUSED = 0x04000000; 2445 2446 /** 2447 * Flag whether the accessibility state of the subtree rooted at this view changed. 2448 */ 2449 static final int PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED = 0x08000000; 2450 2451 /** 2452 * Flag indicating whether a view failed the quickReject() check in draw(). This condition 2453 * is used to check whether later changes to the view's transform should invalidate the 2454 * view to force the quickReject test to run again. 2455 */ 2456 static final int PFLAG2_VIEW_QUICK_REJECTED = 0x10000000; 2457 2458 /** 2459 * Flag indicating that start/end padding has been resolved into left/right padding 2460 * for use in measurement, layout, drawing, etc. This is set by {@link #resolvePadding()} 2461 * and checked by {@link #measure(int, int)} to determine if padding needs to be resolved 2462 * during measurement. In some special cases this is required such as when an adapter-based 2463 * view measures prospective children without attaching them to a window. 2464 */ 2465 static final int PFLAG2_PADDING_RESOLVED = 0x20000000; 2466 2467 /** 2468 * Flag indicating that the start/end drawables has been resolved into left/right ones. 2469 */ 2470 static final int PFLAG2_DRAWABLE_RESOLVED = 0x40000000; 2471 2472 /** 2473 * Indicates that the view is tracking some sort of transient state 2474 * that the app should not need to be aware of, but that the framework 2475 * should take special care to preserve. 2476 */ 2477 static final int PFLAG2_HAS_TRANSIENT_STATE = 0x80000000; 2478 2479 /** 2480 * Group of bits indicating that RTL properties resolution is done. 2481 */ 2482 static final int ALL_RTL_PROPERTIES_RESOLVED = PFLAG2_LAYOUT_DIRECTION_RESOLVED | 2483 PFLAG2_TEXT_DIRECTION_RESOLVED | 2484 PFLAG2_TEXT_ALIGNMENT_RESOLVED | 2485 PFLAG2_PADDING_RESOLVED | 2486 PFLAG2_DRAWABLE_RESOLVED; 2487 2488 // There are a couple of flags left in mPrivateFlags2 2489 2490 /* End of masks for mPrivateFlags2 */ 2491 2492 /** 2493 * Masks for mPrivateFlags3, as generated by dumpFlags(): 2494 * 2495 * |-------|-------|-------|-------| 2496 * 1 PFLAG3_VIEW_IS_ANIMATING_TRANSFORM 2497 * 1 PFLAG3_VIEW_IS_ANIMATING_ALPHA 2498 * 1 PFLAG3_IS_LAID_OUT 2499 * 1 PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT 2500 * 1 PFLAG3_CALLED_SUPER 2501 * 1 PFLAG3_APPLYING_INSETS 2502 * 1 PFLAG3_FITTING_SYSTEM_WINDOWS 2503 * 1 PFLAG3_NESTED_SCROLLING_ENABLED 2504 * 1 PFLAG3_SCROLL_INDICATOR_TOP 2505 * 1 PFLAG3_SCROLL_INDICATOR_BOTTOM 2506 * 1 PFLAG3_SCROLL_INDICATOR_LEFT 2507 * 1 PFLAG3_SCROLL_INDICATOR_RIGHT 2508 * 1 PFLAG3_SCROLL_INDICATOR_START 2509 * 1 PFLAG3_SCROLL_INDICATOR_END 2510 * 1 PFLAG3_ASSIST_BLOCKED 2511 * 1 PFLAG3_CLUSTER 2512 * x * NO LONGER NEEDED, SHOULD BE REUSED * 2513 * 1 PFLAG3_FINGER_DOWN 2514 * 1 PFLAG3_FOCUSED_BY_DEFAULT 2515 * xxxx * NO LONGER NEEDED, SHOULD BE REUSED * 2516 * 1 PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE 2517 * 1 PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED 2518 * 1 PFLAG3_TEMPORARY_DETACH 2519 * 1 PFLAG3_NO_REVEAL_ON_FOCUS 2520 * |-------|-------|-------|-------| 2521 */ 2522 2523 /** 2524 * Flag indicating that view has a transform animation set on it. This is used to track whether 2525 * an animation is cleared between successive frames, in order to tell the associated 2526 * DisplayList to clear its animation matrix. 2527 */ 2528 static final int PFLAG3_VIEW_IS_ANIMATING_TRANSFORM = 0x1; 2529 2530 /** 2531 * Flag indicating that view has an alpha animation set on it. This is used to track whether an 2532 * animation is cleared between successive frames, in order to tell the associated 2533 * DisplayList to restore its alpha value. 2534 */ 2535 static final int PFLAG3_VIEW_IS_ANIMATING_ALPHA = 0x2; 2536 2537 /** 2538 * Flag indicating that the view has been through at least one layout since it 2539 * was last attached to a window. 2540 */ 2541 static final int PFLAG3_IS_LAID_OUT = 0x4; 2542 2543 /** 2544 * Flag indicating that a call to measure() was skipped and should be done 2545 * instead when layout() is invoked. 2546 */ 2547 static final int PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT = 0x8; 2548 2549 /** 2550 * Flag indicating that an overridden method correctly called down to 2551 * the superclass implementation as required by the API spec. 2552 */ 2553 static final int PFLAG3_CALLED_SUPER = 0x10; 2554 2555 /** 2556 * Flag indicating that we're in the process of applying window insets. 2557 */ 2558 static final int PFLAG3_APPLYING_INSETS = 0x20; 2559 2560 /** 2561 * Flag indicating that we're in the process of fitting system windows using the old method. 2562 */ 2563 static final int PFLAG3_FITTING_SYSTEM_WINDOWS = 0x40; 2564 2565 /** 2566 * Flag indicating that nested scrolling is enabled for this view. 2567 * The view will optionally cooperate with views up its parent chain to allow for 2568 * integrated nested scrolling along the same axis. 2569 */ 2570 static final int PFLAG3_NESTED_SCROLLING_ENABLED = 0x80; 2571 2572 /** 2573 * Flag indicating that the bottom scroll indicator should be displayed 2574 * when this view can scroll up. 2575 */ 2576 static final int PFLAG3_SCROLL_INDICATOR_TOP = 0x0100; 2577 2578 /** 2579 * Flag indicating that the bottom scroll indicator should be displayed 2580 * when this view can scroll down. 2581 */ 2582 static final int PFLAG3_SCROLL_INDICATOR_BOTTOM = 0x0200; 2583 2584 /** 2585 * Flag indicating that the left scroll indicator should be displayed 2586 * when this view can scroll left. 2587 */ 2588 static final int PFLAG3_SCROLL_INDICATOR_LEFT = 0x0400; 2589 2590 /** 2591 * Flag indicating that the right scroll indicator should be displayed 2592 * when this view can scroll right. 2593 */ 2594 static final int PFLAG3_SCROLL_INDICATOR_RIGHT = 0x0800; 2595 2596 /** 2597 * Flag indicating that the start scroll indicator should be displayed 2598 * when this view can scroll in the start direction. 2599 */ 2600 static final int PFLAG3_SCROLL_INDICATOR_START = 0x1000; 2601 2602 /** 2603 * Flag indicating that the end scroll indicator should be displayed 2604 * when this view can scroll in the end direction. 2605 */ 2606 static final int PFLAG3_SCROLL_INDICATOR_END = 0x2000; 2607 2608 static final int DRAG_MASK = PFLAG2_DRAG_CAN_ACCEPT | PFLAG2_DRAG_HOVERED; 2609 2610 static final int SCROLL_INDICATORS_NONE = 0x0000; 2611 2612 /** 2613 * Mask for use with setFlags indicating bits used for indicating which 2614 * scroll indicators are enabled. 2615 */ 2616 static final int SCROLL_INDICATORS_PFLAG3_MASK = PFLAG3_SCROLL_INDICATOR_TOP 2617 | PFLAG3_SCROLL_INDICATOR_BOTTOM | PFLAG3_SCROLL_INDICATOR_LEFT 2618 | PFLAG3_SCROLL_INDICATOR_RIGHT | PFLAG3_SCROLL_INDICATOR_START 2619 | PFLAG3_SCROLL_INDICATOR_END; 2620 2621 /** 2622 * Left-shift required to translate between public scroll indicator flags 2623 * and internal PFLAGS3 flags. When used as a right-shift, translates 2624 * PFLAGS3 flags to public flags. 2625 */ 2626 static final int SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT = 8; 2627 2628 /** @hide */ 2629 @Retention(RetentionPolicy.SOURCE) 2630 @IntDef(flag = true, 2631 value = { 2632 SCROLL_INDICATOR_TOP, 2633 SCROLL_INDICATOR_BOTTOM, 2634 SCROLL_INDICATOR_LEFT, 2635 SCROLL_INDICATOR_RIGHT, 2636 SCROLL_INDICATOR_START, 2637 SCROLL_INDICATOR_END, 2638 }) 2639 public @interface ScrollIndicators {} 2640 2641 /** 2642 * Scroll indicator direction for the top edge of the view. 2643 * 2644 * @see #setScrollIndicators(int) 2645 * @see #setScrollIndicators(int, int) 2646 * @see #getScrollIndicators() 2647 */ 2648 public static final int SCROLL_INDICATOR_TOP = 2649 PFLAG3_SCROLL_INDICATOR_TOP >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 2650 2651 /** 2652 * Scroll indicator direction for the bottom edge of the view. 2653 * 2654 * @see #setScrollIndicators(int) 2655 * @see #setScrollIndicators(int, int) 2656 * @see #getScrollIndicators() 2657 */ 2658 public static final int SCROLL_INDICATOR_BOTTOM = 2659 PFLAG3_SCROLL_INDICATOR_BOTTOM >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 2660 2661 /** 2662 * Scroll indicator direction for the left edge of the view. 2663 * 2664 * @see #setScrollIndicators(int) 2665 * @see #setScrollIndicators(int, int) 2666 * @see #getScrollIndicators() 2667 */ 2668 public static final int SCROLL_INDICATOR_LEFT = 2669 PFLAG3_SCROLL_INDICATOR_LEFT >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 2670 2671 /** 2672 * Scroll indicator direction for the right edge of the view. 2673 * 2674 * @see #setScrollIndicators(int) 2675 * @see #setScrollIndicators(int, int) 2676 * @see #getScrollIndicators() 2677 */ 2678 public static final int SCROLL_INDICATOR_RIGHT = 2679 PFLAG3_SCROLL_INDICATOR_RIGHT >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 2680 2681 /** 2682 * Scroll indicator direction for the starting edge of the view. 2683 * <p> 2684 * Resolved according to the view's layout direction, see 2685 * {@link #getLayoutDirection()} for more information. 2686 * 2687 * @see #setScrollIndicators(int) 2688 * @see #setScrollIndicators(int, int) 2689 * @see #getScrollIndicators() 2690 */ 2691 public static final int SCROLL_INDICATOR_START = 2692 PFLAG3_SCROLL_INDICATOR_START >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 2693 2694 /** 2695 * Scroll indicator direction for the ending edge of the view. 2696 * <p> 2697 * Resolved according to the view's layout direction, see 2698 * {@link #getLayoutDirection()} for more information. 2699 * 2700 * @see #setScrollIndicators(int) 2701 * @see #setScrollIndicators(int, int) 2702 * @see #getScrollIndicators() 2703 */ 2704 public static final int SCROLL_INDICATOR_END = 2705 PFLAG3_SCROLL_INDICATOR_END >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 2706 2707 /** 2708 * <p>Indicates that we are allowing {@link ViewStructure} to traverse 2709 * into this view.<p> 2710 */ 2711 static final int PFLAG3_ASSIST_BLOCKED = 0x4000; 2712 2713 /** 2714 * Flag indicating that the view is a root of a keyboard navigation cluster. 2715 * 2716 * @see #isKeyboardNavigationCluster() 2717 * @see #setKeyboardNavigationCluster(boolean) 2718 */ 2719 private static final int PFLAG3_CLUSTER = 0x8000; 2720 2721 /** 2722 * Indicates that the user is currently touching the screen. 2723 * Currently used for the tooltip positioning only. 2724 */ 2725 private static final int PFLAG3_FINGER_DOWN = 0x20000; 2726 2727 /** 2728 * Flag indicating that this view is the default-focus view. 2729 * 2730 * @see #isFocusedByDefault() 2731 * @see #setFocusedByDefault(boolean) 2732 */ 2733 private static final int PFLAG3_FOCUSED_BY_DEFAULT = 0x40000; 2734 2735 /** 2736 * Whether this view has rendered elements that overlap (see {@link 2737 * #hasOverlappingRendering()}, {@link #forceHasOverlappingRendering(boolean)}, and 2738 * {@link #getHasOverlappingRendering()} ). The value in this bit is only valid when 2739 * PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED has been set. Otherwise, the value is 2740 * determined by whatever {@link #hasOverlappingRendering()} returns. 2741 */ 2742 private static final int PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE = 0x800000; 2743 2744 /** 2745 * Whether {@link #forceHasOverlappingRendering(boolean)} has been called. When true, value 2746 * in PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE is valid. 2747 */ 2748 private static final int PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED = 0x1000000; 2749 2750 /** 2751 * Flag indicating that the view is temporarily detached from the parent view. 2752 * 2753 * @see #onStartTemporaryDetach() 2754 * @see #onFinishTemporaryDetach() 2755 */ 2756 static final int PFLAG3_TEMPORARY_DETACH = 0x2000000; 2757 2758 /** 2759 * Flag indicating that the view does not wish to be revealed within its parent 2760 * hierarchy when it gains focus. Expressed in the negative since the historical 2761 * default behavior is to reveal on focus; this flag suppresses that behavior. 2762 * 2763 * @see #setRevealOnFocusHint(boolean) 2764 * @see #getRevealOnFocusHint() 2765 */ 2766 private static final int PFLAG3_NO_REVEAL_ON_FOCUS = 0x4000000; 2767 2768 /* End of masks for mPrivateFlags3 */ 2769 2770 /** 2771 * Always allow a user to over-scroll this view, provided it is a 2772 * view that can scroll. 2773 * 2774 * @see #getOverScrollMode() 2775 * @see #setOverScrollMode(int) 2776 */ 2777 public static final int OVER_SCROLL_ALWAYS = 0; 2778 2779 /** 2780 * Allow a user to over-scroll this view only if the content is large 2781 * enough to meaningfully scroll, provided it is a view that can scroll. 2782 * 2783 * @see #getOverScrollMode() 2784 * @see #setOverScrollMode(int) 2785 */ 2786 public static final int OVER_SCROLL_IF_CONTENT_SCROLLS = 1; 2787 2788 /** 2789 * Never allow a user to over-scroll this view. 2790 * 2791 * @see #getOverScrollMode() 2792 * @see #setOverScrollMode(int) 2793 */ 2794 public static final int OVER_SCROLL_NEVER = 2; 2795 2796 /** 2797 * Special constant for {@link #setSystemUiVisibility(int)}: View has 2798 * requested the system UI (status bar) to be visible (the default). 2799 * 2800 * @see #setSystemUiVisibility(int) 2801 */ 2802 public static final int SYSTEM_UI_FLAG_VISIBLE = 0; 2803 2804 /** 2805 * Flag for {@link #setSystemUiVisibility(int)}: View has requested the 2806 * system UI to enter an unobtrusive "low profile" mode. 2807 * 2808 * <p>This is for use in games, book readers, video players, or any other 2809 * "immersive" application where the usual system chrome is deemed too distracting. 2810 * 2811 * <p>In low profile mode, the status bar and/or navigation icons may dim. 2812 * 2813 * @see #setSystemUiVisibility(int) 2814 */ 2815 public static final int SYSTEM_UI_FLAG_LOW_PROFILE = 0x00000001; 2816 2817 /** 2818 * Flag for {@link #setSystemUiVisibility(int)}: View has requested that the 2819 * system navigation be temporarily hidden. 2820 * 2821 * <p>This is an even less obtrusive state than that called for by 2822 * {@link #SYSTEM_UI_FLAG_LOW_PROFILE}; on devices that draw essential navigation controls 2823 * (Home, Back, and the like) on screen, <code>SYSTEM_UI_FLAG_HIDE_NAVIGATION</code> will cause 2824 * those to disappear. This is useful (in conjunction with the 2825 * {@link android.view.WindowManager.LayoutParams#FLAG_FULLSCREEN FLAG_FULLSCREEN} and 2826 * {@link android.view.WindowManager.LayoutParams#FLAG_LAYOUT_IN_SCREEN FLAG_LAYOUT_IN_SCREEN} 2827 * window flags) for displaying content using every last pixel on the display. 2828 * 2829 * <p>There is a limitation: because navigation controls are so important, the least user 2830 * interaction will cause them to reappear immediately. When this happens, both 2831 * this flag and {@link #SYSTEM_UI_FLAG_FULLSCREEN} will be cleared automatically, 2832 * so that both elements reappear at the same time. 2833 * 2834 * @see #setSystemUiVisibility(int) 2835 */ 2836 public static final int SYSTEM_UI_FLAG_HIDE_NAVIGATION = 0x00000002; 2837 2838 /** 2839 * Flag for {@link #setSystemUiVisibility(int)}: View has requested to go 2840 * into the normal fullscreen mode so that its content can take over the screen 2841 * while still allowing the user to interact with the application. 2842 * 2843 * <p>This has the same visual effect as 2844 * {@link android.view.WindowManager.LayoutParams#FLAG_FULLSCREEN 2845 * WindowManager.LayoutParams.FLAG_FULLSCREEN}, 2846 * meaning that non-critical screen decorations (such as the status bar) will be 2847 * hidden while the user is in the View's window, focusing the experience on 2848 * that content. Unlike the window flag, if you are using ActionBar in 2849 * overlay mode with {@link Window#FEATURE_ACTION_BAR_OVERLAY 2850 * Window.FEATURE_ACTION_BAR_OVERLAY}, then enabling this flag will also 2851 * hide the action bar. 2852 * 2853 * <p>This approach to going fullscreen is best used over the window flag when 2854 * it is a transient state -- that is, the application does this at certain 2855 * points in its user interaction where it wants to allow the user to focus 2856 * on content, but not as a continuous state. For situations where the application 2857 * would like to simply stay full screen the entire time (such as a game that 2858 * wants to take over the screen), the 2859 * {@link android.view.WindowManager.LayoutParams#FLAG_FULLSCREEN window flag} 2860 * is usually a better approach. The state set here will be removed by the system 2861 * in various situations (such as the user moving to another application) like 2862 * the other system UI states. 2863 * 2864 * <p>When using this flag, the application should provide some easy facility 2865 * for the user to go out of it. A common example would be in an e-book 2866 * reader, where tapping on the screen brings back whatever screen and UI 2867 * decorations that had been hidden while the user was immersed in reading 2868 * the book. 2869 * 2870 * @see #setSystemUiVisibility(int) 2871 */ 2872 public static final int SYSTEM_UI_FLAG_FULLSCREEN = 0x00000004; 2873 2874 /** 2875 * Flag for {@link #setSystemUiVisibility(int)}: When using other layout 2876 * flags, we would like a stable view of the content insets given to 2877 * {@link #fitSystemWindows(Rect)}. This means that the insets seen there 2878 * will always represent the worst case that the application can expect 2879 * as a continuous state. In the stock Android UI this is the space for 2880 * the system bar, nav bar, and status bar, but not more transient elements 2881 * such as an input method. 2882 * 2883 * The stable layout your UI sees is based on the system UI modes you can 2884 * switch to. That is, if you specify {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN} 2885 * then you will get a stable layout for changes of the 2886 * {@link #SYSTEM_UI_FLAG_FULLSCREEN} mode; if you specify 2887 * {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN} and 2888 * {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION}, then you can transition 2889 * to {@link #SYSTEM_UI_FLAG_FULLSCREEN} and {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION} 2890 * with a stable layout. (Note that you should avoid using 2891 * {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION} by itself.) 2892 * 2893 * If you have set the window flag {@link WindowManager.LayoutParams#FLAG_FULLSCREEN} 2894 * to hide the status bar (instead of using {@link #SYSTEM_UI_FLAG_FULLSCREEN}), 2895 * then a hidden status bar will be considered a "stable" state for purposes 2896 * here. This allows your UI to continually hide the status bar, while still 2897 * using the system UI flags to hide the action bar while still retaining 2898 * a stable layout. Note that changing the window fullscreen flag will never 2899 * provide a stable layout for a clean transition. 2900 * 2901 * <p>If you are using ActionBar in 2902 * overlay mode with {@link Window#FEATURE_ACTION_BAR_OVERLAY 2903 * Window.FEATURE_ACTION_BAR_OVERLAY}, this flag will also impact the 2904 * insets it adds to those given to the application. 2905 */ 2906 public static final int SYSTEM_UI_FLAG_LAYOUT_STABLE = 0x00000100; 2907 2908 /** 2909 * Flag for {@link #setSystemUiVisibility(int)}: View would like its window 2910 * to be laid out as if it has requested 2911 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, even if it currently hasn't. This 2912 * allows it to avoid artifacts when switching in and out of that mode, at 2913 * the expense that some of its user interface may be covered by screen 2914 * decorations when they are shown. You can perform layout of your inner 2915 * UI elements to account for the navigation system UI through the 2916 * {@link #fitSystemWindows(Rect)} method. 2917 */ 2918 public static final int SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION = 0x00000200; 2919 2920 /** 2921 * Flag for {@link #setSystemUiVisibility(int)}: View would like its window 2922 * to be laid out as if it has requested 2923 * {@link #SYSTEM_UI_FLAG_FULLSCREEN}, even if it currently hasn't. This 2924 * allows it to avoid artifacts when switching in and out of that mode, at 2925 * the expense that some of its user interface may be covered by screen 2926 * decorations when they are shown. You can perform layout of your inner 2927 * UI elements to account for non-fullscreen system UI through the 2928 * {@link #fitSystemWindows(Rect)} method. 2929 */ 2930 public static final int SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN = 0x00000400; 2931 2932 /** 2933 * Flag for {@link #setSystemUiVisibility(int)}: View would like to remain interactive when 2934 * hiding the navigation bar with {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}. If this flag is 2935 * not set, {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION} will be force cleared by the system on any 2936 * user interaction. 2937 * <p>Since this flag is a modifier for {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, it only 2938 * has an effect when used in combination with that flag.</p> 2939 */ 2940 public static final int SYSTEM_UI_FLAG_IMMERSIVE = 0x00000800; 2941 2942 /** 2943 * Flag for {@link #setSystemUiVisibility(int)}: View would like to remain interactive when 2944 * hiding the status bar with {@link #SYSTEM_UI_FLAG_FULLSCREEN} and/or hiding the navigation 2945 * bar with {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}. Use this flag to create an immersive 2946 * experience while also hiding the system bars. If this flag is not set, 2947 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION} will be force cleared by the system on any user 2948 * interaction, and {@link #SYSTEM_UI_FLAG_FULLSCREEN} will be force-cleared by the system 2949 * if the user swipes from the top of the screen. 2950 * <p>When system bars are hidden in immersive mode, they can be revealed temporarily with 2951 * system gestures, such as swiping from the top of the screen. These transient system bars 2952 * will overlay app’s content, may have some degree of transparency, and will automatically 2953 * hide after a short timeout. 2954 * </p><p>Since this flag is a modifier for {@link #SYSTEM_UI_FLAG_FULLSCREEN} and 2955 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, it only has an effect when used in combination 2956 * with one or both of those flags.</p> 2957 */ 2958 public static final int SYSTEM_UI_FLAG_IMMERSIVE_STICKY = 0x00001000; 2959 2960 /** 2961 * Flag for {@link #setSystemUiVisibility(int)}: Requests the status bar to draw in a mode that 2962 * is compatible with light status bar backgrounds. 2963 * 2964 * <p>For this to take effect, the window must request 2965 * {@link android.view.WindowManager.LayoutParams#FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS 2966 * FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS} but not 2967 * {@link android.view.WindowManager.LayoutParams#FLAG_TRANSLUCENT_STATUS 2968 * FLAG_TRANSLUCENT_STATUS}. 2969 * 2970 * @see android.R.attr#windowLightStatusBar 2971 */ 2972 public static final int SYSTEM_UI_FLAG_LIGHT_STATUS_BAR = 0x00002000; 2973 2974 /** 2975 * This flag was previously used for a private API. DO NOT reuse it for a public API as it might 2976 * trigger undefined behavior on older platforms with apps compiled against a new SDK. 2977 */ 2978 private static final int SYSTEM_UI_RESERVED_LEGACY1 = 0x00004000; 2979 2980 /** 2981 * This flag was previously used for a private API. DO NOT reuse it for a public API as it might 2982 * trigger undefined behavior on older platforms with apps compiled against a new SDK. 2983 */ 2984 private static final int SYSTEM_UI_RESERVED_LEGACY2 = 0x00010000; 2985 2986 /** 2987 * Flag for {@link #setSystemUiVisibility(int)}: Requests the navigation bar to draw in a mode 2988 * that is compatible with light navigation bar backgrounds. 2989 * 2990 * <p>For this to take effect, the window must request 2991 * {@link android.view.WindowManager.LayoutParams#FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS 2992 * FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS} but not 2993 * {@link android.view.WindowManager.LayoutParams#FLAG_TRANSLUCENT_NAVIGATION 2994 * FLAG_TRANSLUCENT_NAVIGATION}. 2995 */ 2996 public static final int SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR = 0x00000010; 2997 2998 /** 2999 * @deprecated Use {@link #SYSTEM_UI_FLAG_LOW_PROFILE} instead. 3000 */ 3001 @Deprecated 3002 public static final int STATUS_BAR_HIDDEN = SYSTEM_UI_FLAG_LOW_PROFILE; 3003 3004 /** 3005 * @deprecated Use {@link #SYSTEM_UI_FLAG_VISIBLE} instead. 3006 */ 3007 @Deprecated 3008 public static final int STATUS_BAR_VISIBLE = SYSTEM_UI_FLAG_VISIBLE; 3009 3010 /** 3011 * @hide 3012 * 3013 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3014 * out of the public fields to keep the undefined bits out of the developer's way. 3015 * 3016 * Flag to make the status bar not expandable. Unless you also 3017 * set {@link #STATUS_BAR_DISABLE_NOTIFICATION_ICONS}, new notifications will continue to show. 3018 */ 3019 public static final int STATUS_BAR_DISABLE_EXPAND = 0x00010000; 3020 3021 /** 3022 * @hide 3023 * 3024 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3025 * out of the public fields to keep the undefined bits out of the developer's way. 3026 * 3027 * Flag to hide notification icons and scrolling ticker text. 3028 */ 3029 public static final int STATUS_BAR_DISABLE_NOTIFICATION_ICONS = 0x00020000; 3030 3031 /** 3032 * @hide 3033 * 3034 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3035 * out of the public fields to keep the undefined bits out of the developer's way. 3036 * 3037 * Flag to disable incoming notification alerts. This will not block 3038 * icons, but it will block sound, vibrating and other visual or aural notifications. 3039 */ 3040 public static final int STATUS_BAR_DISABLE_NOTIFICATION_ALERTS = 0x00040000; 3041 3042 /** 3043 * @hide 3044 * 3045 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3046 * out of the public fields to keep the undefined bits out of the developer's way. 3047 * 3048 * Flag to hide only the scrolling ticker. Note that 3049 * {@link #STATUS_BAR_DISABLE_NOTIFICATION_ICONS} implies 3050 * {@link #STATUS_BAR_DISABLE_NOTIFICATION_TICKER}. 3051 */ 3052 public static final int STATUS_BAR_DISABLE_NOTIFICATION_TICKER = 0x00080000; 3053 3054 /** 3055 * @hide 3056 * 3057 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3058 * out of the public fields to keep the undefined bits out of the developer's way. 3059 * 3060 * Flag to hide the center system info area. 3061 */ 3062 public static final int STATUS_BAR_DISABLE_SYSTEM_INFO = 0x00100000; 3063 3064 /** 3065 * @hide 3066 * 3067 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3068 * out of the public fields to keep the undefined bits out of the developer's way. 3069 * 3070 * Flag to hide only the home button. Don't use this 3071 * unless you're a special part of the system UI (i.e., setup wizard, keyguard). 3072 */ 3073 public static final int STATUS_BAR_DISABLE_HOME = 0x00200000; 3074 3075 /** 3076 * @hide 3077 * 3078 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3079 * out of the public fields to keep the undefined bits out of the developer's way. 3080 * 3081 * Flag to hide only the back button. Don't use this 3082 * unless you're a special part of the system UI (i.e., setup wizard, keyguard). 3083 */ 3084 public static final int STATUS_BAR_DISABLE_BACK = 0x00400000; 3085 3086 /** 3087 * @hide 3088 * 3089 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3090 * out of the public fields to keep the undefined bits out of the developer's way. 3091 * 3092 * Flag to hide only the clock. You might use this if your activity has 3093 * its own clock making the status bar's clock redundant. 3094 */ 3095 public static final int STATUS_BAR_DISABLE_CLOCK = 0x00800000; 3096 3097 /** 3098 * @hide 3099 * 3100 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3101 * out of the public fields to keep the undefined bits out of the developer's way. 3102 * 3103 * Flag to hide only the recent apps button. Don't use this 3104 * unless you're a special part of the system UI (i.e., setup wizard, keyguard). 3105 */ 3106 public static final int STATUS_BAR_DISABLE_RECENT = 0x01000000; 3107 3108 /** 3109 * @hide 3110 * 3111 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3112 * out of the public fields to keep the undefined bits out of the developer's way. 3113 * 3114 * Flag to disable the global search gesture. Don't use this 3115 * unless you're a special part of the system UI (i.e., setup wizard, keyguard). 3116 */ 3117 public static final int STATUS_BAR_DISABLE_SEARCH = 0x02000000; 3118 3119 /** 3120 * @hide 3121 * 3122 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3123 * out of the public fields to keep the undefined bits out of the developer's way. 3124 * 3125 * Flag to specify that the status bar is displayed in transient mode. 3126 */ 3127 public static final int STATUS_BAR_TRANSIENT = 0x04000000; 3128 3129 /** 3130 * @hide 3131 * 3132 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3133 * out of the public fields to keep the undefined bits out of the developer's way. 3134 * 3135 * Flag to specify that the navigation bar is displayed in transient mode. 3136 */ 3137 public static final int NAVIGATION_BAR_TRANSIENT = 0x08000000; 3138 3139 /** 3140 * @hide 3141 * 3142 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3143 * out of the public fields to keep the undefined bits out of the developer's way. 3144 * 3145 * Flag to specify that the hidden status bar would like to be shown. 3146 */ 3147 public static final int STATUS_BAR_UNHIDE = 0x10000000; 3148 3149 /** 3150 * @hide 3151 * 3152 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3153 * out of the public fields to keep the undefined bits out of the developer's way. 3154 * 3155 * Flag to specify that the hidden navigation bar would like to be shown. 3156 */ 3157 public static final int NAVIGATION_BAR_UNHIDE = 0x20000000; 3158 3159 /** 3160 * @hide 3161 * 3162 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3163 * out of the public fields to keep the undefined bits out of the developer's way. 3164 * 3165 * Flag to specify that the status bar is displayed in translucent mode. 3166 */ 3167 public static final int STATUS_BAR_TRANSLUCENT = 0x40000000; 3168 3169 /** 3170 * @hide 3171 * 3172 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3173 * out of the public fields to keep the undefined bits out of the developer's way. 3174 * 3175 * Flag to specify that the navigation bar is displayed in translucent mode. 3176 */ 3177 public static final int NAVIGATION_BAR_TRANSLUCENT = 0x80000000; 3178 3179 /** 3180 * @hide 3181 * 3182 * Makes navigation bar transparent (but not the status bar). 3183 */ 3184 public static final int NAVIGATION_BAR_TRANSPARENT = 0x00008000; 3185 3186 /** 3187 * @hide 3188 * 3189 * Makes status bar transparent (but not the navigation bar). 3190 */ 3191 public static final int STATUS_BAR_TRANSPARENT = 0x00000008; 3192 3193 /** 3194 * @hide 3195 * 3196 * Makes both status bar and navigation bar transparent. 3197 */ 3198 public static final int SYSTEM_UI_TRANSPARENT = NAVIGATION_BAR_TRANSPARENT 3199 | STATUS_BAR_TRANSPARENT; 3200 3201 /** 3202 * @hide 3203 */ 3204 public static final int PUBLIC_STATUS_BAR_VISIBILITY_MASK = 0x00003FF7; 3205 3206 /** 3207 * These are the system UI flags that can be cleared by events outside 3208 * of an application. Currently this is just the ability to tap on the 3209 * screen while hiding the navigation bar to have it return. 3210 * @hide 3211 */ 3212 public static final int SYSTEM_UI_CLEARABLE_FLAGS = 3213 SYSTEM_UI_FLAG_LOW_PROFILE | SYSTEM_UI_FLAG_HIDE_NAVIGATION 3214 | SYSTEM_UI_FLAG_FULLSCREEN; 3215 3216 /** 3217 * Flags that can impact the layout in relation to system UI. 3218 */ 3219 public static final int SYSTEM_UI_LAYOUT_FLAGS = 3220 SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION 3221 | SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN; 3222 3223 /** @hide */ 3224 @IntDef(flag = true, 3225 value = { FIND_VIEWS_WITH_TEXT, FIND_VIEWS_WITH_CONTENT_DESCRIPTION }) 3226 @Retention(RetentionPolicy.SOURCE) 3227 public @interface FindViewFlags {} 3228 3229 /** 3230 * Find views that render the specified text. 3231 * 3232 * @see #findViewsWithText(ArrayList, CharSequence, int) 3233 */ 3234 public static final int FIND_VIEWS_WITH_TEXT = 0x00000001; 3235 3236 /** 3237 * Find find views that contain the specified content description. 3238 * 3239 * @see #findViewsWithText(ArrayList, CharSequence, int) 3240 */ 3241 public static final int FIND_VIEWS_WITH_CONTENT_DESCRIPTION = 0x00000002; 3242 3243 /** 3244 * Find views that contain {@link AccessibilityNodeProvider}. Such 3245 * a View is a root of virtual view hierarchy and may contain the searched 3246 * text. If this flag is set Views with providers are automatically 3247 * added and it is a responsibility of the client to call the APIs of 3248 * the provider to determine whether the virtual tree rooted at this View 3249 * contains the text, i.e. getting the list of {@link AccessibilityNodeInfo}s 3250 * representing the virtual views with this text. 3251 * 3252 * @see #findViewsWithText(ArrayList, CharSequence, int) 3253 * 3254 * @hide 3255 */ 3256 public static final int FIND_VIEWS_WITH_ACCESSIBILITY_NODE_PROVIDERS = 0x00000004; 3257 3258 /** 3259 * The undefined cursor position. 3260 * 3261 * @hide 3262 */ 3263 public static final int ACCESSIBILITY_CURSOR_POSITION_UNDEFINED = -1; 3264 3265 /** 3266 * Indicates that the screen has changed state and is now off. 3267 * 3268 * @see #onScreenStateChanged(int) 3269 */ 3270 public static final int SCREEN_STATE_OFF = 0x0; 3271 3272 /** 3273 * Indicates that the screen has changed state and is now on. 3274 * 3275 * @see #onScreenStateChanged(int) 3276 */ 3277 public static final int SCREEN_STATE_ON = 0x1; 3278 3279 /** 3280 * Indicates no axis of view scrolling. 3281 */ 3282 public static final int SCROLL_AXIS_NONE = 0; 3283 3284 /** 3285 * Indicates scrolling along the horizontal axis. 3286 */ 3287 public static final int SCROLL_AXIS_HORIZONTAL = 1 << 0; 3288 3289 /** 3290 * Indicates scrolling along the vertical axis. 3291 */ 3292 public static final int SCROLL_AXIS_VERTICAL = 1 << 1; 3293 3294 /** 3295 * Controls the over-scroll mode for this view. 3296 * See {@link #overScrollBy(int, int, int, int, int, int, int, int, boolean)}, 3297 * {@link #OVER_SCROLL_ALWAYS}, {@link #OVER_SCROLL_IF_CONTENT_SCROLLS}, 3298 * and {@link #OVER_SCROLL_NEVER}. 3299 */ 3300 private int mOverScrollMode; 3301 3302 /** 3303 * The parent this view is attached to. 3304 * {@hide} 3305 * 3306 * @see #getParent() 3307 */ 3308 protected ViewParent mParent; 3309 3310 /** 3311 * {@hide} 3312 */ 3313 AttachInfo mAttachInfo; 3314 3315 /** 3316 * {@hide} 3317 */ 3318 @ViewDebug.ExportedProperty(flagMapping = { 3319 @ViewDebug.FlagToString(mask = PFLAG_FORCE_LAYOUT, equals = PFLAG_FORCE_LAYOUT, 3320 name = "FORCE_LAYOUT"), 3321 @ViewDebug.FlagToString(mask = PFLAG_LAYOUT_REQUIRED, equals = PFLAG_LAYOUT_REQUIRED, 3322 name = "LAYOUT_REQUIRED"), 3323 @ViewDebug.FlagToString(mask = PFLAG_DRAWING_CACHE_VALID, equals = PFLAG_DRAWING_CACHE_VALID, 3324 name = "DRAWING_CACHE_INVALID", outputIf = false), 3325 @ViewDebug.FlagToString(mask = PFLAG_DRAWN, equals = PFLAG_DRAWN, name = "DRAWN", outputIf = true), 3326 @ViewDebug.FlagToString(mask = PFLAG_DRAWN, equals = PFLAG_DRAWN, name = "NOT_DRAWN", outputIf = false), 3327 @ViewDebug.FlagToString(mask = PFLAG_DIRTY_MASK, equals = PFLAG_DIRTY_OPAQUE, name = "DIRTY_OPAQUE"), 3328 @ViewDebug.FlagToString(mask = PFLAG_DIRTY_MASK, equals = PFLAG_DIRTY, name = "DIRTY") 3329 }, formatToHexString = true) 3330 3331 /* @hide */ 3332 public int mPrivateFlags; 3333 int mPrivateFlags2; 3334 int mPrivateFlags3; 3335 3336 /** 3337 * This view's request for the visibility of the status bar. 3338 * @hide 3339 */ 3340 @ViewDebug.ExportedProperty(flagMapping = { 3341 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_LOW_PROFILE, 3342 equals = SYSTEM_UI_FLAG_LOW_PROFILE, 3343 name = "SYSTEM_UI_FLAG_LOW_PROFILE", outputIf = true), 3344 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_HIDE_NAVIGATION, 3345 equals = SYSTEM_UI_FLAG_HIDE_NAVIGATION, 3346 name = "SYSTEM_UI_FLAG_HIDE_NAVIGATION", outputIf = true), 3347 @ViewDebug.FlagToString(mask = PUBLIC_STATUS_BAR_VISIBILITY_MASK, 3348 equals = SYSTEM_UI_FLAG_VISIBLE, 3349 name = "SYSTEM_UI_FLAG_VISIBLE", outputIf = true) 3350 }, formatToHexString = true) 3351 int mSystemUiVisibility; 3352 3353 /** 3354 * Reference count for transient state. 3355 * @see #setHasTransientState(boolean) 3356 */ 3357 int mTransientStateCount = 0; 3358 3359 /** 3360 * Count of how many windows this view has been attached to. 3361 */ 3362 int mWindowAttachCount; 3363 3364 /** 3365 * The layout parameters associated with this view and used by the parent 3366 * {@link android.view.ViewGroup} to determine how this view should be 3367 * laid out. 3368 * {@hide} 3369 */ 3370 protected ViewGroup.LayoutParams mLayoutParams; 3371 3372 /** 3373 * The view flags hold various views states. 3374 * {@hide} 3375 */ 3376 @ViewDebug.ExportedProperty(formatToHexString = true) 3377 int mViewFlags; 3378 3379 static class TransformationInfo { 3380 /** 3381 * The transform matrix for the View. This transform is calculated internally 3382 * based on the translation, rotation, and scale properties. 3383 * 3384 * Do *not* use this variable directly; instead call getMatrix(), which will 3385 * load the value from the View's RenderNode. 3386 */ 3387 private final Matrix mMatrix = new Matrix(); 3388 3389 /** 3390 * The inverse transform matrix for the View. This transform is calculated 3391 * internally based on the translation, rotation, and scale properties. 3392 * 3393 * Do *not* use this variable directly; instead call getInverseMatrix(), 3394 * which will load the value from the View's RenderNode. 3395 */ 3396 private Matrix mInverseMatrix; 3397 3398 /** 3399 * The opacity of the View. This is a value from 0 to 1, where 0 means 3400 * completely transparent and 1 means completely opaque. 3401 */ 3402 @ViewDebug.ExportedProperty 3403 float mAlpha = 1f; 3404 3405 /** 3406 * The opacity of the view as manipulated by the Fade transition. This is a hidden 3407 * property only used by transitions, which is composited with the other alpha 3408 * values to calculate the final visual alpha value. 3409 */ 3410 float mTransitionAlpha = 1f; 3411 } 3412 3413 /** @hide */ 3414 public TransformationInfo mTransformationInfo; 3415 3416 /** 3417 * Current clip bounds. to which all drawing of this view are constrained. 3418 */ 3419 Rect mClipBounds = null; 3420 3421 private boolean mLastIsOpaque; 3422 3423 /** 3424 * The distance in pixels from the left edge of this view's parent 3425 * to the left edge of this view. 3426 * {@hide} 3427 */ 3428 @ViewDebug.ExportedProperty(category = "layout") 3429 protected int mLeft; 3430 /** 3431 * The distance in pixels from the left edge of this view's parent 3432 * to the right edge of this view. 3433 * {@hide} 3434 */ 3435 @ViewDebug.ExportedProperty(category = "layout") 3436 protected int mRight; 3437 /** 3438 * The distance in pixels from the top edge of this view's parent 3439 * to the top edge of this view. 3440 * {@hide} 3441 */ 3442 @ViewDebug.ExportedProperty(category = "layout") 3443 protected int mTop; 3444 /** 3445 * The distance in pixels from the top edge of this view's parent 3446 * to the bottom edge of this view. 3447 * {@hide} 3448 */ 3449 @ViewDebug.ExportedProperty(category = "layout") 3450 protected int mBottom; 3451 3452 /** 3453 * The offset, in pixels, by which the content of this view is scrolled 3454 * horizontally. 3455 * {@hide} 3456 */ 3457 @ViewDebug.ExportedProperty(category = "scrolling") 3458 protected int mScrollX; 3459 /** 3460 * The offset, in pixels, by which the content of this view is scrolled 3461 * vertically. 3462 * {@hide} 3463 */ 3464 @ViewDebug.ExportedProperty(category = "scrolling") 3465 protected int mScrollY; 3466 3467 /** 3468 * The left padding in pixels, that is the distance in pixels between the 3469 * left edge of this view and the left edge of its content. 3470 * {@hide} 3471 */ 3472 @ViewDebug.ExportedProperty(category = "padding") 3473 protected int mPaddingLeft = 0; 3474 /** 3475 * The right padding in pixels, that is the distance in pixels between the 3476 * right edge of this view and the right edge of its content. 3477 * {@hide} 3478 */ 3479 @ViewDebug.ExportedProperty(category = "padding") 3480 protected int mPaddingRight = 0; 3481 /** 3482 * The top padding in pixels, that is the distance in pixels between the 3483 * top edge of this view and the top edge of its content. 3484 * {@hide} 3485 */ 3486 @ViewDebug.ExportedProperty(category = "padding") 3487 protected int mPaddingTop; 3488 /** 3489 * The bottom padding in pixels, that is the distance in pixels between the 3490 * bottom edge of this view and the bottom edge of its content. 3491 * {@hide} 3492 */ 3493 @ViewDebug.ExportedProperty(category = "padding") 3494 protected int mPaddingBottom; 3495 3496 /** 3497 * The layout insets in pixels, that is the distance in pixels between the 3498 * visible edges of this view its bounds. 3499 */ 3500 private Insets mLayoutInsets; 3501 3502 /** 3503 * Briefly describes the view and is primarily used for accessibility support. 3504 */ 3505 private CharSequence mContentDescription; 3506 3507 /** 3508 * Specifies the id of a view for which this view serves as a label for 3509 * accessibility purposes. 3510 */ 3511 private int mLabelForId = View.NO_ID; 3512 3513 /** 3514 * Predicate for matching labeled view id with its label for 3515 * accessibility purposes. 3516 */ 3517 private MatchLabelForPredicate mMatchLabelForPredicate; 3518 3519 /** 3520 * Specifies a view before which this one is visited in accessibility traversal. 3521 */ 3522 private int mAccessibilityTraversalBeforeId = NO_ID; 3523 3524 /** 3525 * Specifies a view after which this one is visited in accessibility traversal. 3526 */ 3527 private int mAccessibilityTraversalAfterId = NO_ID; 3528 3529 /** 3530 * Predicate for matching a view by its id. 3531 */ 3532 private MatchIdPredicate mMatchIdPredicate; 3533 3534 /** 3535 * Cache the paddingRight set by the user to append to the scrollbar's size. 3536 * 3537 * @hide 3538 */ 3539 @ViewDebug.ExportedProperty(category = "padding") 3540 protected int mUserPaddingRight; 3541 3542 /** 3543 * Cache the paddingBottom set by the user to append to the scrollbar's size. 3544 * 3545 * @hide 3546 */ 3547 @ViewDebug.ExportedProperty(category = "padding") 3548 protected int mUserPaddingBottom; 3549 3550 /** 3551 * Cache the paddingLeft set by the user to append to the scrollbar's size. 3552 * 3553 * @hide 3554 */ 3555 @ViewDebug.ExportedProperty(category = "padding") 3556 protected int mUserPaddingLeft; 3557 3558 /** 3559 * Cache the paddingStart set by the user to append to the scrollbar's size. 3560 * 3561 */ 3562 @ViewDebug.ExportedProperty(category = "padding") 3563 int mUserPaddingStart; 3564 3565 /** 3566 * Cache the paddingEnd set by the user to append to the scrollbar's size. 3567 * 3568 */ 3569 @ViewDebug.ExportedProperty(category = "padding") 3570 int mUserPaddingEnd; 3571 3572 /** 3573 * Cache initial left padding. 3574 * 3575 * @hide 3576 */ 3577 int mUserPaddingLeftInitial; 3578 3579 /** 3580 * Cache initial right padding. 3581 * 3582 * @hide 3583 */ 3584 int mUserPaddingRightInitial; 3585 3586 /** 3587 * Default undefined padding 3588 */ 3589 private static final int UNDEFINED_PADDING = Integer.MIN_VALUE; 3590 3591 /** 3592 * Cache if a left padding has been defined 3593 */ 3594 private boolean mLeftPaddingDefined = false; 3595 3596 /** 3597 * Cache if a right padding has been defined 3598 */ 3599 private boolean mRightPaddingDefined = false; 3600 3601 /** 3602 * @hide 3603 */ 3604 int mOldWidthMeasureSpec = Integer.MIN_VALUE; 3605 /** 3606 * @hide 3607 */ 3608 int mOldHeightMeasureSpec = Integer.MIN_VALUE; 3609 3610 private LongSparseLongArray mMeasureCache; 3611 3612 @ViewDebug.ExportedProperty(deepExport = true, prefix = "bg_") 3613 private Drawable mBackground; 3614 private TintInfo mBackgroundTint; 3615 3616 @ViewDebug.ExportedProperty(deepExport = true, prefix = "fg_") 3617 private ForegroundInfo mForegroundInfo; 3618 3619 private Drawable mScrollIndicatorDrawable; 3620 3621 /** 3622 * RenderNode used for backgrounds. 3623 * <p> 3624 * When non-null and valid, this is expected to contain an up-to-date copy 3625 * of the background drawable. It is cleared on temporary detach, and reset 3626 * on cleanup. 3627 */ 3628 private RenderNode mBackgroundRenderNode; 3629 3630 private int mBackgroundResource; 3631 private boolean mBackgroundSizeChanged; 3632 3633 private String mTransitionName; 3634 3635 static class TintInfo { 3636 ColorStateList mTintList; 3637 PorterDuff.Mode mTintMode; 3638 boolean mHasTintMode; 3639 boolean mHasTintList; 3640 } 3641 3642 private static class ForegroundInfo { 3643 private Drawable mDrawable; 3644 private TintInfo mTintInfo; 3645 private int mGravity = Gravity.FILL; 3646 private boolean mInsidePadding = true; 3647 private boolean mBoundsChanged = true; 3648 private final Rect mSelfBounds = new Rect(); 3649 private final Rect mOverlayBounds = new Rect(); 3650 } 3651 3652 static class ListenerInfo { 3653 /** 3654 * Listener used to dispatch focus change events. 3655 * This field should be made private, so it is hidden from the SDK. 3656 * {@hide} 3657 */ 3658 protected OnFocusChangeListener mOnFocusChangeListener; 3659 3660 /** 3661 * Listeners for layout change events. 3662 */ 3663 private ArrayList<OnLayoutChangeListener> mOnLayoutChangeListeners; 3664 3665 protected OnScrollChangeListener mOnScrollChangeListener; 3666 3667 /** 3668 * Listeners for attach events. 3669 */ 3670 private CopyOnWriteArrayList<OnAttachStateChangeListener> mOnAttachStateChangeListeners; 3671 3672 /** 3673 * Listener used to dispatch click events. 3674 * This field should be made private, so it is hidden from the SDK. 3675 * {@hide} 3676 */ 3677 public OnClickListener mOnClickListener; 3678 3679 /** 3680 * Listener used to dispatch long click events. 3681 * This field should be made private, so it is hidden from the SDK. 3682 * {@hide} 3683 */ 3684 protected OnLongClickListener mOnLongClickListener; 3685 3686 /** 3687 * Listener used to dispatch context click events. This field should be made private, so it 3688 * is hidden from the SDK. 3689 * {@hide} 3690 */ 3691 protected OnContextClickListener mOnContextClickListener; 3692 3693 /** 3694 * Listener used to build the context menu. 3695 * This field should be made private, so it is hidden from the SDK. 3696 * {@hide} 3697 */ 3698 protected OnCreateContextMenuListener mOnCreateContextMenuListener; 3699 3700 private OnKeyListener mOnKeyListener; 3701 3702 private OnTouchListener mOnTouchListener; 3703 3704 private OnHoverListener mOnHoverListener; 3705 3706 private OnGenericMotionListener mOnGenericMotionListener; 3707 3708 private OnDragListener mOnDragListener; 3709 3710 private OnSystemUiVisibilityChangeListener mOnSystemUiVisibilityChangeListener; 3711 3712 OnApplyWindowInsetsListener mOnApplyWindowInsetsListener; 3713 3714 OnCapturedPointerListener mOnCapturedPointerListener; 3715 } 3716 3717 ListenerInfo mListenerInfo; 3718 3719 private static class TooltipInfo { 3720 /** 3721 * Text to be displayed in a tooltip popup. 3722 */ 3723 @Nullable 3724 CharSequence mTooltipText; 3725 3726 /** 3727 * View-relative position of the tooltip anchor point. 3728 */ 3729 int mAnchorX; 3730 int mAnchorY; 3731 3732 /** 3733 * The tooltip popup. 3734 */ 3735 @Nullable 3736 TooltipPopup mTooltipPopup; 3737 3738 /** 3739 * Set to true if the tooltip was shown as a result of a long click. 3740 */ 3741 boolean mTooltipFromLongClick; 3742 3743 /** 3744 * Keep these Runnables so that they can be used to reschedule. 3745 */ 3746 Runnable mShowTooltipRunnable; 3747 Runnable mHideTooltipRunnable; 3748 } 3749 3750 TooltipInfo mTooltipInfo; 3751 3752 // Temporary values used to hold (x,y) coordinates when delegating from the 3753 // two-arg performLongClick() method to the legacy no-arg version. 3754 private float mLongClickX = Float.NaN; 3755 private float mLongClickY = Float.NaN; 3756 3757 /** 3758 * The application environment this view lives in. 3759 * This field should be made private, so it is hidden from the SDK. 3760 * {@hide} 3761 */ 3762 @ViewDebug.ExportedProperty(deepExport = true) 3763 protected Context mContext; 3764 3765 private final Resources mResources; 3766 3767 private ScrollabilityCache mScrollCache; 3768 3769 private int[] mDrawableState = null; 3770 3771 ViewOutlineProvider mOutlineProvider = ViewOutlineProvider.BACKGROUND; 3772 3773 /** 3774 * Animator that automatically runs based on state changes. 3775 */ 3776 private StateListAnimator mStateListAnimator; 3777 3778 /** 3779 * When this view has focus and the next focus is {@link #FOCUS_LEFT}, 3780 * the user may specify which view to go to next. 3781 */ 3782 private int mNextFocusLeftId = View.NO_ID; 3783 3784 /** 3785 * When this view has focus and the next focus is {@link #FOCUS_RIGHT}, 3786 * the user may specify which view to go to next. 3787 */ 3788 private int mNextFocusRightId = View.NO_ID; 3789 3790 /** 3791 * When this view has focus and the next focus is {@link #FOCUS_UP}, 3792 * the user may specify which view to go to next. 3793 */ 3794 private int mNextFocusUpId = View.NO_ID; 3795 3796 /** 3797 * When this view has focus and the next focus is {@link #FOCUS_DOWN}, 3798 * the user may specify which view to go to next. 3799 */ 3800 private int mNextFocusDownId = View.NO_ID; 3801 3802 /** 3803 * When this view has focus and the next focus is {@link #FOCUS_FORWARD}, 3804 * the user may specify which view to go to next. 3805 */ 3806 int mNextFocusForwardId = View.NO_ID; 3807 3808 /** 3809 * User-specified next keyboard navigation cluster. 3810 */ 3811 int mNextClusterForwardId = View.NO_ID; 3812 3813 private CheckForLongPress mPendingCheckForLongPress; 3814 private CheckForTap mPendingCheckForTap = null; 3815 private PerformClick mPerformClick; 3816 private SendViewScrolledAccessibilityEvent mSendViewScrolledAccessibilityEvent; 3817 3818 private UnsetPressedState mUnsetPressedState; 3819 3820 /** 3821 * Whether the long press's action has been invoked. The tap's action is invoked on the 3822 * up event while a long press is invoked as soon as the long press duration is reached, so 3823 * a long press could be performed before the tap is checked, in which case the tap's action 3824 * should not be invoked. 3825 */ 3826 private boolean mHasPerformedLongPress; 3827 3828 /** 3829 * Whether a context click button is currently pressed down. This is true when the stylus is 3830 * touching the screen and the primary button has been pressed, or if a mouse's right button is 3831 * pressed. This is false once the button is released or if the stylus has been lifted. 3832 */ 3833 private boolean mInContextButtonPress; 3834 3835 /** 3836 * Whether the next up event should be ignored for the purposes of gesture recognition. This is 3837 * true after a stylus button press has occured, when the next up event should not be recognized 3838 * as a tap. 3839 */ 3840 private boolean mIgnoreNextUpEvent; 3841 3842 /** 3843 * The minimum height of the view. We'll try our best to have the height 3844 * of this view to at least this amount. 3845 */ 3846 @ViewDebug.ExportedProperty(category = "measurement") 3847 private int mMinHeight; 3848 3849 /** 3850 * The minimum width of the view. We'll try our best to have the width 3851 * of this view to at least this amount. 3852 */ 3853 @ViewDebug.ExportedProperty(category = "measurement") 3854 private int mMinWidth; 3855 3856 /** 3857 * The delegate to handle touch events that are physically in this view 3858 * but should be handled by another view. 3859 */ 3860 private TouchDelegate mTouchDelegate = null; 3861 3862 /** 3863 * Solid color to use as a background when creating the drawing cache. Enables 3864 * the cache to use 16 bit bitmaps instead of 32 bit. 3865 */ 3866 private int mDrawingCacheBackgroundColor = 0; 3867 3868 /** 3869 * Special tree observer used when mAttachInfo is null. 3870 */ 3871 private ViewTreeObserver mFloatingTreeObserver; 3872 3873 /** 3874 * Cache the touch slop from the context that created the view. 3875 */ 3876 private int mTouchSlop; 3877 3878 /** 3879 * Object that handles automatic animation of view properties. 3880 */ 3881 private ViewPropertyAnimator mAnimator = null; 3882 3883 /** 3884 * List of registered FrameMetricsObservers. 3885 */ 3886 private ArrayList<FrameMetricsObserver> mFrameMetricsObservers; 3887 3888 /** 3889 * Flag indicating that a drag can cross window boundaries. When 3890 * {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, int)} is called 3891 * with this flag set, all visible applications with targetSdkVersion >= 3892 * {@link android.os.Build.VERSION_CODES#N API 24} will be able to participate 3893 * in the drag operation and receive the dragged content. 3894 * 3895 * <p>If this is the only flag set, then the drag recipient will only have access to text data 3896 * and intents contained in the {@link ClipData} object. Access to URIs contained in the 3897 * {@link ClipData} is determined by other DRAG_FLAG_GLOBAL_* flags</p> 3898 */ 3899 public static final int DRAG_FLAG_GLOBAL = 1 << 8; // 256 3900 3901 /** 3902 * When this flag is used with {@link #DRAG_FLAG_GLOBAL}, the drag recipient will be able to 3903 * request read access to the content URI(s) contained in the {@link ClipData} object. 3904 * @see android.content.Intent.FLAG_GRANT_READ_URI_PERMISSION 3905 */ 3906 public static final int DRAG_FLAG_GLOBAL_URI_READ = Intent.FLAG_GRANT_READ_URI_PERMISSION; 3907 3908 /** 3909 * When this flag is used with {@link #DRAG_FLAG_GLOBAL}, the drag recipient will be able to 3910 * request write access to the content URI(s) contained in the {@link ClipData} object. 3911 * @see android.content.Intent.FLAG_GRANT_WRITE_URI_PERMISSION 3912 */ 3913 public static final int DRAG_FLAG_GLOBAL_URI_WRITE = Intent.FLAG_GRANT_WRITE_URI_PERMISSION; 3914 3915 /** 3916 * When this flag is used with {@link #DRAG_FLAG_GLOBAL_URI_READ} and/or {@link 3917 * #DRAG_FLAG_GLOBAL_URI_WRITE}, the URI permission grant can be persisted across device 3918 * reboots until explicitly revoked with 3919 * {@link android.content.Context#revokeUriPermission(Uri,int) Context.revokeUriPermission}. 3920 * @see android.content.Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION 3921 */ 3922 public static final int DRAG_FLAG_GLOBAL_PERSISTABLE_URI_PERMISSION = 3923 Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION; 3924 3925 /** 3926 * When this flag is used with {@link #DRAG_FLAG_GLOBAL_URI_READ} and/or {@link 3927 * #DRAG_FLAG_GLOBAL_URI_WRITE}, the URI permission grant applies to any URI that is a prefix 3928 * match against the original granted URI. 3929 * @see android.content.Intent.FLAG_GRANT_PREFIX_URI_PERMISSION 3930 */ 3931 public static final int DRAG_FLAG_GLOBAL_PREFIX_URI_PERMISSION = 3932 Intent.FLAG_GRANT_PREFIX_URI_PERMISSION; 3933 3934 /** 3935 * Flag indicating that the drag shadow will be opaque. When 3936 * {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, int)} is called 3937 * with this flag set, the drag shadow will be opaque, otherwise, it will be semitransparent. 3938 */ 3939 public static final int DRAG_FLAG_OPAQUE = 1 << 9; 3940 3941 /** 3942 * Vertical scroll factor cached by {@link #getVerticalScrollFactor}. 3943 */ 3944 private float mVerticalScrollFactor; 3945 3946 /** 3947 * Position of the vertical scroll bar. 3948 */ 3949 private int mVerticalScrollbarPosition; 3950 3951 /** 3952 * Position the scroll bar at the default position as determined by the system. 3953 */ 3954 public static final int SCROLLBAR_POSITION_DEFAULT = 0; 3955 3956 /** 3957 * Position the scroll bar along the left edge. 3958 */ 3959 public static final int SCROLLBAR_POSITION_LEFT = 1; 3960 3961 /** 3962 * Position the scroll bar along the right edge. 3963 */ 3964 public static final int SCROLLBAR_POSITION_RIGHT = 2; 3965 3966 /** 3967 * Indicates that the view does not have a layer. 3968 * 3969 * @see #getLayerType() 3970 * @see #setLayerType(int, android.graphics.Paint) 3971 * @see #LAYER_TYPE_SOFTWARE 3972 * @see #LAYER_TYPE_HARDWARE 3973 */ 3974 public static final int LAYER_TYPE_NONE = 0; 3975 3976 /** 3977 * <p>Indicates that the view has a software layer. A software layer is backed 3978 * by a bitmap and causes the view to be rendered using Android's software 3979 * rendering pipeline, even if hardware acceleration is enabled.</p> 3980 * 3981 * <p>Software layers have various usages:</p> 3982 * <p>When the application is not using hardware acceleration, a software layer 3983 * is useful to apply a specific color filter and/or blending mode and/or 3984 * translucency to a view and all its children.</p> 3985 * <p>When the application is using hardware acceleration, a software layer 3986 * is useful to render drawing primitives not supported by the hardware 3987 * accelerated pipeline. It can also be used to cache a complex view tree 3988 * into a texture and reduce the complexity of drawing operations. For instance, 3989 * when animating a complex view tree with a translation, a software layer can 3990 * be used to render the view tree only once.</p> 3991 * <p>Software layers should be avoided when the affected view tree updates 3992 * often. Every update will require to re-render the software layer, which can 3993 * potentially be slow (particularly when hardware acceleration is turned on 3994 * since the layer will have to be uploaded into a hardware texture after every 3995 * update.)</p> 3996 * 3997 * @see #getLayerType() 3998 * @see #setLayerType(int, android.graphics.Paint) 3999 * @see #LAYER_TYPE_NONE 4000 * @see #LAYER_TYPE_HARDWARE 4001 */ 4002 public static final int LAYER_TYPE_SOFTWARE = 1; 4003 4004 /** 4005 * <p>Indicates that the view has a hardware layer. A hardware layer is backed 4006 * by a hardware specific texture (generally Frame Buffer Objects or FBO on 4007 * OpenGL hardware) and causes the view to be rendered using Android's hardware 4008 * rendering pipeline, but only if hardware acceleration is turned on for the 4009 * view hierarchy. When hardware acceleration is turned off, hardware layers 4010 * behave exactly as {@link #LAYER_TYPE_SOFTWARE software layers}.</p> 4011 * 4012 * <p>A hardware layer is useful to apply a specific color filter and/or 4013 * blending mode and/or translucency to a view and all its children.</p> 4014 * <p>A hardware layer can be used to cache a complex view tree into a 4015 * texture and reduce the complexity of drawing operations. For instance, 4016 * when animating a complex view tree with a translation, a hardware layer can 4017 * be used to render the view tree only once.</p> 4018 * <p>A hardware layer can also be used to increase the rendering quality when 4019 * rotation transformations are applied on a view. It can also be used to 4020 * prevent potential clipping issues when applying 3D transforms on a view.</p> 4021 * 4022 * @see #getLayerType() 4023 * @see #setLayerType(int, android.graphics.Paint) 4024 * @see #LAYER_TYPE_NONE 4025 * @see #LAYER_TYPE_SOFTWARE 4026 */ 4027 public static final int LAYER_TYPE_HARDWARE = 2; 4028 4029 @ViewDebug.ExportedProperty(category = "drawing", mapping = { 4030 @ViewDebug.IntToString(from = LAYER_TYPE_NONE, to = "NONE"), 4031 @ViewDebug.IntToString(from = LAYER_TYPE_SOFTWARE, to = "SOFTWARE"), 4032 @ViewDebug.IntToString(from = LAYER_TYPE_HARDWARE, to = "HARDWARE") 4033 }) 4034 int mLayerType = LAYER_TYPE_NONE; 4035 Paint mLayerPaint; 4036 4037 /** 4038 * Set to true when drawing cache is enabled and cannot be created. 4039 * 4040 * @hide 4041 */ 4042 public boolean mCachingFailed; 4043 private Bitmap mDrawingCache; 4044 private Bitmap mUnscaledDrawingCache; 4045 4046 /** 4047 * RenderNode holding View properties, potentially holding a DisplayList of View content. 4048 * <p> 4049 * When non-null and valid, this is expected to contain an up-to-date copy 4050 * of the View content. Its DisplayList content is cleared on temporary detach and reset on 4051 * cleanup. 4052 */ 4053 final RenderNode mRenderNode; 4054 4055 /** 4056 * Set to true when the view is sending hover accessibility events because it 4057 * is the innermost hovered view. 4058 */ 4059 private boolean mSendingHoverAccessibilityEvents; 4060 4061 /** 4062 * Delegate for injecting accessibility functionality. 4063 */ 4064 AccessibilityDelegate mAccessibilityDelegate; 4065 4066 /** 4067 * The view's overlay layer. Developers get a reference to the overlay via getOverlay() 4068 * and add/remove objects to/from the overlay directly through the Overlay methods. 4069 */ 4070 ViewOverlay mOverlay; 4071 4072 /** 4073 * The currently active parent view for receiving delegated nested scrolling events. 4074 * This is set by {@link #startNestedScroll(int)} during a touch interaction and cleared 4075 * by {@link #stopNestedScroll()} at the same point where we clear 4076 * requestDisallowInterceptTouchEvent. 4077 */ 4078 private ViewParent mNestedScrollingParent; 4079 4080 /** 4081 * Consistency verifier for debugging purposes. 4082 * @hide 4083 */ 4084 protected final InputEventConsistencyVerifier mInputEventConsistencyVerifier = 4085 InputEventConsistencyVerifier.isInstrumentationEnabled() ? 4086 new InputEventConsistencyVerifier(this, 0) : null; 4087 4088 private static final AtomicInteger sNextGeneratedId = new AtomicInteger(1); 4089 4090 private int[] mTempNestedScrollConsumed; 4091 4092 /** 4093 * An overlay is going to draw this View instead of being drawn as part of this 4094 * View's parent. mGhostView is the View in the Overlay that must be invalidated 4095 * when this view is invalidated. 4096 */ 4097 GhostView mGhostView; 4098 4099 /** 4100 * Holds pairs of adjacent attribute data: attribute name followed by its value. 4101 * @hide 4102 */ 4103 @ViewDebug.ExportedProperty(category = "attributes", hasAdjacentMapping = true) 4104 public String[] mAttributes; 4105 4106 /** 4107 * Maps a Resource id to its name. 4108 */ 4109 private static SparseArray<String> mAttributeMap; 4110 4111 /** 4112 * Queue of pending runnables. Used to postpone calls to post() until this 4113 * view is attached and has a handler. 4114 */ 4115 private HandlerActionQueue mRunQueue; 4116 4117 /** 4118 * The pointer icon when the mouse hovers on this view. The default is null. 4119 */ 4120 private PointerIcon mPointerIcon; 4121 4122 /** 4123 * @hide 4124 */ 4125 String mStartActivityRequestWho; 4126 4127 @Nullable 4128 private RoundScrollbarRenderer mRoundScrollbarRenderer; 4129 4130 /** 4131 * Simple constructor to use when creating a view from code. 4132 * 4133 * @param context The Context the view is running in, through which it can 4134 * access the current theme, resources, etc. 4135 */ 4136 public View(Context context) { 4137 mContext = context; 4138 mResources = context != null ? context.getResources() : null; 4139 mViewFlags = SOUND_EFFECTS_ENABLED | HAPTIC_FEEDBACK_ENABLED | FOCUSABLE_AUTO; 4140 // Set some flags defaults 4141 mPrivateFlags2 = 4142 (LAYOUT_DIRECTION_DEFAULT << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT) | 4143 (TEXT_DIRECTION_DEFAULT << PFLAG2_TEXT_DIRECTION_MASK_SHIFT) | 4144 (PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT) | 4145 (TEXT_ALIGNMENT_DEFAULT << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT) | 4146 (PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT) | 4147 (IMPORTANT_FOR_ACCESSIBILITY_DEFAULT << PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT); 4148 mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); 4149 setOverScrollMode(OVER_SCROLL_IF_CONTENT_SCROLLS); 4150 mUserPaddingStart = UNDEFINED_PADDING; 4151 mUserPaddingEnd = UNDEFINED_PADDING; 4152 mRenderNode = RenderNode.create(getClass().getName(), this); 4153 4154 if (!sCompatibilityDone && context != null) { 4155 final int targetSdkVersion = context.getApplicationInfo().targetSdkVersion; 4156 4157 // Older apps may need this compatibility hack for measurement. 4158 sUseBrokenMakeMeasureSpec = targetSdkVersion <= Build.VERSION_CODES.JELLY_BEAN_MR1; 4159 4160 // Older apps expect onMeasure() to always be called on a layout pass, regardless 4161 // of whether a layout was requested on that View. 4162 sIgnoreMeasureCache = targetSdkVersion < Build.VERSION_CODES.KITKAT; 4163 4164 Canvas.sCompatibilityRestore = targetSdkVersion < Build.VERSION_CODES.M; 4165 4166 // In M and newer, our widgets can pass a "hint" value in the size 4167 // for UNSPECIFIED MeasureSpecs. This lets child views of scrolling containers 4168 // know what the expected parent size is going to be, so e.g. list items can size 4169 // themselves at 1/3 the size of their container. It breaks older apps though, 4170 // specifically apps that use some popular open source libraries. 4171 sUseZeroUnspecifiedMeasureSpec = targetSdkVersion < Build.VERSION_CODES.M; 4172 4173 // Old versions of the platform would give different results from 4174 // LinearLayout measurement passes using EXACTLY and non-EXACTLY 4175 // modes, so we always need to run an additional EXACTLY pass. 4176 sAlwaysRemeasureExactly = targetSdkVersion <= Build.VERSION_CODES.M; 4177 4178 // Prior to N, layout params could change without requiring a 4179 // subsequent call to setLayoutParams() and they would usually 4180 // work. Partial layout breaks this assumption. 4181 sLayoutParamsAlwaysChanged = targetSdkVersion <= Build.VERSION_CODES.M; 4182 4183 // Prior to N, TextureView would silently ignore calls to setBackground/setForeground. 4184 // On N+, we throw, but that breaks compatibility with apps that use these methods. 4185 sTextureViewIgnoresDrawableSetters = targetSdkVersion <= Build.VERSION_CODES.M; 4186 4187 // Prior to N, we would drop margins in LayoutParam conversions. The fix triggers bugs 4188 // in apps so we target check it to avoid breaking existing apps. 4189 sPreserveMarginParamsInLayoutParamConversion = 4190 targetSdkVersion >= Build.VERSION_CODES.N; 4191 4192 sCascadedDragDrop = targetSdkVersion < Build.VERSION_CODES.N; 4193 4194 sHasFocusableExcludeAutoFocusable = targetSdkVersion < Build.VERSION_CODES.O; 4195 4196 sAutoFocusableOffUIThreadWontNotifyParents = targetSdkVersion < Build.VERSION_CODES.O; 4197 4198 sCompatibilityDone = true; 4199 } 4200 } 4201 4202 /** 4203 * Constructor that is called when inflating a view from XML. This is called 4204 * when a view is being constructed from an XML file, supplying attributes 4205 * that were specified in the XML file. This version uses a default style of 4206 * 0, so the only attribute values applied are those in the Context's Theme 4207 * and the given AttributeSet. 4208 * 4209 * <p> 4210 * The method onFinishInflate() will be called after all children have been 4211 * added. 4212 * 4213 * @param context The Context the view is running in, through which it can 4214 * access the current theme, resources, etc. 4215 * @param attrs The attributes of the XML tag that is inflating the view. 4216 * @see #View(Context, AttributeSet, int) 4217 */ 4218 public View(Context context, @Nullable AttributeSet attrs) { 4219 this(context, attrs, 0); 4220 } 4221 4222 /** 4223 * Perform inflation from XML and apply a class-specific base style from a 4224 * theme attribute. This constructor of View allows subclasses to use their 4225 * own base style when they are inflating. For example, a Button class's 4226 * constructor would call this version of the super class constructor and 4227 * supply <code>R.attr.buttonStyle</code> for <var>defStyleAttr</var>; this 4228 * allows the theme's button style to modify all of the base view attributes 4229 * (in particular its background) as well as the Button class's attributes. 4230 * 4231 * @param context The Context the view is running in, through which it can 4232 * access the current theme, resources, etc. 4233 * @param attrs The attributes of the XML tag that is inflating the view. 4234 * @param defStyleAttr An attribute in the current theme that contains a 4235 * reference to a style resource that supplies default values for 4236 * the view. Can be 0 to not look for defaults. 4237 * @see #View(Context, AttributeSet) 4238 */ 4239 public View(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { 4240 this(context, attrs, defStyleAttr, 0); 4241 } 4242 4243 /** 4244 * Perform inflation from XML and apply a class-specific base style from a 4245 * theme attribute or style resource. This constructor of View allows 4246 * subclasses to use their own base style when they are inflating. 4247 * <p> 4248 * When determining the final value of a particular attribute, there are 4249 * four inputs that come into play: 4250 * <ol> 4251 * <li>Any attribute values in the given AttributeSet. 4252 * <li>The style resource specified in the AttributeSet (named "style"). 4253 * <li>The default style specified by <var>defStyleAttr</var>. 4254 * <li>The default style specified by <var>defStyleRes</var>. 4255 * <li>The base values in this theme. 4256 * </ol> 4257 * <p> 4258 * Each of these inputs is considered in-order, with the first listed taking 4259 * precedence over the following ones. In other words, if in the 4260 * AttributeSet you have supplied <code><Button * textColor="#ff000000"></code> 4261 * , then the button's text will <em>always</em> be black, regardless of 4262 * what is specified in any of the styles. 4263 * 4264 * @param context The Context the view is running in, through which it can 4265 * access the current theme, resources, etc. 4266 * @param attrs The attributes of the XML tag that is inflating the view. 4267 * @param defStyleAttr An attribute in the current theme that contains a 4268 * reference to a style resource that supplies default values for 4269 * the view. Can be 0 to not look for defaults. 4270 * @param defStyleRes A resource identifier of a style resource that 4271 * supplies default values for the view, used only if 4272 * defStyleAttr is 0 or can not be found in the theme. Can be 0 4273 * to not look for defaults. 4274 * @see #View(Context, AttributeSet, int) 4275 */ 4276 public View(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) { 4277 this(context); 4278 4279 final TypedArray a = context.obtainStyledAttributes( 4280 attrs, com.android.internal.R.styleable.View, defStyleAttr, defStyleRes); 4281 4282 if (mDebugViewAttributes) { 4283 saveAttributeData(attrs, a); 4284 } 4285 4286 Drawable background = null; 4287 4288 int leftPadding = -1; 4289 int topPadding = -1; 4290 int rightPadding = -1; 4291 int bottomPadding = -1; 4292 int startPadding = UNDEFINED_PADDING; 4293 int endPadding = UNDEFINED_PADDING; 4294 4295 int padding = -1; 4296 int paddingHorizontal = -1; 4297 int paddingVertical = -1; 4298 4299 int viewFlagValues = 0; 4300 int viewFlagMasks = 0; 4301 4302 boolean setScrollContainer = false; 4303 4304 int x = 0; 4305 int y = 0; 4306 4307 float tx = 0; 4308 float ty = 0; 4309 float tz = 0; 4310 float elevation = 0; 4311 float rotation = 0; 4312 float rotationX = 0; 4313 float rotationY = 0; 4314 float sx = 1f; 4315 float sy = 1f; 4316 boolean transformSet = false; 4317 4318 int scrollbarStyle = SCROLLBARS_INSIDE_OVERLAY; 4319 int overScrollMode = mOverScrollMode; 4320 boolean initializeScrollbars = false; 4321 boolean initializeScrollIndicators = false; 4322 4323 boolean startPaddingDefined = false; 4324 boolean endPaddingDefined = false; 4325 boolean leftPaddingDefined = false; 4326 boolean rightPaddingDefined = false; 4327 4328 final int targetSdkVersion = context.getApplicationInfo().targetSdkVersion; 4329 4330 // Set default values. 4331 viewFlagValues |= FOCUSABLE_AUTO; 4332 viewFlagMasks |= FOCUSABLE_AUTO; 4333 4334 final int N = a.getIndexCount(); 4335 for (int i = 0; i < N; i++) { 4336 int attr = a.getIndex(i); 4337 switch (attr) { 4338 case com.android.internal.R.styleable.View_background: 4339 background = a.getDrawable(attr); 4340 break; 4341 case com.android.internal.R.styleable.View_padding: 4342 padding = a.getDimensionPixelSize(attr, -1); 4343 mUserPaddingLeftInitial = padding; 4344 mUserPaddingRightInitial = padding; 4345 leftPaddingDefined = true; 4346 rightPaddingDefined = true; 4347 break; 4348 case com.android.internal.R.styleable.View_paddingHorizontal: 4349 paddingHorizontal = a.getDimensionPixelSize(attr, -1); 4350 mUserPaddingLeftInitial = paddingHorizontal; 4351 mUserPaddingRightInitial = paddingHorizontal; 4352 leftPaddingDefined = true; 4353 rightPaddingDefined = true; 4354 break; 4355 case com.android.internal.R.styleable.View_paddingVertical: 4356 paddingVertical = a.getDimensionPixelSize(attr, -1); 4357 break; 4358 case com.android.internal.R.styleable.View_paddingLeft: 4359 leftPadding = a.getDimensionPixelSize(attr, -1); 4360 mUserPaddingLeftInitial = leftPadding; 4361 leftPaddingDefined = true; 4362 break; 4363 case com.android.internal.R.styleable.View_paddingTop: 4364 topPadding = a.getDimensionPixelSize(attr, -1); 4365 break; 4366 case com.android.internal.R.styleable.View_paddingRight: 4367 rightPadding = a.getDimensionPixelSize(attr, -1); 4368 mUserPaddingRightInitial = rightPadding; 4369 rightPaddingDefined = true; 4370 break; 4371 case com.android.internal.R.styleable.View_paddingBottom: 4372 bottomPadding = a.getDimensionPixelSize(attr, -1); 4373 break; 4374 case com.android.internal.R.styleable.View_paddingStart: 4375 startPadding = a.getDimensionPixelSize(attr, UNDEFINED_PADDING); 4376 startPaddingDefined = (startPadding != UNDEFINED_PADDING); 4377 break; 4378 case com.android.internal.R.styleable.View_paddingEnd: 4379 endPadding = a.getDimensionPixelSize(attr, UNDEFINED_PADDING); 4380 endPaddingDefined = (endPadding != UNDEFINED_PADDING); 4381 break; 4382 case com.android.internal.R.styleable.View_scrollX: 4383 x = a.getDimensionPixelOffset(attr, 0); 4384 break; 4385 case com.android.internal.R.styleable.View_scrollY: 4386 y = a.getDimensionPixelOffset(attr, 0); 4387 break; 4388 case com.android.internal.R.styleable.View_alpha: 4389 setAlpha(a.getFloat(attr, 1f)); 4390 break; 4391 case com.android.internal.R.styleable.View_transformPivotX: 4392 setPivotX(a.getDimension(attr, 0)); 4393 break; 4394 case com.android.internal.R.styleable.View_transformPivotY: 4395 setPivotY(a.getDimension(attr, 0)); 4396 break; 4397 case com.android.internal.R.styleable.View_translationX: 4398 tx = a.getDimension(attr, 0); 4399 transformSet = true; 4400 break; 4401 case com.android.internal.R.styleable.View_translationY: 4402 ty = a.getDimension(attr, 0); 4403 transformSet = true; 4404 break; 4405 case com.android.internal.R.styleable.View_translationZ: 4406 tz = a.getDimension(attr, 0); 4407 transformSet = true; 4408 break; 4409 case com.android.internal.R.styleable.View_elevation: 4410 elevation = a.getDimension(attr, 0); 4411 transformSet = true; 4412 break; 4413 case com.android.internal.R.styleable.View_rotation: 4414 rotation = a.getFloat(attr, 0); 4415 transformSet = true; 4416 break; 4417 case com.android.internal.R.styleable.View_rotationX: 4418 rotationX = a.getFloat(attr, 0); 4419 transformSet = true; 4420 break; 4421 case com.android.internal.R.styleable.View_rotationY: 4422 rotationY = a.getFloat(attr, 0); 4423 transformSet = true; 4424 break; 4425 case com.android.internal.R.styleable.View_scaleX: 4426 sx = a.getFloat(attr, 1f); 4427 transformSet = true; 4428 break; 4429 case com.android.internal.R.styleable.View_scaleY: 4430 sy = a.getFloat(attr, 1f); 4431 transformSet = true; 4432 break; 4433 case com.android.internal.R.styleable.View_id: 4434 mID = a.getResourceId(attr, NO_ID); 4435 break; 4436 case com.android.internal.R.styleable.View_tag: 4437 mTag = a.getText(attr); 4438 break; 4439 case com.android.internal.R.styleable.View_fitsSystemWindows: 4440 if (a.getBoolean(attr, false)) { 4441 viewFlagValues |= FITS_SYSTEM_WINDOWS; 4442 viewFlagMasks |= FITS_SYSTEM_WINDOWS; 4443 } 4444 break; 4445 case com.android.internal.R.styleable.View_focusable: 4446 viewFlagValues = (viewFlagValues & ~FOCUSABLE_MASK) | getFocusableAttribute(a); 4447 if ((viewFlagValues & FOCUSABLE_AUTO) == 0) { 4448 viewFlagMasks |= FOCUSABLE_MASK; 4449 } 4450 break; 4451 case com.android.internal.R.styleable.View_focusableInTouchMode: 4452 if (a.getBoolean(attr, false)) { 4453 viewFlagValues |= FOCUSABLE_IN_TOUCH_MODE | FOCUSABLE; 4454 viewFlagMasks |= FOCUSABLE_IN_TOUCH_MODE | FOCUSABLE_MASK; 4455 } 4456 break; 4457 case com.android.internal.R.styleable.View_clickable: 4458 if (a.getBoolean(attr, false)) { 4459 viewFlagValues |= CLICKABLE; 4460 viewFlagMasks |= CLICKABLE; 4461 } 4462 break; 4463 case com.android.internal.R.styleable.View_longClickable: 4464 if (a.getBoolean(attr, false)) { 4465 viewFlagValues |= LONG_CLICKABLE; 4466 viewFlagMasks |= LONG_CLICKABLE; 4467 } 4468 break; 4469 case com.android.internal.R.styleable.View_contextClickable: 4470 if (a.getBoolean(attr, false)) { 4471 viewFlagValues |= CONTEXT_CLICKABLE; 4472 viewFlagMasks |= CONTEXT_CLICKABLE; 4473 } 4474 break; 4475 case com.android.internal.R.styleable.View_saveEnabled: 4476 if (!a.getBoolean(attr, true)) { 4477 viewFlagValues |= SAVE_DISABLED; 4478 viewFlagMasks |= SAVE_DISABLED_MASK; 4479 } 4480 break; 4481 case com.android.internal.R.styleable.View_duplicateParentState: 4482 if (a.getBoolean(attr, false)) { 4483 viewFlagValues |= DUPLICATE_PARENT_STATE; 4484 viewFlagMasks |= DUPLICATE_PARENT_STATE; 4485 } 4486 break; 4487 case com.android.internal.R.styleable.View_visibility: 4488 final int visibility = a.getInt(attr, 0); 4489 if (visibility != 0) { 4490 viewFlagValues |= VISIBILITY_FLAGS[visibility]; 4491 viewFlagMasks |= VISIBILITY_MASK; 4492 } 4493 break; 4494 case com.android.internal.R.styleable.View_layoutDirection: 4495 // Clear any layout direction flags (included resolved bits) already set 4496 mPrivateFlags2 &= 4497 ~(PFLAG2_LAYOUT_DIRECTION_MASK | PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK); 4498 // Set the layout direction flags depending on the value of the attribute 4499 final int layoutDirection = a.getInt(attr, -1); 4500 final int value = (layoutDirection != -1) ? 4501 LAYOUT_DIRECTION_FLAGS[layoutDirection] : LAYOUT_DIRECTION_DEFAULT; 4502 mPrivateFlags2 |= (value << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT); 4503 break; 4504 case com.android.internal.R.styleable.View_drawingCacheQuality: 4505 final int cacheQuality = a.getInt(attr, 0); 4506 if (cacheQuality != 0) { 4507 viewFlagValues |= DRAWING_CACHE_QUALITY_FLAGS[cacheQuality]; 4508 viewFlagMasks |= DRAWING_CACHE_QUALITY_MASK; 4509 } 4510 break; 4511 case com.android.internal.R.styleable.View_contentDescription: 4512 setContentDescription(a.getString(attr)); 4513 break; 4514 case com.android.internal.R.styleable.View_accessibilityTraversalBefore: 4515 setAccessibilityTraversalBefore(a.getResourceId(attr, NO_ID)); 4516 break; 4517 case com.android.internal.R.styleable.View_accessibilityTraversalAfter: 4518 setAccessibilityTraversalAfter(a.getResourceId(attr, NO_ID)); 4519 break; 4520 case com.android.internal.R.styleable.View_labelFor: 4521 setLabelFor(a.getResourceId(attr, NO_ID)); 4522 break; 4523 case com.android.internal.R.styleable.View_soundEffectsEnabled: 4524 if (!a.getBoolean(attr, true)) { 4525 viewFlagValues &= ~SOUND_EFFECTS_ENABLED; 4526 viewFlagMasks |= SOUND_EFFECTS_ENABLED; 4527 } 4528 break; 4529 case com.android.internal.R.styleable.View_hapticFeedbackEnabled: 4530 if (!a.getBoolean(attr, true)) { 4531 viewFlagValues &= ~HAPTIC_FEEDBACK_ENABLED; 4532 viewFlagMasks |= HAPTIC_FEEDBACK_ENABLED; 4533 } 4534 break; 4535 case R.styleable.View_scrollbars: 4536 final int scrollbars = a.getInt(attr, SCROLLBARS_NONE); 4537 if (scrollbars != SCROLLBARS_NONE) { 4538 viewFlagValues |= scrollbars; 4539 viewFlagMasks |= SCROLLBARS_MASK; 4540 initializeScrollbars = true; 4541 } 4542 break; 4543 //noinspection deprecation 4544 case R.styleable.View_fadingEdge: 4545 if (targetSdkVersion >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { 4546 // Ignore the attribute starting with ICS 4547 break; 4548 } 4549 // With builds < ICS, fall through and apply fading edges 4550 case R.styleable.View_requiresFadingEdge: 4551 final int fadingEdge = a.getInt(attr, FADING_EDGE_NONE); 4552 if (fadingEdge != FADING_EDGE_NONE) { 4553 viewFlagValues |= fadingEdge; 4554 viewFlagMasks |= FADING_EDGE_MASK; 4555 initializeFadingEdgeInternal(a); 4556 } 4557 break; 4558 case R.styleable.View_scrollbarStyle: 4559 scrollbarStyle = a.getInt(attr, SCROLLBARS_INSIDE_OVERLAY); 4560 if (scrollbarStyle != SCROLLBARS_INSIDE_OVERLAY) { 4561 viewFlagValues |= scrollbarStyle & SCROLLBARS_STYLE_MASK; 4562 viewFlagMasks |= SCROLLBARS_STYLE_MASK; 4563 } 4564 break; 4565 case R.styleable.View_isScrollContainer: 4566 setScrollContainer = true; 4567 if (a.getBoolean(attr, false)) { 4568 setScrollContainer(true); 4569 } 4570 break; 4571 case com.android.internal.R.styleable.View_keepScreenOn: 4572 if (a.getBoolean(attr, false)) { 4573 viewFlagValues |= KEEP_SCREEN_ON; 4574 viewFlagMasks |= KEEP_SCREEN_ON; 4575 } 4576 break; 4577 case R.styleable.View_filterTouchesWhenObscured: 4578 if (a.getBoolean(attr, false)) { 4579 viewFlagValues |= FILTER_TOUCHES_WHEN_OBSCURED; 4580 viewFlagMasks |= FILTER_TOUCHES_WHEN_OBSCURED; 4581 } 4582 break; 4583 case R.styleable.View_nextFocusLeft: 4584 mNextFocusLeftId = a.getResourceId(attr, View.NO_ID); 4585 break; 4586 case R.styleable.View_nextFocusRight: 4587 mNextFocusRightId = a.getResourceId(attr, View.NO_ID); 4588 break; 4589 case R.styleable.View_nextFocusUp: 4590 mNextFocusUpId = a.getResourceId(attr, View.NO_ID); 4591 break; 4592 case R.styleable.View_nextFocusDown: 4593 mNextFocusDownId = a.getResourceId(attr, View.NO_ID); 4594 break; 4595 case R.styleable.View_nextFocusForward: 4596 mNextFocusForwardId = a.getResourceId(attr, View.NO_ID); 4597 break; 4598 case R.styleable.View_nextClusterForward: 4599 mNextClusterForwardId = a.getResourceId(attr, View.NO_ID); 4600 break; 4601 case R.styleable.View_minWidth: 4602 mMinWidth = a.getDimensionPixelSize(attr, 0); 4603 break; 4604 case R.styleable.View_minHeight: 4605 mMinHeight = a.getDimensionPixelSize(attr, 0); 4606 break; 4607 case R.styleable.View_onClick: 4608 if (context.isRestricted()) { 4609 throw new IllegalStateException("The android:onClick attribute cannot " 4610 + "be used within a restricted context"); 4611 } 4612 4613 final String handlerName = a.getString(attr); 4614 if (handlerName != null) { 4615 setOnClickListener(new DeclaredOnClickListener(this, handlerName)); 4616 } 4617 break; 4618 case R.styleable.View_overScrollMode: 4619 overScrollMode = a.getInt(attr, OVER_SCROLL_IF_CONTENT_SCROLLS); 4620 break; 4621 case R.styleable.View_verticalScrollbarPosition: 4622 mVerticalScrollbarPosition = a.getInt(attr, SCROLLBAR_POSITION_DEFAULT); 4623 break; 4624 case R.styleable.View_layerType: 4625 setLayerType(a.getInt(attr, LAYER_TYPE_NONE), null); 4626 break; 4627 case R.styleable.View_textDirection: 4628 // Clear any text direction flag already set 4629 mPrivateFlags2 &= ~PFLAG2_TEXT_DIRECTION_MASK; 4630 // Set the text direction flags depending on the value of the attribute 4631 final int textDirection = a.getInt(attr, -1); 4632 if (textDirection != -1) { 4633 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_FLAGS[textDirection]; 4634 } 4635 break; 4636 case R.styleable.View_textAlignment: 4637 // Clear any text alignment flag already set 4638 mPrivateFlags2 &= ~PFLAG2_TEXT_ALIGNMENT_MASK; 4639 // Set the text alignment flag depending on the value of the attribute 4640 final int textAlignment = a.getInt(attr, TEXT_ALIGNMENT_DEFAULT); 4641 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_FLAGS[textAlignment]; 4642 break; 4643 case R.styleable.View_importantForAccessibility: 4644 setImportantForAccessibility(a.getInt(attr, 4645 IMPORTANT_FOR_ACCESSIBILITY_DEFAULT)); 4646 break; 4647 case R.styleable.View_accessibilityLiveRegion: 4648 setAccessibilityLiveRegion(a.getInt(attr, ACCESSIBILITY_LIVE_REGION_DEFAULT)); 4649 break; 4650 case R.styleable.View_transitionName: 4651 setTransitionName(a.getString(attr)); 4652 break; 4653 case R.styleable.View_nestedScrollingEnabled: 4654 setNestedScrollingEnabled(a.getBoolean(attr, false)); 4655 break; 4656 case R.styleable.View_stateListAnimator: 4657 setStateListAnimator(AnimatorInflater.loadStateListAnimator(context, 4658 a.getResourceId(attr, 0))); 4659 break; 4660 case R.styleable.View_backgroundTint: 4661 // This will get applied later during setBackground(). 4662 if (mBackgroundTint == null) { 4663 mBackgroundTint = new TintInfo(); 4664 } 4665 mBackgroundTint.mTintList = a.getColorStateList( 4666 R.styleable.View_backgroundTint); 4667 mBackgroundTint.mHasTintList = true; 4668 break; 4669 case R.styleable.View_backgroundTintMode: 4670 // This will get applied later during setBackground(). 4671 if (mBackgroundTint == null) { 4672 mBackgroundTint = new TintInfo(); 4673 } 4674 mBackgroundTint.mTintMode = Drawable.parseTintMode(a.getInt( 4675 R.styleable.View_backgroundTintMode, -1), null); 4676 mBackgroundTint.mHasTintMode = true; 4677 break; 4678 case R.styleable.View_outlineProvider: 4679 setOutlineProviderFromAttribute(a.getInt(R.styleable.View_outlineProvider, 4680 PROVIDER_BACKGROUND)); 4681 break; 4682 case R.styleable.View_foreground: 4683 if (targetSdkVersion >= Build.VERSION_CODES.M || this instanceof FrameLayout) { 4684 setForeground(a.getDrawable(attr)); 4685 } 4686 break; 4687 case R.styleable.View_foregroundGravity: 4688 if (targetSdkVersion >= Build.VERSION_CODES.M || this instanceof FrameLayout) { 4689 setForegroundGravity(a.getInt(attr, Gravity.NO_GRAVITY)); 4690 } 4691 break; 4692 case R.styleable.View_foregroundTintMode: 4693 if (targetSdkVersion >= Build.VERSION_CODES.M || this instanceof FrameLayout) { 4694 setForegroundTintMode(Drawable.parseTintMode(a.getInt(attr, -1), null)); 4695 } 4696 break; 4697 case R.styleable.View_foregroundTint: 4698 if (targetSdkVersion >= Build.VERSION_CODES.M || this instanceof FrameLayout) { 4699 setForegroundTintList(a.getColorStateList(attr)); 4700 } 4701 break; 4702 case R.styleable.View_foregroundInsidePadding: 4703 if (targetSdkVersion >= Build.VERSION_CODES.M || this instanceof FrameLayout) { 4704 if (mForegroundInfo == null) { 4705 mForegroundInfo = new ForegroundInfo(); 4706 } 4707 mForegroundInfo.mInsidePadding = a.getBoolean(attr, 4708 mForegroundInfo.mInsidePadding); 4709 } 4710 break; 4711 case R.styleable.View_scrollIndicators: 4712 final int scrollIndicators = 4713 (a.getInt(attr, 0) << SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT) 4714 & SCROLL_INDICATORS_PFLAG3_MASK; 4715 if (scrollIndicators != 0) { 4716 mPrivateFlags3 |= scrollIndicators; 4717 initializeScrollIndicators = true; 4718 } 4719 break; 4720 case R.styleable.View_pointerIcon: 4721 final int resourceId = a.getResourceId(attr, 0); 4722 if (resourceId != 0) { 4723 setPointerIcon(PointerIcon.load( 4724 context.getResources(), resourceId)); 4725 } else { 4726 final int pointerType = a.getInt(attr, PointerIcon.TYPE_NOT_SPECIFIED); 4727 if (pointerType != PointerIcon.TYPE_NOT_SPECIFIED) { 4728 setPointerIcon(PointerIcon.getSystemIcon(context, pointerType)); 4729 } 4730 } 4731 break; 4732 case R.styleable.View_forceHasOverlappingRendering: 4733 if (a.peekValue(attr) != null) { 4734 forceHasOverlappingRendering(a.getBoolean(attr, true)); 4735 } 4736 break; 4737 case R.styleable.View_tooltipText: 4738 setTooltipText(a.getText(attr)); 4739 break; 4740 case R.styleable.View_keyboardNavigationCluster: 4741 if (a.peekValue(attr) != null) { 4742 setKeyboardNavigationCluster(a.getBoolean(attr, true)); 4743 } 4744 break; 4745 case R.styleable.View_focusedByDefault: 4746 if (a.peekValue(attr) != null) { 4747 setFocusedByDefault(a.getBoolean(attr, true)); 4748 } 4749 break; 4750 } 4751 } 4752 4753 setOverScrollMode(overScrollMode); 4754 4755 // Cache start/end user padding as we cannot fully resolve padding here (we dont have yet 4756 // the resolved layout direction). Those cached values will be used later during padding 4757 // resolution. 4758 mUserPaddingStart = startPadding; 4759 mUserPaddingEnd = endPadding; 4760 4761 if (background != null) { 4762 setBackground(background); 4763 } 4764 4765 // setBackground above will record that padding is currently provided by the background. 4766 // If we have padding specified via xml, record that here instead and use it. 4767 mLeftPaddingDefined = leftPaddingDefined; 4768 mRightPaddingDefined = rightPaddingDefined; 4769 4770 if (padding >= 0) { 4771 leftPadding = padding; 4772 topPadding = padding; 4773 rightPadding = padding; 4774 bottomPadding = padding; 4775 mUserPaddingLeftInitial = padding; 4776 mUserPaddingRightInitial = padding; 4777 } else { 4778 if (paddingHorizontal >= 0) { 4779 leftPadding = paddingHorizontal; 4780 rightPadding = paddingHorizontal; 4781 mUserPaddingLeftInitial = paddingHorizontal; 4782 mUserPaddingRightInitial = paddingHorizontal; 4783 } 4784 if (paddingVertical >= 0) { 4785 topPadding = paddingVertical; 4786 bottomPadding = paddingVertical; 4787 } 4788 } 4789 4790 if (isRtlCompatibilityMode()) { 4791 // RTL compatibility mode: pre Jelly Bean MR1 case OR no RTL support case. 4792 // left / right padding are used if defined (meaning here nothing to do). If they are not 4793 // defined and start / end padding are defined (e.g. in Frameworks resources), then we use 4794 // start / end and resolve them as left / right (layout direction is not taken into account). 4795 // Padding from the background drawable is stored at this point in mUserPaddingLeftInitial 4796 // and mUserPaddingRightInitial) so drawable padding will be used as ultimate default if 4797 // defined. 4798 if (!mLeftPaddingDefined && startPaddingDefined) { 4799 leftPadding = startPadding; 4800 } 4801 mUserPaddingLeftInitial = (leftPadding >= 0) ? leftPadding : mUserPaddingLeftInitial; 4802 if (!mRightPaddingDefined && endPaddingDefined) { 4803 rightPadding = endPadding; 4804 } 4805 mUserPaddingRightInitial = (rightPadding >= 0) ? rightPadding : mUserPaddingRightInitial; 4806 } else { 4807 // Jelly Bean MR1 and after case: if start/end defined, they will override any left/right 4808 // values defined. Otherwise, left /right values are used. 4809 // Padding from the background drawable is stored at this point in mUserPaddingLeftInitial 4810 // and mUserPaddingRightInitial) so drawable padding will be used as ultimate default if 4811 // defined. 4812 final boolean hasRelativePadding = startPaddingDefined || endPaddingDefined; 4813 4814 if (mLeftPaddingDefined && !hasRelativePadding) { 4815 mUserPaddingLeftInitial = leftPadding; 4816 } 4817 if (mRightPaddingDefined && !hasRelativePadding) { 4818 mUserPaddingRightInitial = rightPadding; 4819 } 4820 } 4821 4822 internalSetPadding( 4823 mUserPaddingLeftInitial, 4824 topPadding >= 0 ? topPadding : mPaddingTop, 4825 mUserPaddingRightInitial, 4826 bottomPadding >= 0 ? bottomPadding : mPaddingBottom); 4827 4828 if (viewFlagMasks != 0) { 4829 setFlags(viewFlagValues, viewFlagMasks); 4830 } 4831 4832 if (initializeScrollbars) { 4833 initializeScrollbarsInternal(a); 4834 } 4835 4836 if (initializeScrollIndicators) { 4837 initializeScrollIndicatorsInternal(); 4838 } 4839 4840 a.recycle(); 4841 4842 // Needs to be called after mViewFlags is set 4843 if (scrollbarStyle != SCROLLBARS_INSIDE_OVERLAY) { 4844 recomputePadding(); 4845 } 4846 4847 if (x != 0 || y != 0) { 4848 scrollTo(x, y); 4849 } 4850 4851 if (transformSet) { 4852 setTranslationX(tx); 4853 setTranslationY(ty); 4854 setTranslationZ(tz); 4855 setElevation(elevation); 4856 setRotation(rotation); 4857 setRotationX(rotationX); 4858 setRotationY(rotationY); 4859 setScaleX(sx); 4860 setScaleY(sy); 4861 } 4862 4863 if (!setScrollContainer && (viewFlagValues&SCROLLBARS_VERTICAL) != 0) { 4864 setScrollContainer(true); 4865 } 4866 4867 computeOpaqueFlags(); 4868 } 4869 4870 /** 4871 * An implementation of OnClickListener that attempts to lazily load a 4872 * named click handling method from a parent or ancestor context. 4873 */ 4874 private static class DeclaredOnClickListener implements OnClickListener { 4875 private final View mHostView; 4876 private final String mMethodName; 4877 4878 private Method mResolvedMethod; 4879 private Context mResolvedContext; 4880 4881 public DeclaredOnClickListener(@NonNull View hostView, @NonNull String methodName) { 4882 mHostView = hostView; 4883 mMethodName = methodName; 4884 } 4885 4886 @Override 4887 public void onClick(@NonNull View v) { 4888 if (mResolvedMethod == null) { 4889 resolveMethod(mHostView.getContext(), mMethodName); 4890 } 4891 4892 try { 4893 mResolvedMethod.invoke(mResolvedContext, v); 4894 } catch (IllegalAccessException e) { 4895 throw new IllegalStateException( 4896 "Could not execute non-public method for android:onClick", e); 4897 } catch (InvocationTargetException e) { 4898 throw new IllegalStateException( 4899 "Could not execute method for android:onClick", e); 4900 } 4901 } 4902 4903 @NonNull 4904 private void resolveMethod(@Nullable Context context, @NonNull String name) { 4905 while (context != null) { 4906 try { 4907 if (!context.isRestricted()) { 4908 final Method method = context.getClass().getMethod(mMethodName, View.class); 4909 if (method != null) { 4910 mResolvedMethod = method; 4911 mResolvedContext = context; 4912 return; 4913 } 4914 } 4915 } catch (NoSuchMethodException e) { 4916 // Failed to find method, keep searching up the hierarchy. 4917 } 4918 4919 if (context instanceof ContextWrapper) { 4920 context = ((ContextWrapper) context).getBaseContext(); 4921 } else { 4922 // Can't search up the hierarchy, null out and fail. 4923 context = null; 4924 } 4925 } 4926 4927 final int id = mHostView.getId(); 4928 final String idText = id == NO_ID ? "" : " with id '" 4929 + mHostView.getContext().getResources().getResourceEntryName(id) + "'"; 4930 throw new IllegalStateException("Could not find method " + mMethodName 4931 + "(View) in a parent or ancestor Context for android:onClick " 4932 + "attribute defined on view " + mHostView.getClass() + idText); 4933 } 4934 } 4935 4936 /** 4937 * Non-public constructor for use in testing 4938 */ 4939 View() { 4940 mResources = null; 4941 mRenderNode = RenderNode.create(getClass().getName(), this); 4942 } 4943 4944 final boolean debugDraw() { 4945 return DEBUG_DRAW || mAttachInfo != null && mAttachInfo.mDebugLayout; 4946 } 4947 4948 private static SparseArray<String> getAttributeMap() { 4949 if (mAttributeMap == null) { 4950 mAttributeMap = new SparseArray<>(); 4951 } 4952 return mAttributeMap; 4953 } 4954 4955 private void saveAttributeData(@Nullable AttributeSet attrs, @NonNull TypedArray t) { 4956 final int attrsCount = attrs == null ? 0 : attrs.getAttributeCount(); 4957 final int indexCount = t.getIndexCount(); 4958 final String[] attributes = new String[(attrsCount + indexCount) * 2]; 4959 4960 int i = 0; 4961 4962 // Store raw XML attributes. 4963 for (int j = 0; j < attrsCount; ++j) { 4964 attributes[i] = attrs.getAttributeName(j); 4965 attributes[i + 1] = attrs.getAttributeValue(j); 4966 i += 2; 4967 } 4968 4969 // Store resolved styleable attributes. 4970 final Resources res = t.getResources(); 4971 final SparseArray<String> attributeMap = getAttributeMap(); 4972 for (int j = 0; j < indexCount; ++j) { 4973 final int index = t.getIndex(j); 4974 if (!t.hasValueOrEmpty(index)) { 4975 // Value is undefined. Skip it. 4976 continue; 4977 } 4978 4979 final int resourceId = t.getResourceId(index, 0); 4980 if (resourceId == 0) { 4981 // Value is not a reference. Skip it. 4982 continue; 4983 } 4984 4985 String resourceName = attributeMap.get(resourceId); 4986 if (resourceName == null) { 4987 try { 4988 resourceName = res.getResourceName(resourceId); 4989 } catch (Resources.NotFoundException e) { 4990 resourceName = "0x" + Integer.toHexString(resourceId); 4991 } 4992 attributeMap.put(resourceId, resourceName); 4993 } 4994 4995 attributes[i] = resourceName; 4996 attributes[i + 1] = t.getString(index); 4997 i += 2; 4998 } 4999 5000 // Trim to fit contents. 5001 final String[] trimmed = new String[i]; 5002 System.arraycopy(attributes, 0, trimmed, 0, i); 5003 mAttributes = trimmed; 5004 } 5005 5006 public String toString() { 5007 StringBuilder out = new StringBuilder(128); 5008 out.append(getClass().getName()); 5009 out.append('{'); 5010 out.append(Integer.toHexString(System.identityHashCode(this))); 5011 out.append(' '); 5012 switch (mViewFlags&VISIBILITY_MASK) { 5013 case VISIBLE: out.append('V'); break; 5014 case INVISIBLE: out.append('I'); break; 5015 case GONE: out.append('G'); break; 5016 default: out.append('.'); break; 5017 } 5018 out.append((mViewFlags & FOCUSABLE) == FOCUSABLE ? 'F' : '.'); 5019 out.append((mViewFlags&ENABLED_MASK) == ENABLED ? 'E' : '.'); 5020 out.append((mViewFlags&DRAW_MASK) == WILL_NOT_DRAW ? '.' : 'D'); 5021 out.append((mViewFlags&SCROLLBARS_HORIZONTAL) != 0 ? 'H' : '.'); 5022 out.append((mViewFlags&SCROLLBARS_VERTICAL) != 0 ? 'V' : '.'); 5023 out.append((mViewFlags&CLICKABLE) != 0 ? 'C' : '.'); 5024 out.append((mViewFlags&LONG_CLICKABLE) != 0 ? 'L' : '.'); 5025 out.append((mViewFlags&CONTEXT_CLICKABLE) != 0 ? 'X' : '.'); 5026 out.append(' '); 5027 out.append((mPrivateFlags&PFLAG_IS_ROOT_NAMESPACE) != 0 ? 'R' : '.'); 5028 out.append((mPrivateFlags&PFLAG_FOCUSED) != 0 ? 'F' : '.'); 5029 out.append((mPrivateFlags&PFLAG_SELECTED) != 0 ? 'S' : '.'); 5030 if ((mPrivateFlags&PFLAG_PREPRESSED) != 0) { 5031 out.append('p'); 5032 } else { 5033 out.append((mPrivateFlags&PFLAG_PRESSED) != 0 ? 'P' : '.'); 5034 } 5035 out.append((mPrivateFlags&PFLAG_HOVERED) != 0 ? 'H' : '.'); 5036 out.append((mPrivateFlags&PFLAG_ACTIVATED) != 0 ? 'A' : '.'); 5037 out.append((mPrivateFlags&PFLAG_INVALIDATED) != 0 ? 'I' : '.'); 5038 out.append((mPrivateFlags&PFLAG_DIRTY_MASK) != 0 ? 'D' : '.'); 5039 out.append(' '); 5040 out.append(mLeft); 5041 out.append(','); 5042 out.append(mTop); 5043 out.append('-'); 5044 out.append(mRight); 5045 out.append(','); 5046 out.append(mBottom); 5047 final int id = getId(); 5048 if (id != NO_ID) { 5049 out.append(" #"); 5050 out.append(Integer.toHexString(id)); 5051 final Resources r = mResources; 5052 if (id > 0 && Resources.resourceHasPackage(id) && r != null) { 5053 try { 5054 String pkgname; 5055 switch (id&0xff000000) { 5056 case 0x7f000000: 5057 pkgname="app"; 5058 break; 5059 case 0x01000000: 5060 pkgname="android"; 5061 break; 5062 default: 5063 pkgname = r.getResourcePackageName(id); 5064 break; 5065 } 5066 String typename = r.getResourceTypeName(id); 5067 String entryname = r.getResourceEntryName(id); 5068 out.append(" "); 5069 out.append(pkgname); 5070 out.append(":"); 5071 out.append(typename); 5072 out.append("/"); 5073 out.append(entryname); 5074 } catch (Resources.NotFoundException e) { 5075 } 5076 } 5077 } 5078 out.append("}"); 5079 return out.toString(); 5080 } 5081 5082 /** 5083 * <p> 5084 * Initializes the fading edges from a given set of styled attributes. This 5085 * method should be called by subclasses that need fading edges and when an 5086 * instance of these subclasses is created programmatically rather than 5087 * being inflated from XML. This method is automatically called when the XML 5088 * is inflated. 5089 * </p> 5090 * 5091 * @param a the styled attributes set to initialize the fading edges from 5092 * 5093 * @removed 5094 */ 5095 protected void initializeFadingEdge(TypedArray a) { 5096 // This method probably shouldn't have been included in the SDK to begin with. 5097 // It relies on 'a' having been initialized using an attribute filter array that is 5098 // not publicly available to the SDK. The old method has been renamed 5099 // to initializeFadingEdgeInternal and hidden for framework use only; 5100 // this one initializes using defaults to make it safe to call for apps. 5101 5102 TypedArray arr = mContext.obtainStyledAttributes(com.android.internal.R.styleable.View); 5103 5104 initializeFadingEdgeInternal(arr); 5105 5106 arr.recycle(); 5107 } 5108 5109 /** 5110 * <p> 5111 * Initializes the fading edges from a given set of styled attributes. This 5112 * method should be called by subclasses that need fading edges and when an 5113 * instance of these subclasses is created programmatically rather than 5114 * being inflated from XML. This method is automatically called when the XML 5115 * is inflated. 5116 * </p> 5117 * 5118 * @param a the styled attributes set to initialize the fading edges from 5119 * @hide This is the real method; the public one is shimmed to be safe to call from apps. 5120 */ 5121 protected void initializeFadingEdgeInternal(TypedArray a) { 5122 initScrollCache(); 5123 5124 mScrollCache.fadingEdgeLength = a.getDimensionPixelSize( 5125 R.styleable.View_fadingEdgeLength, 5126 ViewConfiguration.get(mContext).getScaledFadingEdgeLength()); 5127 } 5128 5129 /** 5130 * Returns the size of the vertical faded edges used to indicate that more 5131 * content in this view is visible. 5132 * 5133 * @return The size in pixels of the vertical faded edge or 0 if vertical 5134 * faded edges are not enabled for this view. 5135 * @attr ref android.R.styleable#View_fadingEdgeLength 5136 */ 5137 public int getVerticalFadingEdgeLength() { 5138 if (isVerticalFadingEdgeEnabled()) { 5139 ScrollabilityCache cache = mScrollCache; 5140 if (cache != null) { 5141 return cache.fadingEdgeLength; 5142 } 5143 } 5144 return 0; 5145 } 5146 5147 /** 5148 * Set the size of the faded edge used to indicate that more content in this 5149 * view is available. Will not change whether the fading edge is enabled; use 5150 * {@link #setVerticalFadingEdgeEnabled(boolean)} or 5151 * {@link #setHorizontalFadingEdgeEnabled(boolean)} to enable the fading edge 5152 * for the vertical or horizontal fading edges. 5153 * 5154 * @param length The size in pixels of the faded edge used to indicate that more 5155 * content in this view is visible. 5156 */ 5157 public void setFadingEdgeLength(int length) { 5158 initScrollCache(); 5159 mScrollCache.fadingEdgeLength = length; 5160 } 5161 5162 /** 5163 * Returns the size of the horizontal faded edges used to indicate that more 5164 * content in this view is visible. 5165 * 5166 * @return The size in pixels of the horizontal faded edge or 0 if horizontal 5167 * faded edges are not enabled for this view. 5168 * @attr ref android.R.styleable#View_fadingEdgeLength 5169 */ 5170 public int getHorizontalFadingEdgeLength() { 5171 if (isHorizontalFadingEdgeEnabled()) { 5172 ScrollabilityCache cache = mScrollCache; 5173 if (cache != null) { 5174 return cache.fadingEdgeLength; 5175 } 5176 } 5177 return 0; 5178 } 5179 5180 /** 5181 * Returns the width of the vertical scrollbar. 5182 * 5183 * @return The width in pixels of the vertical scrollbar or 0 if there 5184 * is no vertical scrollbar. 5185 */ 5186 public int getVerticalScrollbarWidth() { 5187 ScrollabilityCache cache = mScrollCache; 5188 if (cache != null) { 5189 ScrollBarDrawable scrollBar = cache.scrollBar; 5190 if (scrollBar != null) { 5191 int size = scrollBar.getSize(true); 5192 if (size <= 0) { 5193 size = cache.scrollBarSize; 5194 } 5195 return size; 5196 } 5197 return 0; 5198 } 5199 return 0; 5200 } 5201 5202 /** 5203 * Returns the height of the horizontal scrollbar. 5204 * 5205 * @return The height in pixels of the horizontal scrollbar or 0 if 5206 * there is no horizontal scrollbar. 5207 */ 5208 protected int getHorizontalScrollbarHeight() { 5209 ScrollabilityCache cache = mScrollCache; 5210 if (cache != null) { 5211 ScrollBarDrawable scrollBar = cache.scrollBar; 5212 if (scrollBar != null) { 5213 int size = scrollBar.getSize(false); 5214 if (size <= 0) { 5215 size = cache.scrollBarSize; 5216 } 5217 return size; 5218 } 5219 return 0; 5220 } 5221 return 0; 5222 } 5223 5224 /** 5225 * <p> 5226 * Initializes the scrollbars from a given set of styled attributes. This 5227 * method should be called by subclasses that need scrollbars and when an 5228 * instance of these subclasses is created programmatically rather than 5229 * being inflated from XML. This method is automatically called when the XML 5230 * is inflated. 5231 * </p> 5232 * 5233 * @param a the styled attributes set to initialize the scrollbars from 5234 * 5235 * @removed 5236 */ 5237 protected void initializeScrollbars(TypedArray a) { 5238 // It's not safe to use this method from apps. The parameter 'a' must have been obtained 5239 // using the View filter array which is not available to the SDK. As such, internal 5240 // framework usage now uses initializeScrollbarsInternal and we grab a default 5241 // TypedArray with the right filter instead here. 5242 TypedArray arr = mContext.obtainStyledAttributes(com.android.internal.R.styleable.View); 5243 5244 initializeScrollbarsInternal(arr); 5245 5246 // We ignored the method parameter. Recycle the one we actually did use. 5247 arr.recycle(); 5248 } 5249 5250 /** 5251 * <p> 5252 * Initializes the scrollbars from a given set of styled attributes. This 5253 * method should be called by subclasses that need scrollbars and when an 5254 * instance of these subclasses is created programmatically rather than 5255 * being inflated from XML. This method is automatically called when the XML 5256 * is inflated. 5257 * </p> 5258 * 5259 * @param a the styled attributes set to initialize the scrollbars from 5260 * @hide 5261 */ 5262 protected void initializeScrollbarsInternal(TypedArray a) { 5263 initScrollCache(); 5264 5265 final ScrollabilityCache scrollabilityCache = mScrollCache; 5266 5267 if (scrollabilityCache.scrollBar == null) { 5268 scrollabilityCache.scrollBar = new ScrollBarDrawable(); 5269 scrollabilityCache.scrollBar.setState(getDrawableState()); 5270 scrollabilityCache.scrollBar.setCallback(this); 5271 } 5272 5273 final boolean fadeScrollbars = a.getBoolean(R.styleable.View_fadeScrollbars, true); 5274 5275 if (!fadeScrollbars) { 5276 scrollabilityCache.state = ScrollabilityCache.ON; 5277 } 5278 scrollabilityCache.fadeScrollBars = fadeScrollbars; 5279 5280 5281 scrollabilityCache.scrollBarFadeDuration = a.getInt( 5282 R.styleable.View_scrollbarFadeDuration, ViewConfiguration 5283 .getScrollBarFadeDuration()); 5284 scrollabilityCache.scrollBarDefaultDelayBeforeFade = a.getInt( 5285 R.styleable.View_scrollbarDefaultDelayBeforeFade, 5286 ViewConfiguration.getScrollDefaultDelay()); 5287 5288 5289 scrollabilityCache.scrollBarSize = a.getDimensionPixelSize( 5290 com.android.internal.R.styleable.View_scrollbarSize, 5291 ViewConfiguration.get(mContext).getScaledScrollBarSize()); 5292 5293 Drawable track = a.getDrawable(R.styleable.View_scrollbarTrackHorizontal); 5294 scrollabilityCache.scrollBar.setHorizontalTrackDrawable(track); 5295 5296 Drawable thumb = a.getDrawable(R.styleable.View_scrollbarThumbHorizontal); 5297 if (thumb != null) { 5298 scrollabilityCache.scrollBar.setHorizontalThumbDrawable(thumb); 5299 } 5300 5301 boolean alwaysDraw = a.getBoolean(R.styleable.View_scrollbarAlwaysDrawHorizontalTrack, 5302 false); 5303 if (alwaysDraw) { 5304 scrollabilityCache.scrollBar.setAlwaysDrawHorizontalTrack(true); 5305 } 5306 5307 track = a.getDrawable(R.styleable.View_scrollbarTrackVertical); 5308 scrollabilityCache.scrollBar.setVerticalTrackDrawable(track); 5309 5310 thumb = a.getDrawable(R.styleable.View_scrollbarThumbVertical); 5311 if (thumb != null) { 5312 scrollabilityCache.scrollBar.setVerticalThumbDrawable(thumb); 5313 } 5314 5315 alwaysDraw = a.getBoolean(R.styleable.View_scrollbarAlwaysDrawVerticalTrack, 5316 false); 5317 if (alwaysDraw) { 5318 scrollabilityCache.scrollBar.setAlwaysDrawVerticalTrack(true); 5319 } 5320 5321 // Apply layout direction to the new Drawables if needed 5322 final int layoutDirection = getLayoutDirection(); 5323 if (track != null) { 5324 track.setLayoutDirection(layoutDirection); 5325 } 5326 if (thumb != null) { 5327 thumb.setLayoutDirection(layoutDirection); 5328 } 5329 5330 // Re-apply user/background padding so that scrollbar(s) get added 5331 resolvePadding(); 5332 } 5333 5334 private void initializeScrollIndicatorsInternal() { 5335 // Some day maybe we'll break this into top/left/start/etc. and let the 5336 // client control it. Until then, you can have any scroll indicator you 5337 // want as long as it's a 1dp foreground-colored rectangle. 5338 if (mScrollIndicatorDrawable == null) { 5339 mScrollIndicatorDrawable = mContext.getDrawable(R.drawable.scroll_indicator_material); 5340 } 5341 } 5342 5343 /** 5344 * <p> 5345 * Initalizes the scrollability cache if necessary. 5346 * </p> 5347 */ 5348 private void initScrollCache() { 5349 if (mScrollCache == null) { 5350 mScrollCache = new ScrollabilityCache(ViewConfiguration.get(mContext), this); 5351 } 5352 } 5353 5354 private ScrollabilityCache getScrollCache() { 5355 initScrollCache(); 5356 return mScrollCache; 5357 } 5358 5359 /** 5360 * Set the position of the vertical scroll bar. Should be one of 5361 * {@link #SCROLLBAR_POSITION_DEFAULT}, {@link #SCROLLBAR_POSITION_LEFT} or 5362 * {@link #SCROLLBAR_POSITION_RIGHT}. 5363 * 5364 * @param position Where the vertical scroll bar should be positioned. 5365 */ 5366 public void setVerticalScrollbarPosition(int position) { 5367 if (mVerticalScrollbarPosition != position) { 5368 mVerticalScrollbarPosition = position; 5369 computeOpaqueFlags(); 5370 resolvePadding(); 5371 } 5372 } 5373 5374 /** 5375 * @return The position where the vertical scroll bar will show, if applicable. 5376 * @see #setVerticalScrollbarPosition(int) 5377 */ 5378 public int getVerticalScrollbarPosition() { 5379 return mVerticalScrollbarPosition; 5380 } 5381 5382 boolean isOnScrollbar(float x, float y) { 5383 if (mScrollCache == null) { 5384 return false; 5385 } 5386 x += getScrollX(); 5387 y += getScrollY(); 5388 if (isVerticalScrollBarEnabled() && !isVerticalScrollBarHidden()) { 5389 final Rect touchBounds = mScrollCache.mScrollBarTouchBounds; 5390 getVerticalScrollBarBounds(null, touchBounds); 5391 if (touchBounds.contains((int) x, (int) y)) { 5392 return true; 5393 } 5394 } 5395 if (isHorizontalScrollBarEnabled()) { 5396 final Rect touchBounds = mScrollCache.mScrollBarTouchBounds; 5397 getHorizontalScrollBarBounds(null, touchBounds); 5398 if (touchBounds.contains((int) x, (int) y)) { 5399 return true; 5400 } 5401 } 5402 return false; 5403 } 5404 5405 boolean isOnScrollbarThumb(float x, float y) { 5406 return isOnVerticalScrollbarThumb(x, y) || isOnHorizontalScrollbarThumb(x, y); 5407 } 5408 5409 private boolean isOnVerticalScrollbarThumb(float x, float y) { 5410 if (mScrollCache == null) { 5411 return false; 5412 } 5413 if (isVerticalScrollBarEnabled() && !isVerticalScrollBarHidden()) { 5414 x += getScrollX(); 5415 y += getScrollY(); 5416 final Rect bounds = mScrollCache.mScrollBarBounds; 5417 final Rect touchBounds = mScrollCache.mScrollBarTouchBounds; 5418 getVerticalScrollBarBounds(bounds, touchBounds); 5419 final int range = computeVerticalScrollRange(); 5420 final int offset = computeVerticalScrollOffset(); 5421 final int extent = computeVerticalScrollExtent(); 5422 final int thumbLength = ScrollBarUtils.getThumbLength(bounds.height(), bounds.width(), 5423 extent, range); 5424 final int thumbOffset = ScrollBarUtils.getThumbOffset(bounds.height(), thumbLength, 5425 extent, range, offset); 5426 final int thumbTop = bounds.top + thumbOffset; 5427 final int adjust = Math.max(mScrollCache.scrollBarMinTouchTarget - thumbLength, 0) / 2; 5428 if (x >= touchBounds.left && x <= touchBounds.right 5429 && y >= thumbTop - adjust && y <= thumbTop + thumbLength + adjust) { 5430 return true; 5431 } 5432 } 5433 return false; 5434 } 5435 5436 private boolean isOnHorizontalScrollbarThumb(float x, float y) { 5437 if (mScrollCache == null) { 5438 return false; 5439 } 5440 if (isHorizontalScrollBarEnabled()) { 5441 x += getScrollX(); 5442 y += getScrollY(); 5443 final Rect bounds = mScrollCache.mScrollBarBounds; 5444 final Rect touchBounds = mScrollCache.mScrollBarTouchBounds; 5445 getHorizontalScrollBarBounds(bounds, touchBounds); 5446 final int range = computeHorizontalScrollRange(); 5447 final int offset = computeHorizontalScrollOffset(); 5448 final int extent = computeHorizontalScrollExtent(); 5449 final int thumbLength = ScrollBarUtils.getThumbLength(bounds.width(), bounds.height(), 5450 extent, range); 5451 final int thumbOffset = ScrollBarUtils.getThumbOffset(bounds.width(), thumbLength, 5452 extent, range, offset); 5453 final int thumbLeft = bounds.left + thumbOffset; 5454 final int adjust = Math.max(mScrollCache.scrollBarMinTouchTarget - thumbLength, 0) / 2; 5455 if (x >= thumbLeft - adjust && x <= thumbLeft + thumbLength + adjust 5456 && y >= touchBounds.top && y <= touchBounds.bottom) { 5457 return true; 5458 } 5459 } 5460 return false; 5461 } 5462 5463 boolean isDraggingScrollBar() { 5464 return mScrollCache != null 5465 && mScrollCache.mScrollBarDraggingState != ScrollabilityCache.NOT_DRAGGING; 5466 } 5467 5468 /** 5469 * Sets the state of all scroll indicators. 5470 * <p> 5471 * See {@link #setScrollIndicators(int, int)} for usage information. 5472 * 5473 * @param indicators a bitmask of indicators that should be enabled, or 5474 * {@code 0} to disable all indicators 5475 * @see #setScrollIndicators(int, int) 5476 * @see #getScrollIndicators() 5477 * @attr ref android.R.styleable#View_scrollIndicators 5478 */ 5479 public void setScrollIndicators(@ScrollIndicators int indicators) { 5480 setScrollIndicators(indicators, 5481 SCROLL_INDICATORS_PFLAG3_MASK >>> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT); 5482 } 5483 5484 /** 5485 * Sets the state of the scroll indicators specified by the mask. To change 5486 * all scroll indicators at once, see {@link #setScrollIndicators(int)}. 5487 * <p> 5488 * When a scroll indicator is enabled, it will be displayed if the view 5489 * can scroll in the direction of the indicator. 5490 * <p> 5491 * Multiple indicator types may be enabled or disabled by passing the 5492 * logical OR of the desired types. If multiple types are specified, they 5493 * will all be set to the same enabled state. 5494 * <p> 5495 * For example, to enable the top scroll indicatorExample: {@code setScrollIndicators 5496 * 5497 * @param indicators the indicator direction, or the logical OR of multiple 5498 * indicator directions. One or more of: 5499 * <ul> 5500 * <li>{@link #SCROLL_INDICATOR_TOP}</li> 5501 * <li>{@link #SCROLL_INDICATOR_BOTTOM}</li> 5502 * <li>{@link #SCROLL_INDICATOR_LEFT}</li> 5503 * <li>{@link #SCROLL_INDICATOR_RIGHT}</li> 5504 * <li>{@link #SCROLL_INDICATOR_START}</li> 5505 * <li>{@link #SCROLL_INDICATOR_END}</li> 5506 * </ul> 5507 * @see #setScrollIndicators(int) 5508 * @see #getScrollIndicators() 5509 * @attr ref android.R.styleable#View_scrollIndicators 5510 */ 5511 public void setScrollIndicators(@ScrollIndicators int indicators, @ScrollIndicators int mask) { 5512 // Shift and sanitize mask. 5513 mask <<= SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 5514 mask &= SCROLL_INDICATORS_PFLAG3_MASK; 5515 5516 // Shift and mask indicators. 5517 indicators <<= SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 5518 indicators &= mask; 5519 5520 // Merge with non-masked flags. 5521 final int updatedFlags = indicators | (mPrivateFlags3 & ~mask); 5522 5523 if (mPrivateFlags3 != updatedFlags) { 5524 mPrivateFlags3 = updatedFlags; 5525 5526 if (indicators != 0) { 5527 initializeScrollIndicatorsInternal(); 5528 } 5529 invalidate(); 5530 } 5531 } 5532 5533 /** 5534 * Returns a bitmask representing the enabled scroll indicators. 5535 * <p> 5536 * For example, if the top and left scroll indicators are enabled and all 5537 * other indicators are disabled, the return value will be 5538 * {@code View.SCROLL_INDICATOR_TOP | View.SCROLL_INDICATOR_LEFT}. 5539 * <p> 5540 * To check whether the bottom scroll indicator is enabled, use the value 5541 * of {@code (getScrollIndicators() & View.SCROLL_INDICATOR_BOTTOM) != 0}. 5542 * 5543 * @return a bitmask representing the enabled scroll indicators 5544 */ 5545 @ScrollIndicators 5546 public int getScrollIndicators() { 5547 return (mPrivateFlags3 & SCROLL_INDICATORS_PFLAG3_MASK) 5548 >>> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 5549 } 5550 5551 ListenerInfo getListenerInfo() { 5552 if (mListenerInfo != null) { 5553 return mListenerInfo; 5554 } 5555 mListenerInfo = new ListenerInfo(); 5556 return mListenerInfo; 5557 } 5558 5559 /** 5560 * Register a callback to be invoked when the scroll X or Y positions of 5561 * this view change. 5562 * <p> 5563 * <b>Note:</b> Some views handle scrolling independently from View and may 5564 * have their own separate listeners for scroll-type events. For example, 5565 * {@link android.widget.ListView ListView} allows clients to register an 5566 * {@link android.widget.ListView#setOnScrollListener(android.widget.AbsListView.OnScrollListener) AbsListView.OnScrollListener} 5567 * to listen for changes in list scroll position. 5568 * 5569 * @param l The listener to notify when the scroll X or Y position changes. 5570 * @see android.view.View#getScrollX() 5571 * @see android.view.View#getScrollY() 5572 */ 5573 public void setOnScrollChangeListener(OnScrollChangeListener l) { 5574 getListenerInfo().mOnScrollChangeListener = l; 5575 } 5576 5577 /** 5578 * Register a callback to be invoked when focus of this view changed. 5579 * 5580 * @param l The callback that will run. 5581 */ 5582 public void setOnFocusChangeListener(OnFocusChangeListener l) { 5583 getListenerInfo().mOnFocusChangeListener = l; 5584 } 5585 5586 /** 5587 * Add a listener that will be called when the bounds of the view change due to 5588 * layout processing. 5589 * 5590 * @param listener The listener that will be called when layout bounds change. 5591 */ 5592 public void addOnLayoutChangeListener(OnLayoutChangeListener listener) { 5593 ListenerInfo li = getListenerInfo(); 5594 if (li.mOnLayoutChangeListeners == null) { 5595 li.mOnLayoutChangeListeners = new ArrayList<OnLayoutChangeListener>(); 5596 } 5597 if (!li.mOnLayoutChangeListeners.contains(listener)) { 5598 li.mOnLayoutChangeListeners.add(listener); 5599 } 5600 } 5601 5602 /** 5603 * Remove a listener for layout changes. 5604 * 5605 * @param listener The listener for layout bounds change. 5606 */ 5607 public void removeOnLayoutChangeListener(OnLayoutChangeListener listener) { 5608 ListenerInfo li = mListenerInfo; 5609 if (li == null || li.mOnLayoutChangeListeners == null) { 5610 return; 5611 } 5612 li.mOnLayoutChangeListeners.remove(listener); 5613 } 5614 5615 /** 5616 * Add a listener for attach state changes. 5617 * 5618 * This listener will be called whenever this view is attached or detached 5619 * from a window. Remove the listener using 5620 * {@link #removeOnAttachStateChangeListener(OnAttachStateChangeListener)}. 5621 * 5622 * @param listener Listener to attach 5623 * @see #removeOnAttachStateChangeListener(OnAttachStateChangeListener) 5624 */ 5625 public void addOnAttachStateChangeListener(OnAttachStateChangeListener listener) { 5626 ListenerInfo li = getListenerInfo(); 5627 if (li.mOnAttachStateChangeListeners == null) { 5628 li.mOnAttachStateChangeListeners 5629 = new CopyOnWriteArrayList<OnAttachStateChangeListener>(); 5630 } 5631 li.mOnAttachStateChangeListeners.add(listener); 5632 } 5633 5634 /** 5635 * Remove a listener for attach state changes. The listener will receive no further 5636 * notification of window attach/detach events. 5637 * 5638 * @param listener Listener to remove 5639 * @see #addOnAttachStateChangeListener(OnAttachStateChangeListener) 5640 */ 5641 public void removeOnAttachStateChangeListener(OnAttachStateChangeListener listener) { 5642 ListenerInfo li = mListenerInfo; 5643 if (li == null || li.mOnAttachStateChangeListeners == null) { 5644 return; 5645 } 5646 li.mOnAttachStateChangeListeners.remove(listener); 5647 } 5648 5649 /** 5650 * Returns the focus-change callback registered for this view. 5651 * 5652 * @return The callback, or null if one is not registered. 5653 */ 5654 public OnFocusChangeListener getOnFocusChangeListener() { 5655 ListenerInfo li = mListenerInfo; 5656 return li != null ? li.mOnFocusChangeListener : null; 5657 } 5658 5659 /** 5660 * Register a callback to be invoked when this view is clicked. If this view is not 5661 * clickable, it becomes clickable. 5662 * 5663 * @param l The callback that will run 5664 * 5665 * @see #setClickable(boolean) 5666 */ 5667 public void setOnClickListener(@Nullable OnClickListener l) { 5668 if (!isClickable()) { 5669 setClickable(true); 5670 } 5671 getListenerInfo().mOnClickListener = l; 5672 } 5673 5674 /** 5675 * Return whether this view has an attached OnClickListener. Returns 5676 * true if there is a listener, false if there is none. 5677 */ 5678 public boolean hasOnClickListeners() { 5679 ListenerInfo li = mListenerInfo; 5680 return (li != null && li.mOnClickListener != null); 5681 } 5682 5683 /** 5684 * Register a callback to be invoked when this view is clicked and held. If this view is not 5685 * long clickable, it becomes long clickable. 5686 * 5687 * @param l The callback that will run 5688 * 5689 * @see #setLongClickable(boolean) 5690 */ 5691 public void setOnLongClickListener(@Nullable OnLongClickListener l) { 5692 if (!isLongClickable()) { 5693 setLongClickable(true); 5694 } 5695 getListenerInfo().mOnLongClickListener = l; 5696 } 5697 5698 /** 5699 * Register a callback to be invoked when this view is context clicked. If the view is not 5700 * context clickable, it becomes context clickable. 5701 * 5702 * @param l The callback that will run 5703 * @see #setContextClickable(boolean) 5704 */ 5705 public void setOnContextClickListener(@Nullable OnContextClickListener l) { 5706 if (!isContextClickable()) { 5707 setContextClickable(true); 5708 } 5709 getListenerInfo().mOnContextClickListener = l; 5710 } 5711 5712 /** 5713 * Register a callback to be invoked when the context menu for this view is 5714 * being built. If this view is not long clickable, it becomes long clickable. 5715 * 5716 * @param l The callback that will run 5717 * 5718 */ 5719 public void setOnCreateContextMenuListener(OnCreateContextMenuListener l) { 5720 if (!isLongClickable()) { 5721 setLongClickable(true); 5722 } 5723 getListenerInfo().mOnCreateContextMenuListener = l; 5724 } 5725 5726 /** 5727 * Set an observer to collect stats for each frame rendered for this view. 5728 * 5729 * @hide 5730 */ 5731 public void addFrameMetricsListener(Window window, 5732 Window.OnFrameMetricsAvailableListener listener, 5733 Handler handler) { 5734 if (mAttachInfo != null) { 5735 if (mAttachInfo.mThreadedRenderer != null) { 5736 if (mFrameMetricsObservers == null) { 5737 mFrameMetricsObservers = new ArrayList<>(); 5738 } 5739 5740 FrameMetricsObserver fmo = new FrameMetricsObserver(window, 5741 handler.getLooper(), listener); 5742 mFrameMetricsObservers.add(fmo); 5743 mAttachInfo.mThreadedRenderer.addFrameMetricsObserver(fmo); 5744 } else { 5745 Log.w(VIEW_LOG_TAG, "View not hardware-accelerated. Unable to observe frame stats"); 5746 } 5747 } else { 5748 if (mFrameMetricsObservers == null) { 5749 mFrameMetricsObservers = new ArrayList<>(); 5750 } 5751 5752 FrameMetricsObserver fmo = new FrameMetricsObserver(window, 5753 handler.getLooper(), listener); 5754 mFrameMetricsObservers.add(fmo); 5755 } 5756 } 5757 5758 /** 5759 * Remove observer configured to collect frame stats for this view. 5760 * 5761 * @hide 5762 */ 5763 public void removeFrameMetricsListener( 5764 Window.OnFrameMetricsAvailableListener listener) { 5765 ThreadedRenderer renderer = getThreadedRenderer(); 5766 FrameMetricsObserver fmo = findFrameMetricsObserver(listener); 5767 if (fmo == null) { 5768 throw new IllegalArgumentException( 5769 "attempt to remove OnFrameMetricsAvailableListener that was never added"); 5770 } 5771 5772 if (mFrameMetricsObservers != null) { 5773 mFrameMetricsObservers.remove(fmo); 5774 if (renderer != null) { 5775 renderer.removeFrameMetricsObserver(fmo); 5776 } 5777 } 5778 } 5779 5780 private void registerPendingFrameMetricsObservers() { 5781 if (mFrameMetricsObservers != null) { 5782 ThreadedRenderer renderer = getThreadedRenderer(); 5783 if (renderer != null) { 5784 for (FrameMetricsObserver fmo : mFrameMetricsObservers) { 5785 renderer.addFrameMetricsObserver(fmo); 5786 } 5787 } else { 5788 Log.w(VIEW_LOG_TAG, "View not hardware-accelerated. Unable to observe frame stats"); 5789 } 5790 } 5791 } 5792 5793 private FrameMetricsObserver findFrameMetricsObserver( 5794 Window.OnFrameMetricsAvailableListener listener) { 5795 for (int i = 0; i < mFrameMetricsObservers.size(); i++) { 5796 FrameMetricsObserver observer = mFrameMetricsObservers.get(i); 5797 if (observer.mListener == listener) { 5798 return observer; 5799 } 5800 } 5801 5802 return null; 5803 } 5804 5805 /** 5806 * Call this view's OnClickListener, if it is defined. Performs all normal 5807 * actions associated with clicking: reporting accessibility event, playing 5808 * a sound, etc. 5809 * 5810 * @return True there was an assigned OnClickListener that was called, false 5811 * otherwise is returned. 5812 */ 5813 public boolean performClick() { 5814 final boolean result; 5815 final ListenerInfo li = mListenerInfo; 5816 if (li != null && li.mOnClickListener != null) { 5817 playSoundEffect(SoundEffectConstants.CLICK); 5818 li.mOnClickListener.onClick(this); 5819 result = true; 5820 } else { 5821 result = false; 5822 } 5823 5824 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED); 5825 return result; 5826 } 5827 5828 /** 5829 * Directly call any attached OnClickListener. Unlike {@link #performClick()}, 5830 * this only calls the listener, and does not do any associated clicking 5831 * actions like reporting an accessibility event. 5832 * 5833 * @return True there was an assigned OnClickListener that was called, false 5834 * otherwise is returned. 5835 */ 5836 public boolean callOnClick() { 5837 ListenerInfo li = mListenerInfo; 5838 if (li != null && li.mOnClickListener != null) { 5839 li.mOnClickListener.onClick(this); 5840 return true; 5841 } 5842 return false; 5843 } 5844 5845 /** 5846 * Calls this view's OnLongClickListener, if it is defined. Invokes the 5847 * context menu if the OnLongClickListener did not consume the event. 5848 * 5849 * @return {@code true} if one of the above receivers consumed the event, 5850 * {@code false} otherwise 5851 */ 5852 public boolean performLongClick() { 5853 return performLongClickInternal(mLongClickX, mLongClickY); 5854 } 5855 5856 /** 5857 * Calls this view's OnLongClickListener, if it is defined. Invokes the 5858 * context menu if the OnLongClickListener did not consume the event, 5859 * anchoring it to an (x,y) coordinate. 5860 * 5861 * @param x x coordinate of the anchoring touch event, or {@link Float#NaN} 5862 * to disable anchoring 5863 * @param y y coordinate of the anchoring touch event, or {@link Float#NaN} 5864 * to disable anchoring 5865 * @return {@code true} if one of the above receivers consumed the event, 5866 * {@code false} otherwise 5867 */ 5868 public boolean performLongClick(float x, float y) { 5869 mLongClickX = x; 5870 mLongClickY = y; 5871 final boolean handled = performLongClick(); 5872 mLongClickX = Float.NaN; 5873 mLongClickY = Float.NaN; 5874 return handled; 5875 } 5876 5877 /** 5878 * Calls this view's OnLongClickListener, if it is defined. Invokes the 5879 * context menu if the OnLongClickListener did not consume the event, 5880 * optionally anchoring it to an (x,y) coordinate. 5881 * 5882 * @param x x coordinate of the anchoring touch event, or {@link Float#NaN} 5883 * to disable anchoring 5884 * @param y y coordinate of the anchoring touch event, or {@link Float#NaN} 5885 * to disable anchoring 5886 * @return {@code true} if one of the above receivers consumed the event, 5887 * {@code false} otherwise 5888 */ 5889 private boolean performLongClickInternal(float x, float y) { 5890 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_LONG_CLICKED); 5891 5892 boolean handled = false; 5893 final ListenerInfo li = mListenerInfo; 5894 if (li != null && li.mOnLongClickListener != null) { 5895 handled = li.mOnLongClickListener.onLongClick(View.this); 5896 } 5897 if (!handled) { 5898 final boolean isAnchored = !Float.isNaN(x) && !Float.isNaN(y); 5899 handled = isAnchored ? showContextMenu(x, y) : showContextMenu(); 5900 } 5901 if ((mViewFlags & TOOLTIP) == TOOLTIP) { 5902 if (!handled) { 5903 handled = showLongClickTooltip((int) x, (int) y); 5904 } 5905 } 5906 if (handled) { 5907 performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); 5908 } 5909 return handled; 5910 } 5911 5912 /** 5913 * Call this view's OnContextClickListener, if it is defined. 5914 * 5915 * @param x the x coordinate of the context click 5916 * @param y the y coordinate of the context click 5917 * @return True if there was an assigned OnContextClickListener that consumed the event, false 5918 * otherwise. 5919 */ 5920 public boolean performContextClick(float x, float y) { 5921 return performContextClick(); 5922 } 5923 5924 /** 5925 * Call this view's OnContextClickListener, if it is defined. 5926 * 5927 * @return True if there was an assigned OnContextClickListener that consumed the event, false 5928 * otherwise. 5929 */ 5930 public boolean performContextClick() { 5931 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CONTEXT_CLICKED); 5932 5933 boolean handled = false; 5934 ListenerInfo li = mListenerInfo; 5935 if (li != null && li.mOnContextClickListener != null) { 5936 handled = li.mOnContextClickListener.onContextClick(View.this); 5937 } 5938 if (handled) { 5939 performHapticFeedback(HapticFeedbackConstants.CONTEXT_CLICK); 5940 } 5941 return handled; 5942 } 5943 5944 /** 5945 * Performs button-related actions during a touch down event. 5946 * 5947 * @param event The event. 5948 * @return True if the down was consumed. 5949 * 5950 * @hide 5951 */ 5952 protected boolean performButtonActionOnTouchDown(MotionEvent event) { 5953 if (event.isFromSource(InputDevice.SOURCE_MOUSE) && 5954 (event.getButtonState() & MotionEvent.BUTTON_SECONDARY) != 0) { 5955 showContextMenu(event.getX(), event.getY()); 5956 mPrivateFlags |= PFLAG_CANCEL_NEXT_UP_EVENT; 5957 return true; 5958 } 5959 return false; 5960 } 5961 5962 /** 5963 * Shows the context menu for this view. 5964 * 5965 * @return {@code true} if the context menu was shown, {@code false} 5966 * otherwise 5967 * @see #showContextMenu(float, float) 5968 */ 5969 public boolean showContextMenu() { 5970 return getParent().showContextMenuForChild(this); 5971 } 5972 5973 /** 5974 * Shows the context menu for this view anchored to the specified 5975 * view-relative coordinate. 5976 * 5977 * @param x the X coordinate in pixels relative to the view to which the 5978 * menu should be anchored, or {@link Float#NaN} to disable anchoring 5979 * @param y the Y coordinate in pixels relative to the view to which the 5980 * menu should be anchored, or {@link Float#NaN} to disable anchoring 5981 * @return {@code true} if the context menu was shown, {@code false} 5982 * otherwise 5983 */ 5984 public boolean showContextMenu(float x, float y) { 5985 return getParent().showContextMenuForChild(this, x, y); 5986 } 5987 5988 /** 5989 * Start an action mode with the default type {@link ActionMode#TYPE_PRIMARY}. 5990 * 5991 * @param callback Callback that will control the lifecycle of the action mode 5992 * @return The new action mode if it is started, null otherwise 5993 * 5994 * @see ActionMode 5995 * @see #startActionMode(android.view.ActionMode.Callback, int) 5996 */ 5997 public ActionMode startActionMode(ActionMode.Callback callback) { 5998 return startActionMode(callback, ActionMode.TYPE_PRIMARY); 5999 } 6000 6001 /** 6002 * Start an action mode with the given type. 6003 * 6004 * @param callback Callback that will control the lifecycle of the action mode 6005 * @param type One of {@link ActionMode#TYPE_PRIMARY} or {@link ActionMode#TYPE_FLOATING}. 6006 * @return The new action mode if it is started, null otherwise 6007 * 6008 * @see ActionMode 6009 */ 6010 public ActionMode startActionMode(ActionMode.Callback callback, int type) { 6011 ViewParent parent = getParent(); 6012 if (parent == null) return null; 6013 try { 6014 return parent.startActionModeForChild(this, callback, type); 6015 } catch (AbstractMethodError ame) { 6016 // Older implementations of custom views might not implement this. 6017 return parent.startActionModeForChild(this, callback); 6018 } 6019 } 6020 6021 /** 6022 * Call {@link Context#startActivityForResult(String, Intent, int, Bundle)} for the View's 6023 * Context, creating a unique View identifier to retrieve the result. 6024 * 6025 * @param intent The Intent to be started. 6026 * @param requestCode The request code to use. 6027 * @hide 6028 */ 6029 public void startActivityForResult(Intent intent, int requestCode) { 6030 mStartActivityRequestWho = "@android:view:" + System.identityHashCode(this); 6031 getContext().startActivityForResult(mStartActivityRequestWho, intent, requestCode, null); 6032 } 6033 6034 /** 6035 * If this View corresponds to the calling who, dispatches the activity result. 6036 * @param who The identifier for the targeted View to receive the result. 6037 * @param requestCode The integer request code originally supplied to 6038 * startActivityForResult(), allowing you to identify who this 6039 * result came from. 6040 * @param resultCode The integer result code returned by the child activity 6041 * through its setResult(). 6042 * @param data An Intent, which can return result data to the caller 6043 * (various data can be attached to Intent "extras"). 6044 * @return {@code true} if the activity result was dispatched. 6045 * @hide 6046 */ 6047 public boolean dispatchActivityResult( 6048 String who, int requestCode, int resultCode, Intent data) { 6049 if (mStartActivityRequestWho != null && mStartActivityRequestWho.equals(who)) { 6050 onActivityResult(requestCode, resultCode, data); 6051 mStartActivityRequestWho = null; 6052 return true; 6053 } 6054 return false; 6055 } 6056 6057 /** 6058 * Receive the result from a previous call to {@link #startActivityForResult(Intent, int)}. 6059 * 6060 * @param requestCode The integer request code originally supplied to 6061 * startActivityForResult(), allowing you to identify who this 6062 * result came from. 6063 * @param resultCode The integer result code returned by the child activity 6064 * through its setResult(). 6065 * @param data An Intent, which can return result data to the caller 6066 * (various data can be attached to Intent "extras"). 6067 * @hide 6068 */ 6069 public void onActivityResult(int requestCode, int resultCode, Intent data) { 6070 // Do nothing. 6071 } 6072 6073 /** 6074 * Register a callback to be invoked when a hardware key is pressed in this view. 6075 * Key presses in software input methods will generally not trigger the methods of 6076 * this listener. 6077 * @param l the key listener to attach to this view 6078 */ 6079 public void setOnKeyListener(OnKeyListener l) { 6080 getListenerInfo().mOnKeyListener = l; 6081 } 6082 6083 /** 6084 * Register a callback to be invoked when a touch event is sent to this view. 6085 * @param l the touch listener to attach to this view 6086 */ 6087 public void setOnTouchListener(OnTouchListener l) { 6088 getListenerInfo().mOnTouchListener = l; 6089 } 6090 6091 /** 6092 * Register a callback to be invoked when a generic motion event is sent to this view. 6093 * @param l the generic motion listener to attach to this view 6094 */ 6095 public void setOnGenericMotionListener(OnGenericMotionListener l) { 6096 getListenerInfo().mOnGenericMotionListener = l; 6097 } 6098 6099 /** 6100 * Register a callback to be invoked when a hover event is sent to this view. 6101 * @param l the hover listener to attach to this view 6102 */ 6103 public void setOnHoverListener(OnHoverListener l) { 6104 getListenerInfo().mOnHoverListener = l; 6105 } 6106 6107 /** 6108 * Register a drag event listener callback object for this View. The parameter is 6109 * an implementation of {@link android.view.View.OnDragListener}. To send a drag event to a 6110 * View, the system calls the 6111 * {@link android.view.View.OnDragListener#onDrag(View,DragEvent)} method. 6112 * @param l An implementation of {@link android.view.View.OnDragListener}. 6113 */ 6114 public void setOnDragListener(OnDragListener l) { 6115 getListenerInfo().mOnDragListener = l; 6116 } 6117 6118 /** 6119 * Give this view focus. This will cause 6120 * {@link #onFocusChanged(boolean, int, android.graphics.Rect)} to be called. 6121 * 6122 * Note: this does not check whether this {@link View} should get focus, it just 6123 * gives it focus no matter what. It should only be called internally by framework 6124 * code that knows what it is doing, namely {@link #requestFocus(int, Rect)}. 6125 * 6126 * @param direction values are {@link View#FOCUS_UP}, {@link View#FOCUS_DOWN}, 6127 * {@link View#FOCUS_LEFT} or {@link View#FOCUS_RIGHT}. This is the direction which 6128 * focus moved when requestFocus() is called. It may not always 6129 * apply, in which case use the default View.FOCUS_DOWN. 6130 * @param previouslyFocusedRect The rectangle of the view that had focus 6131 * prior in this View's coordinate system. 6132 */ 6133 void handleFocusGainInternal(@FocusRealDirection int direction, Rect previouslyFocusedRect) { 6134 if (DBG) { 6135 System.out.println(this + " requestFocus()"); 6136 } 6137 6138 if ((mPrivateFlags & PFLAG_FOCUSED) == 0) { 6139 mPrivateFlags |= PFLAG_FOCUSED; 6140 6141 View oldFocus = (mAttachInfo != null) ? getRootView().findFocus() : null; 6142 6143 if (mParent != null) { 6144 mParent.requestChildFocus(this, this); 6145 setFocusedInCluster(); 6146 } 6147 6148 if (mAttachInfo != null) { 6149 mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(oldFocus, this); 6150 } 6151 6152 onFocusChanged(true, direction, previouslyFocusedRect); 6153 refreshDrawableState(); 6154 } 6155 } 6156 6157 /** 6158 * Sets this view's preference for reveal behavior when it gains focus. 6159 * 6160 * <p>When set to true, this is a signal to ancestor views in the hierarchy that 6161 * this view would prefer to be brought fully into view when it gains focus. 6162 * For example, a text field that a user is meant to type into. Other views such 6163 * as scrolling containers may prefer to opt-out of this behavior.</p> 6164 * 6165 * <p>The default value for views is true, though subclasses may change this 6166 * based on their preferred behavior.</p> 6167 * 6168 * @param revealOnFocus true to request reveal on focus in ancestors, false otherwise 6169 * 6170 * @see #getRevealOnFocusHint() 6171 */ 6172 public final void setRevealOnFocusHint(boolean revealOnFocus) { 6173 if (revealOnFocus) { 6174 mPrivateFlags3 &= ~PFLAG3_NO_REVEAL_ON_FOCUS; 6175 } else { 6176 mPrivateFlags3 |= PFLAG3_NO_REVEAL_ON_FOCUS; 6177 } 6178 } 6179 6180 /** 6181 * Returns this view's preference for reveal behavior when it gains focus. 6182 * 6183 * <p>When this method returns true for a child view requesting focus, ancestor 6184 * views responding to a focus change in {@link ViewParent#requestChildFocus(View, View)} 6185 * should make a best effort to make the newly focused child fully visible to the user. 6186 * When it returns false, ancestor views should preferably not disrupt scroll positioning or 6187 * other properties affecting visibility to the user as part of the focus change.</p> 6188 * 6189 * @return true if this view would prefer to become fully visible when it gains focus, 6190 * false if it would prefer not to disrupt scroll positioning 6191 * 6192 * @see #setRevealOnFocusHint(boolean) 6193 */ 6194 public final boolean getRevealOnFocusHint() { 6195 return (mPrivateFlags3 & PFLAG3_NO_REVEAL_ON_FOCUS) == 0; 6196 } 6197 6198 /** 6199 * Populates <code>outRect</code> with the hotspot bounds. By default, 6200 * the hotspot bounds are identical to the screen bounds. 6201 * 6202 * @param outRect rect to populate with hotspot bounds 6203 * @hide Only for internal use by views and widgets. 6204 */ 6205 public void getHotspotBounds(Rect outRect) { 6206 final Drawable background = getBackground(); 6207 if (background != null) { 6208 background.getHotspotBounds(outRect); 6209 } else { 6210 getBoundsOnScreen(outRect); 6211 } 6212 } 6213 6214 /** 6215 * Request that a rectangle of this view be visible on the screen, 6216 * scrolling if necessary just enough. 6217 * 6218 * <p>A View should call this if it maintains some notion of which part 6219 * of its content is interesting. For example, a text editing view 6220 * should call this when its cursor moves. 6221 * <p>The Rectangle passed into this method should be in the View's content coordinate space. 6222 * It should not be affected by which part of the View is currently visible or its scroll 6223 * position. 6224 * 6225 * @param rectangle The rectangle in the View's content coordinate space 6226 * @return Whether any parent scrolled. 6227 */ 6228 public boolean requestRectangleOnScreen(Rect rectangle) { 6229 return requestRectangleOnScreen(rectangle, false); 6230 } 6231 6232 /** 6233 * Request that a rectangle of this view be visible on the screen, 6234 * scrolling if necessary just enough. 6235 * 6236 * <p>A View should call this if it maintains some notion of which part 6237 * of its content is interesting. For example, a text editing view 6238 * should call this when its cursor moves. 6239 * <p>The Rectangle passed into this method should be in the View's content coordinate space. 6240 * It should not be affected by which part of the View is currently visible or its scroll 6241 * position. 6242 * <p>When <code>immediate</code> is set to true, scrolling will not be 6243 * animated. 6244 * 6245 * @param rectangle The rectangle in the View's content coordinate space 6246 * @param immediate True to forbid animated scrolling, false otherwise 6247 * @return Whether any parent scrolled. 6248 */ 6249 public boolean requestRectangleOnScreen(Rect rectangle, boolean immediate) { 6250 if (mParent == null) { 6251 return false; 6252 } 6253 6254 View child = this; 6255 6256 RectF position = (mAttachInfo != null) ? mAttachInfo.mTmpTransformRect : new RectF(); 6257 position.set(rectangle); 6258 6259 ViewParent parent = mParent; 6260 boolean scrolled = false; 6261 while (parent != null) { 6262 rectangle.set((int) position.left, (int) position.top, 6263 (int) position.right, (int) position.bottom); 6264 6265 scrolled |= parent.requestChildRectangleOnScreen(child, rectangle, immediate); 6266 6267 if (!(parent instanceof View)) { 6268 break; 6269 } 6270 6271 // move it from child's content coordinate space to parent's content coordinate space 6272 position.offset(child.mLeft - child.getScrollX(), child.mTop -child.getScrollY()); 6273 6274 child = (View) parent; 6275 parent = child.getParent(); 6276 } 6277 6278 return scrolled; 6279 } 6280 6281 /** 6282 * Called when this view wants to give up focus. If focus is cleared 6283 * {@link #onFocusChanged(boolean, int, android.graphics.Rect)} is called. 6284 * <p> 6285 * <strong>Note:</strong> When a View clears focus the framework is trying 6286 * to give focus to the first focusable View from the top. Hence, if this 6287 * View is the first from the top that can take focus, then all callbacks 6288 * related to clearing focus will be invoked after which the framework will 6289 * give focus to this view. 6290 * </p> 6291 */ 6292 public void clearFocus() { 6293 if (DBG) { 6294 System.out.println(this + " clearFocus()"); 6295 } 6296 6297 clearFocusInternal(null, true, true); 6298 } 6299 6300 /** 6301 * Clears focus from the view, optionally propagating the change up through 6302 * the parent hierarchy and requesting that the root view place new focus. 6303 * 6304 * @param propagate whether to propagate the change up through the parent 6305 * hierarchy 6306 * @param refocus when propagate is true, specifies whether to request the 6307 * root view place new focus 6308 */ 6309 void clearFocusInternal(View focused, boolean propagate, boolean refocus) { 6310 if ((mPrivateFlags & PFLAG_FOCUSED) != 0) { 6311 mPrivateFlags &= ~PFLAG_FOCUSED; 6312 6313 if (propagate && mParent != null) { 6314 mParent.clearChildFocus(this); 6315 } 6316 6317 onFocusChanged(false, 0, null); 6318 refreshDrawableState(); 6319 6320 if (propagate && (!refocus || !rootViewRequestFocus())) { 6321 notifyGlobalFocusCleared(this); 6322 } 6323 } 6324 } 6325 6326 void notifyGlobalFocusCleared(View oldFocus) { 6327 if (oldFocus != null && mAttachInfo != null) { 6328 mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(oldFocus, null); 6329 } 6330 } 6331 6332 boolean rootViewRequestFocus() { 6333 final View root = getRootView(); 6334 return root != null && root.requestFocus(); 6335 } 6336 6337 /** 6338 * Called internally by the view system when a new view is getting focus. 6339 * This is what clears the old focus. 6340 * <p> 6341 * <b>NOTE:</b> The parent view's focused child must be updated manually 6342 * after calling this method. Otherwise, the view hierarchy may be left in 6343 * an inconstent state. 6344 */ 6345 void unFocus(View focused) { 6346 if (DBG) { 6347 System.out.println(this + " unFocus()"); 6348 } 6349 6350 clearFocusInternal(focused, false, false); 6351 } 6352 6353 /** 6354 * Returns true if this view has focus itself, or is the ancestor of the 6355 * view that has focus. 6356 * 6357 * @return True if this view has or contains focus, false otherwise. 6358 */ 6359 @ViewDebug.ExportedProperty(category = "focus") 6360 public boolean hasFocus() { 6361 return (mPrivateFlags & PFLAG_FOCUSED) != 0; 6362 } 6363 6364 /** 6365 * Returns true if this view is focusable or if it contains a reachable View 6366 * for which {@link #hasFocusable()} returns {@code true}. A "reachable hasFocusable()" 6367 * is a view whose parents do not block descendants focus. 6368 * Only {@link #VISIBLE} views are considered focusable. 6369 * 6370 * <p>As of {@link Build.VERSION_CODES#O} views that are determined to be focusable 6371 * through {@link #FOCUSABLE_AUTO} will also cause this method to return {@code true}. 6372 * Apps that declare a {@link android.content.pm.ApplicationInfo#targetSdkVersion} of 6373 * earlier than {@link Build.VERSION_CODES#O} will continue to see this method return 6374 * {@code false} for views not explicitly marked as focusable. 6375 * Use {@link #hasExplicitFocusable()} if you require the pre-{@link Build.VERSION_CODES#O} 6376 * behavior.</p> 6377 * 6378 * @return {@code true} if the view is focusable or if the view contains a focusable 6379 * view, {@code false} otherwise 6380 * 6381 * @see ViewGroup#FOCUS_BLOCK_DESCENDANTS 6382 * @see ViewGroup#getTouchscreenBlocksFocus() 6383 * @see #hasExplicitFocusable() 6384 */ 6385 public boolean hasFocusable() { 6386 return hasFocusable(!sHasFocusableExcludeAutoFocusable, false); 6387 } 6388 6389 /** 6390 * Returns true if this view is focusable or if it contains a reachable View 6391 * for which {@link #hasExplicitFocusable()} returns {@code true}. 6392 * A "reachable hasExplicitFocusable()" is a view whose parents do not block descendants focus. 6393 * Only {@link #VISIBLE} views for which {@link #getFocusable()} would return 6394 * {@link #FOCUSABLE} are considered focusable. 6395 * 6396 * <p>This method preserves the pre-{@link Build.VERSION_CODES#O} behavior of 6397 * {@link #hasFocusable()} in that only views explicitly set focusable will cause 6398 * this method to return true. A view set to {@link #FOCUSABLE_AUTO} that resolves 6399 * to focusable will not.</p> 6400 * 6401 * @return {@code true} if the view is focusable or if the view contains a focusable 6402 * view, {@code false} otherwise 6403 * 6404 * @see #hasFocusable() 6405 */ 6406 public boolean hasExplicitFocusable() { 6407 return hasFocusable(false, true); 6408 } 6409 6410 boolean hasFocusable(boolean allowAutoFocus, boolean dispatchExplicit) { 6411 if (!isFocusableInTouchMode()) { 6412 for (ViewParent p = mParent; p instanceof ViewGroup; p = p.getParent()) { 6413 final ViewGroup g = (ViewGroup) p; 6414 if (g.shouldBlockFocusForTouchscreen()) { 6415 return false; 6416 } 6417 } 6418 } 6419 if ((mViewFlags & VISIBILITY_MASK) != VISIBLE) { 6420 return false; 6421 } 6422 return (allowAutoFocus 6423 ? getFocusable() != NOT_FOCUSABLE 6424 : getFocusable() == FOCUSABLE) && isFocusable(); 6425 } 6426 6427 /** 6428 * Called by the view system when the focus state of this view changes. 6429 * When the focus change event is caused by directional navigation, direction 6430 * and previouslyFocusedRect provide insight into where the focus is coming from. 6431 * When overriding, be sure to call up through to the super class so that 6432 * the standard focus handling will occur. 6433 * 6434 * @param gainFocus True if the View has focus; false otherwise. 6435 * @param direction The direction focus has moved when requestFocus() 6436 * is called to give this view focus. Values are 6437 * {@link #FOCUS_UP}, {@link #FOCUS_DOWN}, {@link #FOCUS_LEFT}, 6438 * {@link #FOCUS_RIGHT}, {@link #FOCUS_FORWARD}, or {@link #FOCUS_BACKWARD}. 6439 * It may not always apply, in which case use the default. 6440 * @param previouslyFocusedRect The rectangle, in this view's coordinate 6441 * system, of the previously focused view. If applicable, this will be 6442 * passed in as finer grained information about where the focus is coming 6443 * from (in addition to direction). Will be <code>null</code> otherwise. 6444 */ 6445 @CallSuper 6446 protected void onFocusChanged(boolean gainFocus, @FocusDirection int direction, 6447 @Nullable Rect previouslyFocusedRect) { 6448 if (gainFocus) { 6449 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED); 6450 } else { 6451 notifyViewAccessibilityStateChangedIfNeeded( 6452 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 6453 } 6454 6455 InputMethodManager imm = InputMethodManager.peekInstance(); 6456 if (!gainFocus) { 6457 if (isPressed()) { 6458 setPressed(false); 6459 } 6460 if (imm != null && mAttachInfo != null && mAttachInfo.mHasWindowFocus) { 6461 imm.focusOut(this); 6462 } 6463 onFocusLost(); 6464 } else if (imm != null && mAttachInfo != null && mAttachInfo.mHasWindowFocus) { 6465 imm.focusIn(this); 6466 } 6467 6468 if (isAutoFillable()) { 6469 AutoFillManager afm = getAutoFillManager(); 6470 if (afm != null) { 6471 afm.focusChanged(this, gainFocus); 6472 } 6473 } 6474 6475 invalidate(true); 6476 ListenerInfo li = mListenerInfo; 6477 if (li != null && li.mOnFocusChangeListener != null) { 6478 li.mOnFocusChangeListener.onFocusChange(this, gainFocus); 6479 } 6480 6481 if (mAttachInfo != null) { 6482 mAttachInfo.mKeyDispatchState.reset(this); 6483 } 6484 } 6485 6486 /** 6487 * Sends an accessibility event of the given type. If accessibility is 6488 * not enabled this method has no effect. The default implementation calls 6489 * {@link #onInitializeAccessibilityEvent(AccessibilityEvent)} first 6490 * to populate information about the event source (this View), then calls 6491 * {@link #dispatchPopulateAccessibilityEvent(AccessibilityEvent)} to 6492 * populate the text content of the event source including its descendants, 6493 * and last calls 6494 * {@link ViewParent#requestSendAccessibilityEvent(View, AccessibilityEvent)} 6495 * on its parent to request sending of the event to interested parties. 6496 * <p> 6497 * If an {@link AccessibilityDelegate} has been specified via calling 6498 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 6499 * {@link AccessibilityDelegate#sendAccessibilityEvent(View, int)} is 6500 * responsible for handling this call. 6501 * </p> 6502 * 6503 * @param eventType The type of the event to send, as defined by several types from 6504 * {@link android.view.accessibility.AccessibilityEvent}, such as 6505 * {@link android.view.accessibility.AccessibilityEvent#TYPE_VIEW_CLICKED} or 6506 * {@link android.view.accessibility.AccessibilityEvent#TYPE_VIEW_HOVER_ENTER}. 6507 * 6508 * @see #onInitializeAccessibilityEvent(AccessibilityEvent) 6509 * @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent) 6510 * @see ViewParent#requestSendAccessibilityEvent(View, AccessibilityEvent) 6511 * @see AccessibilityDelegate 6512 */ 6513 public void sendAccessibilityEvent(int eventType) { 6514 if (mAccessibilityDelegate != null) { 6515 mAccessibilityDelegate.sendAccessibilityEvent(this, eventType); 6516 } else { 6517 sendAccessibilityEventInternal(eventType); 6518 } 6519 } 6520 6521 /** 6522 * Convenience method for sending a {@link AccessibilityEvent#TYPE_ANNOUNCEMENT} 6523 * {@link AccessibilityEvent} to make an announcement which is related to some 6524 * sort of a context change for which none of the events representing UI transitions 6525 * is a good fit. For example, announcing a new page in a book. If accessibility 6526 * is not enabled this method does nothing. 6527 * 6528 * @param text The announcement text. 6529 */ 6530 public void announceForAccessibility(CharSequence text) { 6531 if (AccessibilityManager.getInstance(mContext).isEnabled() && mParent != null) { 6532 AccessibilityEvent event = AccessibilityEvent.obtain( 6533 AccessibilityEvent.TYPE_ANNOUNCEMENT); 6534 onInitializeAccessibilityEvent(event); 6535 event.getText().add(text); 6536 event.setContentDescription(null); 6537 mParent.requestSendAccessibilityEvent(this, event); 6538 } 6539 } 6540 6541 /** 6542 * @see #sendAccessibilityEvent(int) 6543 * 6544 * Note: Called from the default {@link AccessibilityDelegate}. 6545 * 6546 * @hide 6547 */ 6548 public void sendAccessibilityEventInternal(int eventType) { 6549 if (AccessibilityManager.getInstance(mContext).isEnabled()) { 6550 sendAccessibilityEventUnchecked(AccessibilityEvent.obtain(eventType)); 6551 } 6552 } 6553 6554 /** 6555 * This method behaves exactly as {@link #sendAccessibilityEvent(int)} but 6556 * takes as an argument an empty {@link AccessibilityEvent} and does not 6557 * perform a check whether accessibility is enabled. 6558 * <p> 6559 * If an {@link AccessibilityDelegate} has been specified via calling 6560 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 6561 * {@link AccessibilityDelegate#sendAccessibilityEventUnchecked(View, AccessibilityEvent)} 6562 * is responsible for handling this call. 6563 * </p> 6564 * 6565 * @param event The event to send. 6566 * 6567 * @see #sendAccessibilityEvent(int) 6568 */ 6569 public void sendAccessibilityEventUnchecked(AccessibilityEvent event) { 6570 if (mAccessibilityDelegate != null) { 6571 mAccessibilityDelegate.sendAccessibilityEventUnchecked(this, event); 6572 } else { 6573 sendAccessibilityEventUncheckedInternal(event); 6574 } 6575 } 6576 6577 /** 6578 * @see #sendAccessibilityEventUnchecked(AccessibilityEvent) 6579 * 6580 * Note: Called from the default {@link AccessibilityDelegate}. 6581 * 6582 * @hide 6583 */ 6584 public void sendAccessibilityEventUncheckedInternal(AccessibilityEvent event) { 6585 if (!isShown()) { 6586 return; 6587 } 6588 onInitializeAccessibilityEvent(event); 6589 // Only a subset of accessibility events populates text content. 6590 if ((event.getEventType() & POPULATING_ACCESSIBILITY_EVENT_TYPES) != 0) { 6591 dispatchPopulateAccessibilityEvent(event); 6592 } 6593 // In the beginning we called #isShown(), so we know that getParent() is not null. 6594 getParent().requestSendAccessibilityEvent(this, event); 6595 } 6596 6597 /** 6598 * Dispatches an {@link AccessibilityEvent} to the {@link View} first and then 6599 * to its children for adding their text content to the event. Note that the 6600 * event text is populated in a separate dispatch path since we add to the 6601 * event not only the text of the source but also the text of all its descendants. 6602 * A typical implementation will call 6603 * {@link #onPopulateAccessibilityEvent(AccessibilityEvent)} on the this view 6604 * and then call the {@link #dispatchPopulateAccessibilityEvent(AccessibilityEvent)} 6605 * on each child. Override this method if custom population of the event text 6606 * content is required. 6607 * <p> 6608 * If an {@link AccessibilityDelegate} has been specified via calling 6609 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 6610 * {@link AccessibilityDelegate#dispatchPopulateAccessibilityEvent(View, AccessibilityEvent)} 6611 * is responsible for handling this call. 6612 * </p> 6613 * <p> 6614 * <em>Note:</em> Accessibility events of certain types are not dispatched for 6615 * populating the event text via this method. For details refer to {@link AccessibilityEvent}. 6616 * </p> 6617 * 6618 * @param event The event. 6619 * 6620 * @return True if the event population was completed. 6621 */ 6622 public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) { 6623 if (mAccessibilityDelegate != null) { 6624 return mAccessibilityDelegate.dispatchPopulateAccessibilityEvent(this, event); 6625 } else { 6626 return dispatchPopulateAccessibilityEventInternal(event); 6627 } 6628 } 6629 6630 /** 6631 * @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent) 6632 * 6633 * Note: Called from the default {@link AccessibilityDelegate}. 6634 * 6635 * @hide 6636 */ 6637 public boolean dispatchPopulateAccessibilityEventInternal(AccessibilityEvent event) { 6638 onPopulateAccessibilityEvent(event); 6639 return false; 6640 } 6641 6642 /** 6643 * Called from {@link #dispatchPopulateAccessibilityEvent(AccessibilityEvent)} 6644 * giving a chance to this View to populate the accessibility event with its 6645 * text content. While this method is free to modify event 6646 * attributes other than text content, doing so should normally be performed in 6647 * {@link #onInitializeAccessibilityEvent(AccessibilityEvent)}. 6648 * <p> 6649 * Example: Adding formatted date string to an accessibility event in addition 6650 * to the text added by the super implementation: 6651 * <pre> public void onPopulateAccessibilityEvent(AccessibilityEvent event) { 6652 * super.onPopulateAccessibilityEvent(event); 6653 * final int flags = DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_WEEKDAY; 6654 * String selectedDateUtterance = DateUtils.formatDateTime(mContext, 6655 * mCurrentDate.getTimeInMillis(), flags); 6656 * event.getText().add(selectedDateUtterance); 6657 * }</pre> 6658 * <p> 6659 * If an {@link AccessibilityDelegate} has been specified via calling 6660 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 6661 * {@link AccessibilityDelegate#onPopulateAccessibilityEvent(View, AccessibilityEvent)} 6662 * is responsible for handling this call. 6663 * </p> 6664 * <p class="note"><strong>Note:</strong> Always call the super implementation before adding 6665 * information to the event, in case the default implementation has basic information to add. 6666 * </p> 6667 * 6668 * @param event The accessibility event which to populate. 6669 * 6670 * @see #sendAccessibilityEvent(int) 6671 * @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent) 6672 */ 6673 @CallSuper 6674 public void onPopulateAccessibilityEvent(AccessibilityEvent event) { 6675 if (mAccessibilityDelegate != null) { 6676 mAccessibilityDelegate.onPopulateAccessibilityEvent(this, event); 6677 } else { 6678 onPopulateAccessibilityEventInternal(event); 6679 } 6680 } 6681 6682 /** 6683 * @see #onPopulateAccessibilityEvent(AccessibilityEvent) 6684 * 6685 * Note: Called from the default {@link AccessibilityDelegate}. 6686 * 6687 * @hide 6688 */ 6689 public void onPopulateAccessibilityEventInternal(AccessibilityEvent event) { 6690 } 6691 6692 /** 6693 * Initializes an {@link AccessibilityEvent} with information about 6694 * this View which is the event source. In other words, the source of 6695 * an accessibility event is the view whose state change triggered firing 6696 * the event. 6697 * <p> 6698 * Example: Setting the password property of an event in addition 6699 * to properties set by the super implementation: 6700 * <pre> public void onInitializeAccessibilityEvent(AccessibilityEvent event) { 6701 * super.onInitializeAccessibilityEvent(event); 6702 * event.setPassword(true); 6703 * }</pre> 6704 * <p> 6705 * If an {@link AccessibilityDelegate} has been specified via calling 6706 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 6707 * {@link AccessibilityDelegate#onInitializeAccessibilityEvent(View, AccessibilityEvent)} 6708 * is responsible for handling this call. 6709 * </p> 6710 * <p class="note"><strong>Note:</strong> Always call the super implementation before adding 6711 * information to the event, in case the default implementation has basic information to add. 6712 * </p> 6713 * @param event The event to initialize. 6714 * 6715 * @see #sendAccessibilityEvent(int) 6716 * @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent) 6717 */ 6718 @CallSuper 6719 public void onInitializeAccessibilityEvent(AccessibilityEvent event) { 6720 if (mAccessibilityDelegate != null) { 6721 mAccessibilityDelegate.onInitializeAccessibilityEvent(this, event); 6722 } else { 6723 onInitializeAccessibilityEventInternal(event); 6724 } 6725 } 6726 6727 /** 6728 * @see #onInitializeAccessibilityEvent(AccessibilityEvent) 6729 * 6730 * Note: Called from the default {@link AccessibilityDelegate}. 6731 * 6732 * @hide 6733 */ 6734 public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) { 6735 event.setSource(this); 6736 event.setClassName(getAccessibilityClassName()); 6737 event.setPackageName(getContext().getPackageName()); 6738 event.setEnabled(isEnabled()); 6739 event.setContentDescription(mContentDescription); 6740 6741 switch (event.getEventType()) { 6742 case AccessibilityEvent.TYPE_VIEW_FOCUSED: { 6743 ArrayList<View> focusablesTempList = (mAttachInfo != null) 6744 ? mAttachInfo.mTempArrayList : new ArrayList<View>(); 6745 getRootView().addFocusables(focusablesTempList, View.FOCUS_FORWARD, FOCUSABLES_ALL); 6746 event.setItemCount(focusablesTempList.size()); 6747 event.setCurrentItemIndex(focusablesTempList.indexOf(this)); 6748 if (mAttachInfo != null) { 6749 focusablesTempList.clear(); 6750 } 6751 } break; 6752 case AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED: { 6753 CharSequence text = getIterableTextForAccessibility(); 6754 if (text != null && text.length() > 0) { 6755 event.setFromIndex(getAccessibilitySelectionStart()); 6756 event.setToIndex(getAccessibilitySelectionEnd()); 6757 event.setItemCount(text.length()); 6758 } 6759 } break; 6760 } 6761 } 6762 6763 /** 6764 * Returns an {@link AccessibilityNodeInfo} representing this view from the 6765 * point of view of an {@link android.accessibilityservice.AccessibilityService}. 6766 * This method is responsible for obtaining an accessibility node info from a 6767 * pool of reusable instances and calling 6768 * {@link #onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} on this view to 6769 * initialize the former. 6770 * <p> 6771 * Note: The client is responsible for recycling the obtained instance by calling 6772 * {@link AccessibilityNodeInfo#recycle()} to minimize object creation. 6773 * </p> 6774 * 6775 * @return A populated {@link AccessibilityNodeInfo}. 6776 * 6777 * @see AccessibilityNodeInfo 6778 */ 6779 public AccessibilityNodeInfo createAccessibilityNodeInfo() { 6780 if (mAccessibilityDelegate != null) { 6781 return mAccessibilityDelegate.createAccessibilityNodeInfo(this); 6782 } else { 6783 return createAccessibilityNodeInfoInternal(); 6784 } 6785 } 6786 6787 /** 6788 * @see #createAccessibilityNodeInfo() 6789 * 6790 * @hide 6791 */ 6792 public AccessibilityNodeInfo createAccessibilityNodeInfoInternal() { 6793 AccessibilityNodeProvider provider = getAccessibilityNodeProvider(); 6794 if (provider != null) { 6795 return provider.createAccessibilityNodeInfo(AccessibilityNodeProvider.HOST_VIEW_ID); 6796 } else { 6797 AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain(this); 6798 onInitializeAccessibilityNodeInfo(info); 6799 return info; 6800 } 6801 } 6802 6803 /** 6804 * Initializes an {@link AccessibilityNodeInfo} with information about this view. 6805 * The base implementation sets: 6806 * <ul> 6807 * <li>{@link AccessibilityNodeInfo#setParent(View)},</li> 6808 * <li>{@link AccessibilityNodeInfo#setBoundsInParent(Rect)},</li> 6809 * <li>{@link AccessibilityNodeInfo#setBoundsInScreen(Rect)},</li> 6810 * <li>{@link AccessibilityNodeInfo#setPackageName(CharSequence)},</li> 6811 * <li>{@link AccessibilityNodeInfo#setClassName(CharSequence)},</li> 6812 * <li>{@link AccessibilityNodeInfo#setContentDescription(CharSequence)},</li> 6813 * <li>{@link AccessibilityNodeInfo#setEnabled(boolean)},</li> 6814 * <li>{@link AccessibilityNodeInfo#setClickable(boolean)},</li> 6815 * <li>{@link AccessibilityNodeInfo#setFocusable(boolean)},</li> 6816 * <li>{@link AccessibilityNodeInfo#setFocused(boolean)},</li> 6817 * <li>{@link AccessibilityNodeInfo#setLongClickable(boolean)},</li> 6818 * <li>{@link AccessibilityNodeInfo#setSelected(boolean)},</li> 6819 * <li>{@link AccessibilityNodeInfo#setContextClickable(boolean)}</li> 6820 * </ul> 6821 * <p> 6822 * Subclasses should override this method, call the super implementation, 6823 * and set additional attributes. 6824 * </p> 6825 * <p> 6826 * If an {@link AccessibilityDelegate} has been specified via calling 6827 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 6828 * {@link AccessibilityDelegate#onInitializeAccessibilityNodeInfo(View, AccessibilityNodeInfo)} 6829 * is responsible for handling this call. 6830 * </p> 6831 * 6832 * @param info The instance to initialize. 6833 */ 6834 @CallSuper 6835 public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { 6836 if (mAccessibilityDelegate != null) { 6837 mAccessibilityDelegate.onInitializeAccessibilityNodeInfo(this, info); 6838 } else { 6839 onInitializeAccessibilityNodeInfoInternal(info); 6840 } 6841 } 6842 6843 /** 6844 * Gets the location of this view in screen coordinates. 6845 * 6846 * @param outRect The output location 6847 * @hide 6848 */ 6849 public void getBoundsOnScreen(Rect outRect) { 6850 getBoundsOnScreen(outRect, false); 6851 } 6852 6853 /** 6854 * Gets the location of this view in screen coordinates. 6855 * 6856 * @param outRect The output location 6857 * @param clipToParent Whether to clip child bounds to the parent ones. 6858 * @hide 6859 */ 6860 public void getBoundsOnScreen(Rect outRect, boolean clipToParent) { 6861 if (mAttachInfo == null) { 6862 return; 6863 } 6864 6865 RectF position = mAttachInfo.mTmpTransformRect; 6866 position.set(0, 0, mRight - mLeft, mBottom - mTop); 6867 6868 if (!hasIdentityMatrix()) { 6869 getMatrix().mapRect(position); 6870 } 6871 6872 position.offset(mLeft, mTop); 6873 6874 ViewParent parent = mParent; 6875 while (parent instanceof View) { 6876 View parentView = (View) parent; 6877 6878 position.offset(-parentView.mScrollX, -parentView.mScrollY); 6879 6880 if (clipToParent) { 6881 position.left = Math.max(position.left, 0); 6882 position.top = Math.max(position.top, 0); 6883 position.right = Math.min(position.right, parentView.getWidth()); 6884 position.bottom = Math.min(position.bottom, parentView.getHeight()); 6885 } 6886 6887 if (!parentView.hasIdentityMatrix()) { 6888 parentView.getMatrix().mapRect(position); 6889 } 6890 6891 position.offset(parentView.mLeft, parentView.mTop); 6892 6893 parent = parentView.mParent; 6894 } 6895 6896 if (parent instanceof ViewRootImpl) { 6897 ViewRootImpl viewRootImpl = (ViewRootImpl) parent; 6898 position.offset(0, -viewRootImpl.mCurScrollY); 6899 } 6900 6901 position.offset(mAttachInfo.mWindowLeft, mAttachInfo.mWindowTop); 6902 6903 outRect.set(Math.round(position.left), Math.round(position.top), 6904 Math.round(position.right), Math.round(position.bottom)); 6905 } 6906 6907 /** 6908 * Return the class name of this object to be used for accessibility purposes. 6909 * Subclasses should only override this if they are implementing something that 6910 * should be seen as a completely new class of view when used by accessibility, 6911 * unrelated to the class it is deriving from. This is used to fill in 6912 * {@link AccessibilityNodeInfo#setClassName AccessibilityNodeInfo.setClassName}. 6913 */ 6914 public CharSequence getAccessibilityClassName() { 6915 return View.class.getName(); 6916 } 6917 6918 /** 6919 * Called when assist structure is being retrieved from a view as part of 6920 * {@link android.app.Activity#onProvideAssistData Activity.onProvideAssistData}. 6921 * @param structure Fill in with structured view data. The default implementation 6922 * fills in all data that can be inferred from the view itself. 6923 */ 6924 public void onProvideStructure(ViewStructure structure) { 6925 onProvideStructureForAssistOrAutoFill(structure, false); 6926 } 6927 6928 /** 6929 * Called when assist structure is being retrieved from a view as part of an auto-fill request. 6930 * 6931 * <p>When implementing this method, subclasses must also: 6932 * 6933 * <ol> 6934 * <li>Implement {@link #autoFill(AutoFillValue)}, {@link #getAutoFillType()} 6935 * and {@link #getAutoFillValue()}. 6936 * <li>Call {@link android.view.autofill.AutoFillManager#virtualValueChanged(View, int, 6937 * AutoFillValue)} when its value changed. 6938 * </ol> 6939 * 6940 * @param structure Fill in with structured view data. The default implementation 6941 * fills in all data that can be inferred from the view itself. 6942 * @param flags optional flags (currently {@code 0}). 6943 */ 6944 public void onProvideAutoFillStructure(ViewStructure structure, int flags) { 6945 onProvideStructureForAssistOrAutoFill(structure, true); 6946 } 6947 6948 private void onProvideStructureForAssistOrAutoFill(ViewStructure structure, 6949 boolean forAutoFill) { 6950 final int id = mID; 6951 if (id != NO_ID && !isViewIdGenerated(id)) { 6952 String pkg, type, entry; 6953 try { 6954 final Resources res = getResources(); 6955 entry = res.getResourceEntryName(id); 6956 type = res.getResourceTypeName(id); 6957 pkg = res.getResourcePackageName(id); 6958 } catch (Resources.NotFoundException e) { 6959 entry = type = pkg = null; 6960 } 6961 structure.setId(id, pkg, type, entry); 6962 } else { 6963 structure.setId(id, null, null, null); 6964 } 6965 6966 if (forAutoFill) { 6967 final AutoFillType autoFillType = getAutoFillType(); 6968 // Don't need to fill auto-fill info if view does not support it. 6969 // For example, only TextViews that are editable support auto-fill 6970 if (autoFillType != null) { 6971 // The auto-fill id needs to be unique, but its value doesn't matter, so it's better 6972 // to reuse the accessibility id to save space. 6973 structure.setAutoFillId(getAccessibilityViewId()); 6974 structure.setAutoFillType(autoFillType); 6975 structure.setAutoFillValue(getAutoFillValue()); 6976 } 6977 } 6978 6979 structure.setDimens(mLeft, mTop, mScrollX, mScrollY, mRight - mLeft, mBottom - mTop); 6980 if (!hasIdentityMatrix()) { 6981 structure.setTransformation(getMatrix()); 6982 } 6983 structure.setElevation(getZ()); 6984 structure.setVisibility(getVisibility()); 6985 structure.setEnabled(isEnabled()); 6986 if (isClickable()) { 6987 structure.setClickable(true); 6988 } 6989 if (isFocusable()) { 6990 structure.setFocusable(true); 6991 } 6992 if (isFocused()) { 6993 structure.setFocused(true); 6994 } 6995 if (isAccessibilityFocused()) { 6996 structure.setAccessibilityFocused(true); 6997 } 6998 if (isSelected()) { 6999 structure.setSelected(true); 7000 } 7001 if (isActivated()) { 7002 structure.setActivated(true); 7003 } 7004 if (isLongClickable()) { 7005 structure.setLongClickable(true); 7006 } 7007 if (this instanceof Checkable) { 7008 structure.setCheckable(true); 7009 if (((Checkable)this).isChecked()) { 7010 structure.setChecked(true); 7011 } 7012 } 7013 if (isContextClickable()) { 7014 structure.setContextClickable(true); 7015 } 7016 structure.setClassName(getAccessibilityClassName().toString()); 7017 structure.setContentDescription(getContentDescription()); 7018 } 7019 7020 /** 7021 * Called when assist structure is being retrieved from a view as part of 7022 * {@link android.app.Activity#onProvideAssistData Activity.onProvideAssistData} to 7023 * generate additional virtual structure under this view. The defaullt implementation 7024 * uses {@link #getAccessibilityNodeProvider()} to try to generate this from the 7025 * view's virtual accessibility nodes, if any. You can override this for a more 7026 * optimal implementation providing this data. 7027 */ 7028 public void onProvideVirtualStructure(ViewStructure structure) { 7029 onProvideVirtualStructureForAssistOrAutoFill(structure, false); 7030 } 7031 7032 /** 7033 * Called when assist structure is being retrieved from a view as part of an auto-fill request 7034 * to generate additional virtual structure under this view. 7035 * 7036 * <p>The default implementation uses {@link #getAccessibilityNodeProvider()} to try to 7037 * generate this from the view's virtual accessibility nodes, if any. You can override this 7038 * for a more optimal implementation providing this data. 7039 * 7040 * <p>When implementing this method, subclasses must follow the rules below: 7041 * 7042 * <ol> 7043 * <li>Also implement {@link #autoFillVirtual(int, AutoFillValue)} to auto-fill the virtual 7044 * children. 7045 * <li>Call {@link android.view.autofill.AutoFillManager#virtualFocusChanged(View, int, Rect, 7046 * boolean)} when the focus inside the view changed. 7047 * <li>Call {@link android.view.autofill.AutoFillManager#virtualValueChanged(View, int, 7048 * AutoFillValue)} when the value of a child changed. 7049 * <li>Call {@link android.view.autofill.AutoFillManager#reset()} when the auto-fill context 7050 * of the view structure changed. 7051 * </ol> 7052 * 7053 * @param structure Fill in with structured view data. 7054 * @param flags optional flags (currently {@code 0}). 7055 */ 7056 public void onProvideAutoFillVirtualStructure(ViewStructure structure, int flags) { 7057 onProvideVirtualStructureForAssistOrAutoFill(structure, true); 7058 } 7059 7060 private void onProvideVirtualStructureForAssistOrAutoFill(ViewStructure structure, 7061 boolean forAutoFill) { 7062 // NOTE: currently flags are only used for AutoFill; if they're used for Assist as well, 7063 // this method should take a boolean with the type of request. 7064 AccessibilityNodeProvider provider = getAccessibilityNodeProvider(); 7065 if (provider != null) { 7066 AccessibilityNodeInfo info = createAccessibilityNodeInfo(); 7067 structure.setChildCount(1); 7068 ViewStructure root = structure.newChild(0); 7069 populateVirtualStructure(root, provider, info, forAutoFill); 7070 info.recycle(); 7071 } 7072 } 7073 7074 /** 7075 * Automatically fills the content of this view with the {@code value}. 7076 * 7077 * <p>By default does nothing, but views should override it (and {@link #getAutoFillType()}, 7078 * {@link #getAutoFillValue()}, and {@link #onProvideAutoFillStructure(ViewStructure, int)} 7079 * to support the AutoFill Framework. 7080 * 7081 * <p>Typically, it is implemented by: 7082 * 7083 * <ol> 7084 * <li>Calling the proper getter method on {@link AutoFillValue} to fetch the actual value. 7085 * <li>Passing the actual value to the equivalent setter in the view. 7086 * <ol> 7087 * 7088 * <p>For example, a text-field view would call: 7089 * 7090 * <pre class="prettyprint"> 7091 * CharSequence text = value.getTextValue(); 7092 * if (text != null) { 7093 * setText(text); 7094 * } 7095 * </pre> 7096 * 7097 * @param value value to be auto-filled. 7098 */ 7099 public void autoFill(@SuppressWarnings("unused") AutoFillValue value) { 7100 } 7101 7102 /** 7103 * Automatically fills the content of a virtual view with the {@code value} 7104 * 7105 * <p>See {@link #autoFill(AutoFillValue)} and 7106 * {@link #onProvideAutoFillVirtualStructure(ViewStructure, int)} for more info. 7107 * 7108 * @param value value to be auto-filled. 7109 * @param virtualId id identifying the virtual child inside the custom view. 7110 */ 7111 public void autoFillVirtual(@SuppressWarnings("unused") int virtualId, 7112 @SuppressWarnings("unused") AutoFillValue value) { 7113 } 7114 7115 /** 7116 * Describes the auto-fill type that should be used on calls to 7117 * {@link #autoFill(AutoFillValue)} and {@link #autoFillVirtual(int, AutoFillValue)}. 7118 7119 * <p>By default returns {@code null}, but views should override it (and 7120 * {@link #autoFill(AutoFillValue)} to support the AutoFill Framework. 7121 */ 7122 @Nullable 7123 public AutoFillType getAutoFillType() { 7124 return null; 7125 } 7126 7127 /** 7128 * Gets the {@link View}'s current auto-fill value. 7129 * 7130 * <p>By default returns {@code null}, but views should override it, 7131 * {@link #autoFill(AutoFillValue)}, and {@link #getAutoFillType()} to support the AutoFill 7132 * Framework. 7133 */ 7134 @Nullable 7135 public AutoFillValue getAutoFillValue() { 7136 return null; 7137 } 7138 7139 @Nullable 7140 private AutoFillManager getAutoFillManager() { 7141 return mContext.getSystemService(AutoFillManager.class); 7142 } 7143 7144 private boolean isAutoFillable() { 7145 return getAutoFillType() != null && !isAutoFillBlocked(); 7146 } 7147 7148 private void populateVirtualStructure(ViewStructure structure, 7149 AccessibilityNodeProvider provider, AccessibilityNodeInfo info, boolean forAutoFill) { 7150 structure.setId(AccessibilityNodeInfo.getVirtualDescendantId(info.getSourceNodeId()), 7151 null, null, null); 7152 Rect rect = structure.getTempRect(); 7153 info.getBoundsInParent(rect); 7154 structure.setDimens(rect.left, rect.top, 0, 0, rect.width(), rect.height()); 7155 structure.setVisibility(VISIBLE); 7156 structure.setEnabled(info.isEnabled()); 7157 if (info.isClickable()) { 7158 structure.setClickable(true); 7159 } 7160 if (info.isFocusable()) { 7161 structure.setFocusable(true); 7162 } 7163 if (info.isFocused()) { 7164 structure.setFocused(true); 7165 } 7166 if (info.isAccessibilityFocused()) { 7167 structure.setAccessibilityFocused(true); 7168 } 7169 if (info.isSelected()) { 7170 structure.setSelected(true); 7171 } 7172 if (info.isLongClickable()) { 7173 structure.setLongClickable(true); 7174 } 7175 if (info.isCheckable()) { 7176 structure.setCheckable(true); 7177 if (info.isChecked()) { 7178 structure.setChecked(true); 7179 } 7180 } 7181 if (info.isContextClickable()) { 7182 structure.setContextClickable(true); 7183 } 7184 CharSequence cname = info.getClassName(); 7185 structure.setClassName(cname != null ? cname.toString() : null); 7186 structure.setContentDescription(info.getContentDescription()); 7187 if (!forAutoFill && (info.getText() != null || info.getError() != null)) { 7188 // TODO(b/33197203) (b/33269702): when sanitized, try to use the Accessibility API to 7189 // just set sanitized values (like text coming from resource files), rather than not 7190 // setting it at all. 7191 structure.setText(info.getText(), info.getTextSelectionStart(), 7192 info.getTextSelectionEnd()); 7193 } 7194 final int NCHILDREN = info.getChildCount(); 7195 if (NCHILDREN > 0) { 7196 structure.setChildCount(NCHILDREN); 7197 for (int i=0; i<NCHILDREN; i++) { 7198 AccessibilityNodeInfo cinfo = provider.createAccessibilityNodeInfo( 7199 AccessibilityNodeInfo.getVirtualDescendantId(info.getChildId(i))); 7200 ViewStructure child = structure.newChild(i); 7201 populateVirtualStructure(child, provider, cinfo, forAutoFill); 7202 cinfo.recycle(); 7203 } 7204 } 7205 } 7206 7207 /** 7208 * Dispatch creation of {@link ViewStructure} down the hierarchy. The default 7209 * implementation calls {@link #onProvideStructure} and 7210 * {@link #onProvideVirtualStructure}. 7211 */ 7212 public void dispatchProvideStructure(ViewStructure structure) { 7213 dispatchProvideStructureForAssistOrAutoFill(structure, false); 7214 } 7215 7216 /** 7217 * Dispatch creation of {@link ViewStructure} down the hierarchy. 7218 * 7219 * <p>The structure must be filled according to the request type, which is set in the 7220 * {@code flags} parameter - see the documentation on each flag for more details. 7221 * 7222 * <p>The default implementation calls {@link #onProvideAutoFillStructure(ViewStructure, int)} 7223 * and {@link #onProvideAutoFillVirtualStructure(ViewStructure, int)}. 7224 * 7225 * @param structure Fill in with structured view data. 7226 * @param flags optional flags (currently {@code 0}). 7227 */ 7228 public void dispatchProvideAutoFillStructure(ViewStructure structure, int flags) { 7229 dispatchProvideStructureForAssistOrAutoFill(structure, true); 7230 } 7231 7232 private void dispatchProvideStructureForAssistOrAutoFill(ViewStructure structure, 7233 boolean forAutoFill) { 7234 boolean blocked = forAutoFill ? isAutoFillBlocked() : isAssistBlocked(); 7235 if (!blocked) { 7236 if (forAutoFill) { 7237 // The auto-fill id needs to be unique, but its value doesn't matter, 7238 // so it's better to reuse the accessibility id to save space. 7239 structure.setAutoFillId(getAccessibilityViewId()); 7240 // NOTE: flags are not currently supported, hence 0 7241 onProvideAutoFillStructure(structure, 0); 7242 onProvideAutoFillVirtualStructure(structure, 0); 7243 } else { 7244 onProvideStructure(structure); 7245 onProvideVirtualStructure(structure); 7246 } 7247 } else { 7248 structure.setClassName(getAccessibilityClassName().toString()); 7249 structure.setAssistBlocked(true); 7250 } 7251 } 7252 7253 /** 7254 * @see #onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo) 7255 * 7256 * Note: Called from the default {@link AccessibilityDelegate}. 7257 * 7258 * @hide 7259 */ 7260 public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) { 7261 if (mAttachInfo == null) { 7262 return; 7263 } 7264 7265 Rect bounds = mAttachInfo.mTmpInvalRect; 7266 7267 getDrawingRect(bounds); 7268 info.setBoundsInParent(bounds); 7269 7270 getBoundsOnScreen(bounds, true); 7271 info.setBoundsInScreen(bounds); 7272 7273 ViewParent parent = getParentForAccessibility(); 7274 if (parent instanceof View) { 7275 info.setParent((View) parent); 7276 } 7277 7278 if (mID != View.NO_ID) { 7279 View rootView = getRootView(); 7280 if (rootView == null) { 7281 rootView = this; 7282 } 7283 7284 View label = rootView.findLabelForView(this, mID); 7285 if (label != null) { 7286 info.setLabeledBy(label); 7287 } 7288 7289 if ((mAttachInfo.mAccessibilityFetchFlags 7290 & AccessibilityNodeInfo.FLAG_REPORT_VIEW_IDS) != 0 7291 && Resources.resourceHasPackage(mID)) { 7292 try { 7293 String viewId = getResources().getResourceName(mID); 7294 info.setViewIdResourceName(viewId); 7295 } catch (Resources.NotFoundException nfe) { 7296 /* ignore */ 7297 } 7298 } 7299 } 7300 7301 if (mLabelForId != View.NO_ID) { 7302 View rootView = getRootView(); 7303 if (rootView == null) { 7304 rootView = this; 7305 } 7306 View labeled = rootView.findViewInsideOutShouldExist(this, mLabelForId); 7307 if (labeled != null) { 7308 info.setLabelFor(labeled); 7309 } 7310 } 7311 7312 if (mAccessibilityTraversalBeforeId != View.NO_ID) { 7313 View rootView = getRootView(); 7314 if (rootView == null) { 7315 rootView = this; 7316 } 7317 View next = rootView.findViewInsideOutShouldExist(this, 7318 mAccessibilityTraversalBeforeId); 7319 if (next != null && next.includeForAccessibility()) { 7320 info.setTraversalBefore(next); 7321 } 7322 } 7323 7324 if (mAccessibilityTraversalAfterId != View.NO_ID) { 7325 View rootView = getRootView(); 7326 if (rootView == null) { 7327 rootView = this; 7328 } 7329 View next = rootView.findViewInsideOutShouldExist(this, 7330 mAccessibilityTraversalAfterId); 7331 if (next != null && next.includeForAccessibility()) { 7332 info.setTraversalAfter(next); 7333 } 7334 } 7335 7336 info.setVisibleToUser(isVisibleToUser()); 7337 7338 info.setImportantForAccessibility(isImportantForAccessibility()); 7339 info.setPackageName(mContext.getPackageName()); 7340 info.setClassName(getAccessibilityClassName()); 7341 info.setContentDescription(getContentDescription()); 7342 7343 info.setEnabled(isEnabled()); 7344 info.setClickable(isClickable()); 7345 info.setFocusable(isFocusable()); 7346 info.setFocused(isFocused()); 7347 info.setAccessibilityFocused(isAccessibilityFocused()); 7348 info.setSelected(isSelected()); 7349 info.setLongClickable(isLongClickable()); 7350 info.setContextClickable(isContextClickable()); 7351 info.setLiveRegion(getAccessibilityLiveRegion()); 7352 7353 // TODO: These make sense only if we are in an AdapterView but all 7354 // views can be selected. Maybe from accessibility perspective 7355 // we should report as selectable view in an AdapterView. 7356 info.addAction(AccessibilityNodeInfo.ACTION_SELECT); 7357 info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_SELECTION); 7358 7359 if (isFocusable()) { 7360 if (isFocused()) { 7361 info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_FOCUS); 7362 } else { 7363 info.addAction(AccessibilityNodeInfo.ACTION_FOCUS); 7364 } 7365 } 7366 7367 if (!isAccessibilityFocused()) { 7368 info.addAction(AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS); 7369 } else { 7370 info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS); 7371 } 7372 7373 if (isClickable() && isEnabled()) { 7374 info.addAction(AccessibilityNodeInfo.ACTION_CLICK); 7375 } 7376 7377 if (isLongClickable() && isEnabled()) { 7378 info.addAction(AccessibilityNodeInfo.ACTION_LONG_CLICK); 7379 } 7380 7381 if (isContextClickable() && isEnabled()) { 7382 info.addAction(AccessibilityAction.ACTION_CONTEXT_CLICK); 7383 } 7384 7385 CharSequence text = getIterableTextForAccessibility(); 7386 if (text != null && text.length() > 0) { 7387 info.setTextSelection(getAccessibilitySelectionStart(), getAccessibilitySelectionEnd()); 7388 7389 info.addAction(AccessibilityNodeInfo.ACTION_SET_SELECTION); 7390 info.addAction(AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY); 7391 info.addAction(AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY); 7392 info.setMovementGranularities(AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER 7393 | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD 7394 | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH); 7395 } 7396 7397 info.addAction(AccessibilityAction.ACTION_SHOW_ON_SCREEN); 7398 populateAccessibilityNodeInfoDrawingOrderInParent(info); 7399 } 7400 7401 /** 7402 * Adds extra data to an {@link AccessibilityNodeInfo} based on an explicit request for the 7403 * additional data. 7404 * <p> 7405 * This method only needs overloading if the node is marked as having extra data available. 7406 * </p> 7407 * 7408 * @param info The info to which to add the extra data. Never {@code null}. 7409 * @param extraDataKey A key specifying the type of extra data to add to the info. The 7410 * extra data should be added to the {@link Bundle} returned by 7411 * the info's {@link AccessibilityNodeInfo#getExtras} method. Never 7412 * {@code null}. 7413 * @param arguments A {@link Bundle} holding any arguments relevant for this request. May be 7414 * {@code null} if the service provided no arguments. 7415 * 7416 * @see AccessibilityNodeInfo#setExtraAvailableData 7417 */ 7418 public void addExtraDataToAccessibilityNodeInfo( 7419 @NonNull AccessibilityNodeInfo info, @NonNull String extraDataKey, 7420 @Nullable Bundle arguments) { 7421 } 7422 7423 /** 7424 * Determine the order in which this view will be drawn relative to its siblings for a11y 7425 * 7426 * @param info The info whose drawing order should be populated 7427 */ 7428 private void populateAccessibilityNodeInfoDrawingOrderInParent(AccessibilityNodeInfo info) { 7429 /* 7430 * If the view's bounds haven't been set yet, layout has not completed. In that situation, 7431 * drawing order may not be well-defined, and some Views with custom drawing order may 7432 * not be initialized sufficiently to respond properly getChildDrawingOrder. 7433 */ 7434 if ((mPrivateFlags & PFLAG_HAS_BOUNDS) == 0) { 7435 info.setDrawingOrder(0); 7436 return; 7437 } 7438 int drawingOrderInParent = 1; 7439 // Iterate up the hierarchy if parents are not important for a11y 7440 View viewAtDrawingLevel = this; 7441 final ViewParent parent = getParentForAccessibility(); 7442 while (viewAtDrawingLevel != parent) { 7443 final ViewParent currentParent = viewAtDrawingLevel.getParent(); 7444 if (!(currentParent instanceof ViewGroup)) { 7445 // Should only happen for the Decor 7446 drawingOrderInParent = 0; 7447 break; 7448 } else { 7449 final ViewGroup parentGroup = (ViewGroup) currentParent; 7450 final int childCount = parentGroup.getChildCount(); 7451 if (childCount > 1) { 7452 List<View> preorderedList = parentGroup.buildOrderedChildList(); 7453 if (preorderedList != null) { 7454 final int childDrawIndex = preorderedList.indexOf(viewAtDrawingLevel); 7455 for (int i = 0; i < childDrawIndex; i++) { 7456 drawingOrderInParent += numViewsForAccessibility(preorderedList.get(i)); 7457 } 7458 } else { 7459 final int childIndex = parentGroup.indexOfChild(viewAtDrawingLevel); 7460 final boolean customOrder = parentGroup.isChildrenDrawingOrderEnabled(); 7461 final int childDrawIndex = ((childIndex >= 0) && customOrder) ? parentGroup 7462 .getChildDrawingOrder(childCount, childIndex) : childIndex; 7463 final int numChildrenToIterate = customOrder ? childCount : childDrawIndex; 7464 if (childDrawIndex != 0) { 7465 for (int i = 0; i < numChildrenToIterate; i++) { 7466 final int otherDrawIndex = (customOrder ? 7467 parentGroup.getChildDrawingOrder(childCount, i) : i); 7468 if (otherDrawIndex < childDrawIndex) { 7469 drawingOrderInParent += 7470 numViewsForAccessibility(parentGroup.getChildAt(i)); 7471 } 7472 } 7473 } 7474 } 7475 } 7476 } 7477 viewAtDrawingLevel = (View) currentParent; 7478 } 7479 info.setDrawingOrder(drawingOrderInParent); 7480 } 7481 7482 private static int numViewsForAccessibility(View view) { 7483 if (view != null) { 7484 if (view.includeForAccessibility()) { 7485 return 1; 7486 } else if (view instanceof ViewGroup) { 7487 return ((ViewGroup) view).getNumChildrenForAccessibility(); 7488 } 7489 } 7490 return 0; 7491 } 7492 7493 private View findLabelForView(View view, int labeledId) { 7494 if (mMatchLabelForPredicate == null) { 7495 mMatchLabelForPredicate = new MatchLabelForPredicate(); 7496 } 7497 mMatchLabelForPredicate.mLabeledId = labeledId; 7498 return findViewByPredicateInsideOut(view, mMatchLabelForPredicate); 7499 } 7500 7501 /** 7502 * Computes whether this view is visible to the user. Such a view is 7503 * attached, visible, all its predecessors are visible, it is not clipped 7504 * entirely by its predecessors, and has an alpha greater than zero. 7505 * 7506 * @return Whether the view is visible on the screen. 7507 * 7508 * @hide 7509 */ 7510 protected boolean isVisibleToUser() { 7511 return isVisibleToUser(null); 7512 } 7513 7514 /** 7515 * Computes whether the given portion of this view is visible to the user. 7516 * Such a view is attached, visible, all its predecessors are visible, 7517 * has an alpha greater than zero, and the specified portion is not 7518 * clipped entirely by its predecessors. 7519 * 7520 * @param boundInView the portion of the view to test; coordinates should be relative; may be 7521 * <code>null</code>, and the entire view will be tested in this case. 7522 * When <code>true</code> is returned by the function, the actual visible 7523 * region will be stored in this parameter; that is, if boundInView is fully 7524 * contained within the view, no modification will be made, otherwise regions 7525 * outside of the visible area of the view will be clipped. 7526 * 7527 * @return Whether the specified portion of the view is visible on the screen. 7528 * 7529 * @hide 7530 */ 7531 protected boolean isVisibleToUser(Rect boundInView) { 7532 if (mAttachInfo != null) { 7533 // Attached to invisible window means this view is not visible. 7534 if (mAttachInfo.mWindowVisibility != View.VISIBLE) { 7535 return false; 7536 } 7537 // An invisible predecessor or one with alpha zero means 7538 // that this view is not visible to the user. 7539 Object current = this; 7540 while (current instanceof View) { 7541 View view = (View) current; 7542 // We have attach info so this view is attached and there is no 7543 // need to check whether we reach to ViewRootImpl on the way up. 7544 if (view.getAlpha() <= 0 || view.getTransitionAlpha() <= 0 || 7545 view.getVisibility() != VISIBLE) { 7546 return false; 7547 } 7548 current = view.mParent; 7549 } 7550 // Check if the view is entirely covered by its predecessors. 7551 Rect visibleRect = mAttachInfo.mTmpInvalRect; 7552 Point offset = mAttachInfo.mPoint; 7553 if (!getGlobalVisibleRect(visibleRect, offset)) { 7554 return false; 7555 } 7556 // Check if the visible portion intersects the rectangle of interest. 7557 if (boundInView != null) { 7558 visibleRect.offset(-offset.x, -offset.y); 7559 return boundInView.intersect(visibleRect); 7560 } 7561 return true; 7562 } 7563 return false; 7564 } 7565 7566 /** 7567 * Returns the delegate for implementing accessibility support via 7568 * composition. For more details see {@link AccessibilityDelegate}. 7569 * 7570 * @return The delegate, or null if none set. 7571 * 7572 * @hide 7573 */ 7574 public AccessibilityDelegate getAccessibilityDelegate() { 7575 return mAccessibilityDelegate; 7576 } 7577 7578 /** 7579 * Sets a delegate for implementing accessibility support via composition 7580 * (as opposed to inheritance). For more details, see 7581 * {@link AccessibilityDelegate}. 7582 * <p> 7583 * <strong>Note:</strong> On platform versions prior to 7584 * {@link android.os.Build.VERSION_CODES#M API 23}, delegate methods on 7585 * views in the {@code android.widget.*} package are called <i>before</i> 7586 * host methods. This prevents certain properties such as class name from 7587 * being modified by overriding 7588 * {@link AccessibilityDelegate#onInitializeAccessibilityNodeInfo(View, AccessibilityNodeInfo)}, 7589 * as any changes will be overwritten by the host class. 7590 * <p> 7591 * Starting in {@link android.os.Build.VERSION_CODES#M API 23}, delegate 7592 * methods are called <i>after</i> host methods, which all properties to be 7593 * modified without being overwritten by the host class. 7594 * 7595 * @param delegate the object to which accessibility method calls should be 7596 * delegated 7597 * @see AccessibilityDelegate 7598 */ 7599 public void setAccessibilityDelegate(@Nullable AccessibilityDelegate delegate) { 7600 mAccessibilityDelegate = delegate; 7601 } 7602 7603 /** 7604 * Gets the provider for managing a virtual view hierarchy rooted at this View 7605 * and reported to {@link android.accessibilityservice.AccessibilityService}s 7606 * that explore the window content. 7607 * <p> 7608 * If this method returns an instance, this instance is responsible for managing 7609 * {@link AccessibilityNodeInfo}s describing the virtual sub-tree rooted at this 7610 * View including the one representing the View itself. Similarly the returned 7611 * instance is responsible for performing accessibility actions on any virtual 7612 * view or the root view itself. 7613 * </p> 7614 * <p> 7615 * If an {@link AccessibilityDelegate} has been specified via calling 7616 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 7617 * {@link AccessibilityDelegate#getAccessibilityNodeProvider(View)} 7618 * is responsible for handling this call. 7619 * </p> 7620 * 7621 * @return The provider. 7622 * 7623 * @see AccessibilityNodeProvider 7624 */ 7625 public AccessibilityNodeProvider getAccessibilityNodeProvider() { 7626 if (mAccessibilityDelegate != null) { 7627 return mAccessibilityDelegate.getAccessibilityNodeProvider(this); 7628 } else { 7629 return null; 7630 } 7631 } 7632 7633 /** 7634 * Gets the unique identifier of this view on the screen for accessibility purposes. 7635 * 7636 * @return The view accessibility id. 7637 * 7638 * @hide 7639 */ 7640 public int getAccessibilityViewId() { 7641 if (mAccessibilityViewId == NO_ID) { 7642 mAccessibilityViewId = sNextAccessibilityViewId++; 7643 } 7644 return mAccessibilityViewId; 7645 } 7646 7647 /** 7648 * Gets the unique identifier of the window in which this View reseides. 7649 * 7650 * @return The window accessibility id. 7651 * 7652 * @hide 7653 */ 7654 public int getAccessibilityWindowId() { 7655 return mAttachInfo != null ? mAttachInfo.mAccessibilityWindowId 7656 : AccessibilityNodeInfo.UNDEFINED_ITEM_ID; 7657 } 7658 7659 /** 7660 * Returns the {@link View}'s content description. 7661 * <p> 7662 * <strong>Note:</strong> Do not override this method, as it will have no 7663 * effect on the content description presented to accessibility services. 7664 * You must call {@link #setContentDescription(CharSequence)} to modify the 7665 * content description. 7666 * 7667 * @return the content description 7668 * @see #setContentDescription(CharSequence) 7669 * @attr ref android.R.styleable#View_contentDescription 7670 */ 7671 @ViewDebug.ExportedProperty(category = "accessibility") 7672 public CharSequence getContentDescription() { 7673 return mContentDescription; 7674 } 7675 7676 /** 7677 * Sets the {@link View}'s content description. 7678 * <p> 7679 * A content description briefly describes the view and is primarily used 7680 * for accessibility support to determine how a view should be presented to 7681 * the user. In the case of a view with no textual representation, such as 7682 * {@link android.widget.ImageButton}, a useful content description 7683 * explains what the view does. For example, an image button with a phone 7684 * icon that is used to place a call may use "Call" as its content 7685 * description. An image of a floppy disk that is used to save a file may 7686 * use "Save". 7687 * 7688 * @param contentDescription The content description. 7689 * @see #getContentDescription() 7690 * @attr ref android.R.styleable#View_contentDescription 7691 */ 7692 @RemotableViewMethod 7693 public void setContentDescription(CharSequence contentDescription) { 7694 if (mContentDescription == null) { 7695 if (contentDescription == null) { 7696 return; 7697 } 7698 } else if (mContentDescription.equals(contentDescription)) { 7699 return; 7700 } 7701 mContentDescription = contentDescription; 7702 final boolean nonEmptyDesc = contentDescription != null && contentDescription.length() > 0; 7703 if (nonEmptyDesc && getImportantForAccessibility() == IMPORTANT_FOR_ACCESSIBILITY_AUTO) { 7704 setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES); 7705 notifySubtreeAccessibilityStateChangedIfNeeded(); 7706 } else { 7707 notifyViewAccessibilityStateChangedIfNeeded( 7708 AccessibilityEvent.CONTENT_CHANGE_TYPE_CONTENT_DESCRIPTION); 7709 } 7710 } 7711 7712 /** 7713 * Sets the id of a view before which this one is visited in accessibility traversal. 7714 * A screen-reader must visit the content of this view before the content of the one 7715 * it precedes. For example, if view B is set to be before view A, then a screen-reader 7716 * will traverse the entire content of B before traversing the entire content of A, 7717 * regardles of what traversal strategy it is using. 7718 * <p> 7719 * Views that do not have specified before/after relationships are traversed in order 7720 * determined by the screen-reader. 7721 * </p> 7722 * <p> 7723 * Setting that this view is before a view that is not important for accessibility 7724 * or if this view is not important for accessibility will have no effect as the 7725 * screen-reader is not aware of unimportant views. 7726 * </p> 7727 * 7728 * @param beforeId The id of a view this one precedes in accessibility traversal. 7729 * 7730 * @attr ref android.R.styleable#View_accessibilityTraversalBefore 7731 * 7732 * @see #setImportantForAccessibility(int) 7733 */ 7734 @RemotableViewMethod 7735 public void setAccessibilityTraversalBefore(int beforeId) { 7736 if (mAccessibilityTraversalBeforeId == beforeId) { 7737 return; 7738 } 7739 mAccessibilityTraversalBeforeId = beforeId; 7740 notifyViewAccessibilityStateChangedIfNeeded( 7741 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 7742 } 7743 7744 /** 7745 * Gets the id of a view before which this one is visited in accessibility traversal. 7746 * 7747 * @return The id of a view this one precedes in accessibility traversal if 7748 * specified, otherwise {@link #NO_ID}. 7749 * 7750 * @see #setAccessibilityTraversalBefore(int) 7751 */ 7752 public int getAccessibilityTraversalBefore() { 7753 return mAccessibilityTraversalBeforeId; 7754 } 7755 7756 /** 7757 * Sets the id of a view after which this one is visited in accessibility traversal. 7758 * A screen-reader must visit the content of the other view before the content of this 7759 * one. For example, if view B is set to be after view A, then a screen-reader 7760 * will traverse the entire content of A before traversing the entire content of B, 7761 * regardles of what traversal strategy it is using. 7762 * <p> 7763 * Views that do not have specified before/after relationships are traversed in order 7764 * determined by the screen-reader. 7765 * </p> 7766 * <p> 7767 * Setting that this view is after a view that is not important for accessibility 7768 * or if this view is not important for accessibility will have no effect as the 7769 * screen-reader is not aware of unimportant views. 7770 * </p> 7771 * 7772 * @param afterId The id of a view this one succedees in accessibility traversal. 7773 * 7774 * @attr ref android.R.styleable#View_accessibilityTraversalAfter 7775 * 7776 * @see #setImportantForAccessibility(int) 7777 */ 7778 @RemotableViewMethod 7779 public void setAccessibilityTraversalAfter(int afterId) { 7780 if (mAccessibilityTraversalAfterId == afterId) { 7781 return; 7782 } 7783 mAccessibilityTraversalAfterId = afterId; 7784 notifyViewAccessibilityStateChangedIfNeeded( 7785 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 7786 } 7787 7788 /** 7789 * Gets the id of a view after which this one is visited in accessibility traversal. 7790 * 7791 * @return The id of a view this one succeedes in accessibility traversal if 7792 * specified, otherwise {@link #NO_ID}. 7793 * 7794 * @see #setAccessibilityTraversalAfter(int) 7795 */ 7796 public int getAccessibilityTraversalAfter() { 7797 return mAccessibilityTraversalAfterId; 7798 } 7799 7800 /** 7801 * Gets the id of a view for which this view serves as a label for 7802 * accessibility purposes. 7803 * 7804 * @return The labeled view id. 7805 */ 7806 @ViewDebug.ExportedProperty(category = "accessibility") 7807 public int getLabelFor() { 7808 return mLabelForId; 7809 } 7810 7811 /** 7812 * Sets the id of a view for which this view serves as a label for 7813 * accessibility purposes. 7814 * 7815 * @param id The labeled view id. 7816 */ 7817 @RemotableViewMethod 7818 public void setLabelFor(@IdRes int id) { 7819 if (mLabelForId == id) { 7820 return; 7821 } 7822 mLabelForId = id; 7823 if (mLabelForId != View.NO_ID 7824 && mID == View.NO_ID) { 7825 mID = generateViewId(); 7826 } 7827 notifyViewAccessibilityStateChangedIfNeeded( 7828 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 7829 } 7830 7831 /** 7832 * Invoked whenever this view loses focus, either by losing window focus or by losing 7833 * focus within its window. This method can be used to clear any state tied to the 7834 * focus. For instance, if a button is held pressed with the trackball and the window 7835 * loses focus, this method can be used to cancel the press. 7836 * 7837 * Subclasses of View overriding this method should always call super.onFocusLost(). 7838 * 7839 * @see #onFocusChanged(boolean, int, android.graphics.Rect) 7840 * @see #onWindowFocusChanged(boolean) 7841 * 7842 * @hide pending API council approval 7843 */ 7844 @CallSuper 7845 protected void onFocusLost() { 7846 resetPressedState(); 7847 } 7848 7849 private void resetPressedState() { 7850 if ((mViewFlags & ENABLED_MASK) == DISABLED) { 7851 return; 7852 } 7853 7854 if (isPressed()) { 7855 setPressed(false); 7856 7857 if (!mHasPerformedLongPress) { 7858 removeLongPressCallback(); 7859 } 7860 } 7861 } 7862 7863 /** 7864 * Returns true if this view has focus 7865 * 7866 * @return True if this view has focus, false otherwise. 7867 */ 7868 @ViewDebug.ExportedProperty(category = "focus") 7869 public boolean isFocused() { 7870 return (mPrivateFlags & PFLAG_FOCUSED) != 0; 7871 } 7872 7873 /** 7874 * Find the view in the hierarchy rooted at this view that currently has 7875 * focus. 7876 * 7877 * @return The view that currently has focus, or null if no focused view can 7878 * be found. 7879 */ 7880 public View findFocus() { 7881 return (mPrivateFlags & PFLAG_FOCUSED) != 0 ? this : null; 7882 } 7883 7884 /** 7885 * Indicates whether this view is one of the set of scrollable containers in 7886 * its window. 7887 * 7888 * @return whether this view is one of the set of scrollable containers in 7889 * its window 7890 * 7891 * @attr ref android.R.styleable#View_isScrollContainer 7892 */ 7893 public boolean isScrollContainer() { 7894 return (mPrivateFlags & PFLAG_SCROLL_CONTAINER_ADDED) != 0; 7895 } 7896 7897 /** 7898 * Change whether this view is one of the set of scrollable containers in 7899 * its window. This will be used to determine whether the window can 7900 * resize or must pan when a soft input area is open -- scrollable 7901 * containers allow the window to use resize mode since the container 7902 * will appropriately shrink. 7903 * 7904 * @attr ref android.R.styleable#View_isScrollContainer 7905 */ 7906 public void setScrollContainer(boolean isScrollContainer) { 7907 if (isScrollContainer) { 7908 if (mAttachInfo != null && (mPrivateFlags&PFLAG_SCROLL_CONTAINER_ADDED) == 0) { 7909 mAttachInfo.mScrollContainers.add(this); 7910 mPrivateFlags |= PFLAG_SCROLL_CONTAINER_ADDED; 7911 } 7912 mPrivateFlags |= PFLAG_SCROLL_CONTAINER; 7913 } else { 7914 if ((mPrivateFlags&PFLAG_SCROLL_CONTAINER_ADDED) != 0) { 7915 mAttachInfo.mScrollContainers.remove(this); 7916 } 7917 mPrivateFlags &= ~(PFLAG_SCROLL_CONTAINER|PFLAG_SCROLL_CONTAINER_ADDED); 7918 } 7919 } 7920 7921 /** 7922 * Returns the quality of the drawing cache. 7923 * 7924 * @return One of {@link #DRAWING_CACHE_QUALITY_AUTO}, 7925 * {@link #DRAWING_CACHE_QUALITY_LOW}, or {@link #DRAWING_CACHE_QUALITY_HIGH} 7926 * 7927 * @see #setDrawingCacheQuality(int) 7928 * @see #setDrawingCacheEnabled(boolean) 7929 * @see #isDrawingCacheEnabled() 7930 * 7931 * @attr ref android.R.styleable#View_drawingCacheQuality 7932 */ 7933 @DrawingCacheQuality 7934 public int getDrawingCacheQuality() { 7935 return mViewFlags & DRAWING_CACHE_QUALITY_MASK; 7936 } 7937 7938 /** 7939 * Set the drawing cache quality of this view. This value is used only when the 7940 * drawing cache is enabled 7941 * 7942 * @param quality One of {@link #DRAWING_CACHE_QUALITY_AUTO}, 7943 * {@link #DRAWING_CACHE_QUALITY_LOW}, or {@link #DRAWING_CACHE_QUALITY_HIGH} 7944 * 7945 * @see #getDrawingCacheQuality() 7946 * @see #setDrawingCacheEnabled(boolean) 7947 * @see #isDrawingCacheEnabled() 7948 * 7949 * @attr ref android.R.styleable#View_drawingCacheQuality 7950 */ 7951 public void setDrawingCacheQuality(@DrawingCacheQuality int quality) { 7952 setFlags(quality, DRAWING_CACHE_QUALITY_MASK); 7953 } 7954 7955 /** 7956 * Returns whether the screen should remain on, corresponding to the current 7957 * value of {@link #KEEP_SCREEN_ON}. 7958 * 7959 * @return Returns true if {@link #KEEP_SCREEN_ON} is set. 7960 * 7961 * @see #setKeepScreenOn(boolean) 7962 * 7963 * @attr ref android.R.styleable#View_keepScreenOn 7964 */ 7965 public boolean getKeepScreenOn() { 7966 return (mViewFlags & KEEP_SCREEN_ON) != 0; 7967 } 7968 7969 /** 7970 * Controls whether the screen should remain on, modifying the 7971 * value of {@link #KEEP_SCREEN_ON}. 7972 * 7973 * @param keepScreenOn Supply true to set {@link #KEEP_SCREEN_ON}. 7974 * 7975 * @see #getKeepScreenOn() 7976 * 7977 * @attr ref android.R.styleable#View_keepScreenOn 7978 */ 7979 public void setKeepScreenOn(boolean keepScreenOn) { 7980 setFlags(keepScreenOn ? KEEP_SCREEN_ON : 0, KEEP_SCREEN_ON); 7981 } 7982 7983 /** 7984 * Gets the id of the view to use when the next focus is {@link #FOCUS_LEFT}. 7985 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically. 7986 * 7987 * @attr ref android.R.styleable#View_nextFocusLeft 7988 */ 7989 public int getNextFocusLeftId() { 7990 return mNextFocusLeftId; 7991 } 7992 7993 /** 7994 * Sets the id of the view to use when the next focus is {@link #FOCUS_LEFT}. 7995 * @param nextFocusLeftId The next focus ID, or {@link #NO_ID} if the framework should 7996 * decide automatically. 7997 * 7998 * @attr ref android.R.styleable#View_nextFocusLeft 7999 */ 8000 public void setNextFocusLeftId(int nextFocusLeftId) { 8001 mNextFocusLeftId = nextFocusLeftId; 8002 } 8003 8004 /** 8005 * Gets the id of the view to use when the next focus is {@link #FOCUS_RIGHT}. 8006 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically. 8007 * 8008 * @attr ref android.R.styleable#View_nextFocusRight 8009 */ 8010 public int getNextFocusRightId() { 8011 return mNextFocusRightId; 8012 } 8013 8014 /** 8015 * Sets the id of the view to use when the next focus is {@link #FOCUS_RIGHT}. 8016 * @param nextFocusRightId The next focus ID, or {@link #NO_ID} if the framework should 8017 * decide automatically. 8018 * 8019 * @attr ref android.R.styleable#View_nextFocusRight 8020 */ 8021 public void setNextFocusRightId(int nextFocusRightId) { 8022 mNextFocusRightId = nextFocusRightId; 8023 } 8024 8025 /** 8026 * Gets the id of the view to use when the next focus is {@link #FOCUS_UP}. 8027 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically. 8028 * 8029 * @attr ref android.R.styleable#View_nextFocusUp 8030 */ 8031 public int getNextFocusUpId() { 8032 return mNextFocusUpId; 8033 } 8034 8035 /** 8036 * Sets the id of the view to use when the next focus is {@link #FOCUS_UP}. 8037 * @param nextFocusUpId The next focus ID, or {@link #NO_ID} if the framework should 8038 * decide automatically. 8039 * 8040 * @attr ref android.R.styleable#View_nextFocusUp 8041 */ 8042 public void setNextFocusUpId(int nextFocusUpId) { 8043 mNextFocusUpId = nextFocusUpId; 8044 } 8045 8046 /** 8047 * Gets the id of the view to use when the next focus is {@link #FOCUS_DOWN}. 8048 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically. 8049 * 8050 * @attr ref android.R.styleable#View_nextFocusDown 8051 */ 8052 public int getNextFocusDownId() { 8053 return mNextFocusDownId; 8054 } 8055 8056 /** 8057 * Sets the id of the view to use when the next focus is {@link #FOCUS_DOWN}. 8058 * @param nextFocusDownId The next focus ID, or {@link #NO_ID} if the framework should 8059 * decide automatically. 8060 * 8061 * @attr ref android.R.styleable#View_nextFocusDown 8062 */ 8063 public void setNextFocusDownId(int nextFocusDownId) { 8064 mNextFocusDownId = nextFocusDownId; 8065 } 8066 8067 /** 8068 * Gets the id of the view to use when the next focus is {@link #FOCUS_FORWARD}. 8069 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically. 8070 * 8071 * @attr ref android.R.styleable#View_nextFocusForward 8072 */ 8073 public int getNextFocusForwardId() { 8074 return mNextFocusForwardId; 8075 } 8076 8077 /** 8078 * Sets the id of the view to use when the next focus is {@link #FOCUS_FORWARD}. 8079 * @param nextFocusForwardId The next focus ID, or {@link #NO_ID} if the framework should 8080 * decide automatically. 8081 * 8082 * @attr ref android.R.styleable#View_nextFocusForward 8083 */ 8084 public void setNextFocusForwardId(int nextFocusForwardId) { 8085 mNextFocusForwardId = nextFocusForwardId; 8086 } 8087 8088 /** 8089 * Gets the id of the root of the next keyboard navigation cluster. 8090 * @return The next keyboard navigation cluster ID, or {@link #NO_ID} if the framework should 8091 * decide automatically. 8092 * 8093 * @attr ref android.R.styleable#View_nextClusterForward 8094 */ 8095 public int getNextClusterForwardId() { 8096 return mNextClusterForwardId; 8097 } 8098 8099 /** 8100 * Sets the id of the view to use as the root of the next keyboard navigation cluster. 8101 * @param nextClusterForwardId The next cluster ID, or {@link #NO_ID} if the framework should 8102 * decide automatically. 8103 * 8104 * @attr ref android.R.styleable#View_nextClusterForward 8105 */ 8106 public void setNextClusterForwardId(int nextClusterForwardId) { 8107 mNextClusterForwardId = nextClusterForwardId; 8108 } 8109 8110 /** 8111 * Returns the visibility of this view and all of its ancestors 8112 * 8113 * @return True if this view and all of its ancestors are {@link #VISIBLE} 8114 */ 8115 public boolean isShown() { 8116 View current = this; 8117 //noinspection ConstantConditions 8118 do { 8119 if ((current.mViewFlags & VISIBILITY_MASK) != VISIBLE) { 8120 return false; 8121 } 8122 ViewParent parent = current.mParent; 8123 if (parent == null) { 8124 return false; // We are not attached to the view root 8125 } 8126 if (!(parent instanceof View)) { 8127 return true; 8128 } 8129 current = (View) parent; 8130 } while (current != null); 8131 8132 return false; 8133 } 8134 8135 /** 8136 * Called by the view hierarchy when the content insets for a window have 8137 * changed, to allow it to adjust its content to fit within those windows. 8138 * The content insets tell you the space that the status bar, input method, 8139 * and other system windows infringe on the application's window. 8140 * 8141 * <p>You do not normally need to deal with this function, since the default 8142 * window decoration given to applications takes care of applying it to the 8143 * content of the window. If you use {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN} 8144 * or {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION} this will not be the case, 8145 * and your content can be placed under those system elements. You can then 8146 * use this method within your view hierarchy if you have parts of your UI 8147 * which you would like to ensure are not being covered. 8148 * 8149 * <p>The default implementation of this method simply applies the content 8150 * insets to the view's padding, consuming that content (modifying the 8151 * insets to be 0), and returning true. This behavior is off by default, but can 8152 * be enabled through {@link #setFitsSystemWindows(boolean)}. 8153 * 8154 * <p>This function's traversal down the hierarchy is depth-first. The same content 8155 * insets object is propagated down the hierarchy, so any changes made to it will 8156 * be seen by all following views (including potentially ones above in 8157 * the hierarchy since this is a depth-first traversal). The first view 8158 * that returns true will abort the entire traversal. 8159 * 8160 * <p>The default implementation works well for a situation where it is 8161 * used with a container that covers the entire window, allowing it to 8162 * apply the appropriate insets to its content on all edges. If you need 8163 * a more complicated layout (such as two different views fitting system 8164 * windows, one on the top of the window, and one on the bottom), 8165 * you can override the method and handle the insets however you would like. 8166 * Note that the insets provided by the framework are always relative to the 8167 * far edges of the window, not accounting for the location of the called view 8168 * within that window. (In fact when this method is called you do not yet know 8169 * where the layout will place the view, as it is done before layout happens.) 8170 * 8171 * <p>Note: unlike many View methods, there is no dispatch phase to this 8172 * call. If you are overriding it in a ViewGroup and want to allow the 8173 * call to continue to your children, you must be sure to call the super 8174 * implementation. 8175 * 8176 * <p>Here is a sample layout that makes use of fitting system windows 8177 * to have controls for a video view placed inside of the window decorations 8178 * that it hides and shows. This can be used with code like the second 8179 * sample (video player) shown in {@link #setSystemUiVisibility(int)}. 8180 * 8181 * {@sample development/samples/ApiDemos/res/layout/video_player.xml complete} 8182 * 8183 * @param insets Current content insets of the window. Prior to 8184 * {@link android.os.Build.VERSION_CODES#JELLY_BEAN} you must not modify 8185 * the insets or else you and Android will be unhappy. 8186 * 8187 * @return {@code true} if this view applied the insets and it should not 8188 * continue propagating further down the hierarchy, {@code false} otherwise. 8189 * @see #getFitsSystemWindows() 8190 * @see #setFitsSystemWindows(boolean) 8191 * @see #setSystemUiVisibility(int) 8192 * 8193 * @deprecated As of API 20 use {@link #dispatchApplyWindowInsets(WindowInsets)} to apply 8194 * insets to views. Views should override {@link #onApplyWindowInsets(WindowInsets)} or use 8195 * {@link #setOnApplyWindowInsetsListener(android.view.View.OnApplyWindowInsetsListener)} 8196 * to implement handling their own insets. 8197 */ 8198 @Deprecated 8199 protected boolean fitSystemWindows(Rect insets) { 8200 if ((mPrivateFlags3 & PFLAG3_APPLYING_INSETS) == 0) { 8201 if (insets == null) { 8202 // Null insets by definition have already been consumed. 8203 // This call cannot apply insets since there are none to apply, 8204 // so return false. 8205 return false; 8206 } 8207 // If we're not in the process of dispatching the newer apply insets call, 8208 // that means we're not in the compatibility path. Dispatch into the newer 8209 // apply insets path and take things from there. 8210 try { 8211 mPrivateFlags3 |= PFLAG3_FITTING_SYSTEM_WINDOWS; 8212 return dispatchApplyWindowInsets(new WindowInsets(insets)).isConsumed(); 8213 } finally { 8214 mPrivateFlags3 &= ~PFLAG3_FITTING_SYSTEM_WINDOWS; 8215 } 8216 } else { 8217 // We're being called from the newer apply insets path. 8218 // Perform the standard fallback behavior. 8219 return fitSystemWindowsInt(insets); 8220 } 8221 } 8222 8223 private boolean fitSystemWindowsInt(Rect insets) { 8224 if ((mViewFlags & FITS_SYSTEM_WINDOWS) == FITS_SYSTEM_WINDOWS) { 8225 mUserPaddingStart = UNDEFINED_PADDING; 8226 mUserPaddingEnd = UNDEFINED_PADDING; 8227 Rect localInsets = sThreadLocal.get(); 8228 if (localInsets == null) { 8229 localInsets = new Rect(); 8230 sThreadLocal.set(localInsets); 8231 } 8232 boolean res = computeFitSystemWindows(insets, localInsets); 8233 mUserPaddingLeftInitial = localInsets.left; 8234 mUserPaddingRightInitial = localInsets.right; 8235 internalSetPadding(localInsets.left, localInsets.top, 8236 localInsets.right, localInsets.bottom); 8237 return res; 8238 } 8239 return false; 8240 } 8241 8242 /** 8243 * Called when the view should apply {@link WindowInsets} according to its internal policy. 8244 * 8245 * <p>This method should be overridden by views that wish to apply a policy different from or 8246 * in addition to the default behavior. Clients that wish to force a view subtree 8247 * to apply insets should call {@link #dispatchApplyWindowInsets(WindowInsets)}.</p> 8248 * 8249 * <p>Clients may supply an {@link OnApplyWindowInsetsListener} to a view. If one is set 8250 * it will be called during dispatch instead of this method. The listener may optionally 8251 * call this method from its own implementation if it wishes to apply the view's default 8252 * insets policy in addition to its own.</p> 8253 * 8254 * <p>Implementations of this method should either return the insets parameter unchanged 8255 * or a new {@link WindowInsets} cloned from the supplied insets with any insets consumed 8256 * that this view applied itself. This allows new inset types added in future platform 8257 * versions to pass through existing implementations unchanged without being erroneously 8258 * consumed.</p> 8259 * 8260 * <p>By default if a view's {@link #setFitsSystemWindows(boolean) fitsSystemWindows} 8261 * property is set then the view will consume the system window insets and apply them 8262 * as padding for the view.</p> 8263 * 8264 * @param insets Insets to apply 8265 * @return The supplied insets with any applied insets consumed 8266 */ 8267 public WindowInsets onApplyWindowInsets(WindowInsets insets) { 8268 if ((mPrivateFlags3 & PFLAG3_FITTING_SYSTEM_WINDOWS) == 0) { 8269 // We weren't called from within a direct call to fitSystemWindows, 8270 // call into it as a fallback in case we're in a class that overrides it 8271 // and has logic to perform. 8272 if (fitSystemWindows(insets.getSystemWindowInsets())) { 8273 return insets.consumeSystemWindowInsets(); 8274 } 8275 } else { 8276 // We were called from within a direct call to fitSystemWindows. 8277 if (fitSystemWindowsInt(insets.getSystemWindowInsets())) { 8278 return insets.consumeSystemWindowInsets(); 8279 } 8280 } 8281 return insets; 8282 } 8283 8284 /** 8285 * Set an {@link OnApplyWindowInsetsListener} to take over the policy for applying 8286 * window insets to this view. The listener's 8287 * {@link OnApplyWindowInsetsListener#onApplyWindowInsets(View, WindowInsets) onApplyWindowInsets} 8288 * method will be called instead of the view's 8289 * {@link #onApplyWindowInsets(WindowInsets) onApplyWindowInsets} method. 8290 * 8291 * @param listener Listener to set 8292 * 8293 * @see #onApplyWindowInsets(WindowInsets) 8294 */ 8295 public void setOnApplyWindowInsetsListener(OnApplyWindowInsetsListener listener) { 8296 getListenerInfo().mOnApplyWindowInsetsListener = listener; 8297 } 8298 8299 /** 8300 * Request to apply the given window insets to this view or another view in its subtree. 8301 * 8302 * <p>This method should be called by clients wishing to apply insets corresponding to areas 8303 * obscured by window decorations or overlays. This can include the status and navigation bars, 8304 * action bars, input methods and more. New inset categories may be added in the future. 8305 * The method returns the insets provided minus any that were applied by this view or its 8306 * children.</p> 8307 * 8308 * <p>Clients wishing to provide custom behavior should override the 8309 * {@link #onApplyWindowInsets(WindowInsets)} method or alternatively provide a 8310 * {@link OnApplyWindowInsetsListener} via the 8311 * {@link #setOnApplyWindowInsetsListener(View.OnApplyWindowInsetsListener) setOnApplyWindowInsetsListener} 8312 * method.</p> 8313 * 8314 * <p>This method replaces the older {@link #fitSystemWindows(Rect) fitSystemWindows} method. 8315 * </p> 8316 * 8317 * @param insets Insets to apply 8318 * @return The provided insets minus the insets that were consumed 8319 */ 8320 public WindowInsets dispatchApplyWindowInsets(WindowInsets insets) { 8321 try { 8322 mPrivateFlags3 |= PFLAG3_APPLYING_INSETS; 8323 if (mListenerInfo != null && mListenerInfo.mOnApplyWindowInsetsListener != null) { 8324 return mListenerInfo.mOnApplyWindowInsetsListener.onApplyWindowInsets(this, insets); 8325 } else { 8326 return onApplyWindowInsets(insets); 8327 } 8328 } finally { 8329 mPrivateFlags3 &= ~PFLAG3_APPLYING_INSETS; 8330 } 8331 } 8332 8333 /** 8334 * Compute the view's coordinate within the surface. 8335 * 8336 * <p>Computes the coordinates of this view in its surface. The argument 8337 * must be an array of two integers. After the method returns, the array 8338 * contains the x and y location in that order.</p> 8339 * @hide 8340 * @param location an array of two integers in which to hold the coordinates 8341 */ 8342 public void getLocationInSurface(@Size(2) int[] location) { 8343 getLocationInWindow(location); 8344 if (mAttachInfo != null && mAttachInfo.mViewRootImpl != null) { 8345 location[0] += mAttachInfo.mViewRootImpl.mWindowAttributes.surfaceInsets.left; 8346 location[1] += mAttachInfo.mViewRootImpl.mWindowAttributes.surfaceInsets.top; 8347 } 8348 } 8349 8350 /** 8351 * Provide original WindowInsets that are dispatched to the view hierarchy. The insets are 8352 * only available if the view is attached. 8353 * 8354 * @return WindowInsets from the top of the view hierarchy or null if View is detached 8355 */ 8356 public WindowInsets getRootWindowInsets() { 8357 if (mAttachInfo != null) { 8358 return mAttachInfo.mViewRootImpl.getWindowInsets(false /* forceConstruct */); 8359 } 8360 return null; 8361 } 8362 8363 /** 8364 * @hide Compute the insets that should be consumed by this view and the ones 8365 * that should propagate to those under it. 8366 */ 8367 protected boolean computeFitSystemWindows(Rect inoutInsets, Rect outLocalInsets) { 8368 if ((mViewFlags & OPTIONAL_FITS_SYSTEM_WINDOWS) == 0 8369 || mAttachInfo == null 8370 || ((mAttachInfo.mSystemUiVisibility & SYSTEM_UI_LAYOUT_FLAGS) == 0 8371 && !mAttachInfo.mOverscanRequested)) { 8372 outLocalInsets.set(inoutInsets); 8373 inoutInsets.set(0, 0, 0, 0); 8374 return true; 8375 } else { 8376 // The application wants to take care of fitting system window for 8377 // the content... however we still need to take care of any overscan here. 8378 final Rect overscan = mAttachInfo.mOverscanInsets; 8379 outLocalInsets.set(overscan); 8380 inoutInsets.left -= overscan.left; 8381 inoutInsets.top -= overscan.top; 8382 inoutInsets.right -= overscan.right; 8383 inoutInsets.bottom -= overscan.bottom; 8384 return false; 8385 } 8386 } 8387 8388 /** 8389 * Compute insets that should be consumed by this view and the ones that should propagate 8390 * to those under it. 8391 * 8392 * @param in Insets currently being processed by this View, likely received as a parameter 8393 * to {@link #onApplyWindowInsets(WindowInsets)}. 8394 * @param outLocalInsets A Rect that will receive the insets that should be consumed 8395 * by this view 8396 * @return Insets that should be passed along to views under this one 8397 */ 8398 public WindowInsets computeSystemWindowInsets(WindowInsets in, Rect outLocalInsets) { 8399 if ((mViewFlags & OPTIONAL_FITS_SYSTEM_WINDOWS) == 0 8400 || mAttachInfo == null 8401 || (mAttachInfo.mSystemUiVisibility & SYSTEM_UI_LAYOUT_FLAGS) == 0) { 8402 outLocalInsets.set(in.getSystemWindowInsets()); 8403 return in.consumeSystemWindowInsets(); 8404 } else { 8405 outLocalInsets.set(0, 0, 0, 0); 8406 return in; 8407 } 8408 } 8409 8410 /** 8411 * Sets whether or not this view should account for system screen decorations 8412 * such as the status bar and inset its content; that is, controlling whether 8413 * the default implementation of {@link #fitSystemWindows(Rect)} will be 8414 * executed. See that method for more details. 8415 * 8416 * <p>Note that if you are providing your own implementation of 8417 * {@link #fitSystemWindows(Rect)}, then there is no need to set this 8418 * flag to true -- your implementation will be overriding the default 8419 * implementation that checks this flag. 8420 * 8421 * @param fitSystemWindows If true, then the default implementation of 8422 * {@link #fitSystemWindows(Rect)} will be executed. 8423 * 8424 * @attr ref android.R.styleable#View_fitsSystemWindows 8425 * @see #getFitsSystemWindows() 8426 * @see #fitSystemWindows(Rect) 8427 * @see #setSystemUiVisibility(int) 8428 */ 8429 public void setFitsSystemWindows(boolean fitSystemWindows) { 8430 setFlags(fitSystemWindows ? FITS_SYSTEM_WINDOWS : 0, FITS_SYSTEM_WINDOWS); 8431 } 8432 8433 /** 8434 * Check for state of {@link #setFitsSystemWindows(boolean)}. If this method 8435 * returns {@code true}, the default implementation of {@link #fitSystemWindows(Rect)} 8436 * will be executed. 8437 * 8438 * @return {@code true} if the default implementation of 8439 * {@link #fitSystemWindows(Rect)} will be executed. 8440 * 8441 * @attr ref android.R.styleable#View_fitsSystemWindows 8442 * @see #setFitsSystemWindows(boolean) 8443 * @see #fitSystemWindows(Rect) 8444 * @see #setSystemUiVisibility(int) 8445 */ 8446 @ViewDebug.ExportedProperty 8447 public boolean getFitsSystemWindows() { 8448 return (mViewFlags & FITS_SYSTEM_WINDOWS) == FITS_SYSTEM_WINDOWS; 8449 } 8450 8451 /** @hide */ 8452 public boolean fitsSystemWindows() { 8453 return getFitsSystemWindows(); 8454 } 8455 8456 /** 8457 * Ask that a new dispatch of {@link #fitSystemWindows(Rect)} be performed. 8458 * @deprecated Use {@link #requestApplyInsets()} for newer platform versions. 8459 */ 8460 @Deprecated 8461 public void requestFitSystemWindows() { 8462 if (mParent != null) { 8463 mParent.requestFitSystemWindows(); 8464 } 8465 } 8466 8467 /** 8468 * Ask that a new dispatch of {@link #onApplyWindowInsets(WindowInsets)} be performed. 8469 */ 8470 public void requestApplyInsets() { 8471 requestFitSystemWindows(); 8472 } 8473 8474 /** 8475 * For use by PhoneWindow to make its own system window fitting optional. 8476 * @hide 8477 */ 8478 public void makeOptionalFitsSystemWindows() { 8479 setFlags(OPTIONAL_FITS_SYSTEM_WINDOWS, OPTIONAL_FITS_SYSTEM_WINDOWS); 8480 } 8481 8482 /** 8483 * Returns the outsets, which areas of the device that aren't a surface, but we would like to 8484 * treat them as such. 8485 * @hide 8486 */ 8487 public void getOutsets(Rect outOutsetRect) { 8488 if (mAttachInfo != null) { 8489 outOutsetRect.set(mAttachInfo.mOutsets); 8490 } else { 8491 outOutsetRect.setEmpty(); 8492 } 8493 } 8494 8495 /** 8496 * Returns the visibility status for this view. 8497 * 8498 * @return One of {@link #VISIBLE}, {@link #INVISIBLE}, or {@link #GONE}. 8499 * @attr ref android.R.styleable#View_visibility 8500 */ 8501 @ViewDebug.ExportedProperty(mapping = { 8502 @ViewDebug.IntToString(from = VISIBLE, to = "VISIBLE"), 8503 @ViewDebug.IntToString(from = INVISIBLE, to = "INVISIBLE"), 8504 @ViewDebug.IntToString(from = GONE, to = "GONE") 8505 }) 8506 @Visibility 8507 public int getVisibility() { 8508 return mViewFlags & VISIBILITY_MASK; 8509 } 8510 8511 /** 8512 * Set the visibility state of this view. 8513 * 8514 * @param visibility One of {@link #VISIBLE}, {@link #INVISIBLE}, or {@link #GONE}. 8515 * @attr ref android.R.styleable#View_visibility 8516 */ 8517 @RemotableViewMethod 8518 public void setVisibility(@Visibility int visibility) { 8519 setFlags(visibility, VISIBILITY_MASK); 8520 } 8521 8522 /** 8523 * Returns the enabled status for this view. The interpretation of the 8524 * enabled state varies by subclass. 8525 * 8526 * @return True if this view is enabled, false otherwise. 8527 */ 8528 @ViewDebug.ExportedProperty 8529 public boolean isEnabled() { 8530 return (mViewFlags & ENABLED_MASK) == ENABLED; 8531 } 8532 8533 /** 8534 * Set the enabled state of this view. The interpretation of the enabled 8535 * state varies by subclass. 8536 * 8537 * @param enabled True if this view is enabled, false otherwise. 8538 */ 8539 @RemotableViewMethod 8540 public void setEnabled(boolean enabled) { 8541 if (enabled == isEnabled()) return; 8542 8543 setFlags(enabled ? ENABLED : DISABLED, ENABLED_MASK); 8544 8545 /* 8546 * The View most likely has to change its appearance, so refresh 8547 * the drawable state. 8548 */ 8549 refreshDrawableState(); 8550 8551 // Invalidate too, since the default behavior for views is to be 8552 // be drawn at 50% alpha rather than to change the drawable. 8553 invalidate(true); 8554 8555 if (!enabled) { 8556 cancelPendingInputEvents(); 8557 } 8558 } 8559 8560 /** 8561 * Set whether this view can receive the focus. 8562 * <p> 8563 * Setting this to false will also ensure that this view is not focusable 8564 * in touch mode. 8565 * 8566 * @param focusable If true, this view can receive the focus. 8567 * 8568 * @see #setFocusableInTouchMode(boolean) 8569 * @see #setFocusable(int) 8570 * @attr ref android.R.styleable#View_focusable 8571 */ 8572 public void setFocusable(boolean focusable) { 8573 setFocusable(focusable ? FOCUSABLE : NOT_FOCUSABLE); 8574 } 8575 8576 /** 8577 * Sets whether this view can receive focus. 8578 * <p> 8579 * Setting this to {@link #FOCUSABLE_AUTO} tells the framework to determine focusability 8580 * automatically based on the view's interactivity. This is the default. 8581 * <p> 8582 * Setting this to NOT_FOCUSABLE will ensure that this view is also not focusable 8583 * in touch mode. 8584 * 8585 * @param focusable One of {@link #NOT_FOCUSABLE}, {@link #FOCUSABLE}, 8586 * or {@link #FOCUSABLE_AUTO}. 8587 * @see #setFocusableInTouchMode(boolean) 8588 * @attr ref android.R.styleable#View_focusable 8589 */ 8590 public void setFocusable(@Focusable int focusable) { 8591 if ((focusable & (FOCUSABLE_AUTO | FOCUSABLE)) == 0) { 8592 setFlags(0, FOCUSABLE_IN_TOUCH_MODE); 8593 } 8594 setFlags(focusable, FOCUSABLE_MASK); 8595 } 8596 8597 /** 8598 * Set whether this view can receive focus while in touch mode. 8599 * 8600 * Setting this to true will also ensure that this view is focusable. 8601 * 8602 * @param focusableInTouchMode If true, this view can receive the focus while 8603 * in touch mode. 8604 * 8605 * @see #setFocusable(boolean) 8606 * @attr ref android.R.styleable#View_focusableInTouchMode 8607 */ 8608 public void setFocusableInTouchMode(boolean focusableInTouchMode) { 8609 // Focusable in touch mode should always be set before the focusable flag 8610 // otherwise, setting the focusable flag will trigger a focusableViewAvailable() 8611 // which, in touch mode, will not successfully request focus on this view 8612 // because the focusable in touch mode flag is not set 8613 setFlags(focusableInTouchMode ? FOCUSABLE_IN_TOUCH_MODE : 0, FOCUSABLE_IN_TOUCH_MODE); 8614 if (focusableInTouchMode) { 8615 setFlags(FOCUSABLE, FOCUSABLE_MASK); 8616 } 8617 } 8618 8619 /** 8620 * Set whether this view should have sound effects enabled for events such as 8621 * clicking and touching. 8622 * 8623 * <p>You may wish to disable sound effects for a view if you already play sounds, 8624 * for instance, a dial key that plays dtmf tones. 8625 * 8626 * @param soundEffectsEnabled whether sound effects are enabled for this view. 8627 * @see #isSoundEffectsEnabled() 8628 * @see #playSoundEffect(int) 8629 * @attr ref android.R.styleable#View_soundEffectsEnabled 8630 */ 8631 public void setSoundEffectsEnabled(boolean soundEffectsEnabled) { 8632 setFlags(soundEffectsEnabled ? SOUND_EFFECTS_ENABLED: 0, SOUND_EFFECTS_ENABLED); 8633 } 8634 8635 /** 8636 * @return whether this view should have sound effects enabled for events such as 8637 * clicking and touching. 8638 * 8639 * @see #setSoundEffectsEnabled(boolean) 8640 * @see #playSoundEffect(int) 8641 * @attr ref android.R.styleable#View_soundEffectsEnabled 8642 */ 8643 @ViewDebug.ExportedProperty 8644 public boolean isSoundEffectsEnabled() { 8645 return SOUND_EFFECTS_ENABLED == (mViewFlags & SOUND_EFFECTS_ENABLED); 8646 } 8647 8648 /** 8649 * Set whether this view should have haptic feedback for events such as 8650 * long presses. 8651 * 8652 * <p>You may wish to disable haptic feedback if your view already controls 8653 * its own haptic feedback. 8654 * 8655 * @param hapticFeedbackEnabled whether haptic feedback enabled for this view. 8656 * @see #isHapticFeedbackEnabled() 8657 * @see #performHapticFeedback(int) 8658 * @attr ref android.R.styleable#View_hapticFeedbackEnabled 8659 */ 8660 public void setHapticFeedbackEnabled(boolean hapticFeedbackEnabled) { 8661 setFlags(hapticFeedbackEnabled ? HAPTIC_FEEDBACK_ENABLED: 0, HAPTIC_FEEDBACK_ENABLED); 8662 } 8663 8664 /** 8665 * @return whether this view should have haptic feedback enabled for events 8666 * long presses. 8667 * 8668 * @see #setHapticFeedbackEnabled(boolean) 8669 * @see #performHapticFeedback(int) 8670 * @attr ref android.R.styleable#View_hapticFeedbackEnabled 8671 */ 8672 @ViewDebug.ExportedProperty 8673 public boolean isHapticFeedbackEnabled() { 8674 return HAPTIC_FEEDBACK_ENABLED == (mViewFlags & HAPTIC_FEEDBACK_ENABLED); 8675 } 8676 8677 /** 8678 * Returns the layout direction for this view. 8679 * 8680 * @return One of {@link #LAYOUT_DIRECTION_LTR}, 8681 * {@link #LAYOUT_DIRECTION_RTL}, 8682 * {@link #LAYOUT_DIRECTION_INHERIT} or 8683 * {@link #LAYOUT_DIRECTION_LOCALE}. 8684 * 8685 * @attr ref android.R.styleable#View_layoutDirection 8686 * 8687 * @hide 8688 */ 8689 @ViewDebug.ExportedProperty(category = "layout", mapping = { 8690 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_LTR, to = "LTR"), 8691 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_RTL, to = "RTL"), 8692 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_INHERIT, to = "INHERIT"), 8693 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_LOCALE, to = "LOCALE") 8694 }) 8695 @LayoutDir 8696 public int getRawLayoutDirection() { 8697 return (mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_MASK) >> PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 8698 } 8699 8700 /** 8701 * Set the layout direction for this view. This will propagate a reset of layout direction 8702 * resolution to the view's children and resolve layout direction for this view. 8703 * 8704 * @param layoutDirection the layout direction to set. Should be one of: 8705 * 8706 * {@link #LAYOUT_DIRECTION_LTR}, 8707 * {@link #LAYOUT_DIRECTION_RTL}, 8708 * {@link #LAYOUT_DIRECTION_INHERIT}, 8709 * {@link #LAYOUT_DIRECTION_LOCALE}. 8710 * 8711 * Resolution will be done if the value is set to LAYOUT_DIRECTION_INHERIT. The resolution 8712 * proceeds up the parent chain of the view to get the value. If there is no parent, then it 8713 * will return the default {@link #LAYOUT_DIRECTION_LTR}. 8714 * 8715 * @attr ref android.R.styleable#View_layoutDirection 8716 */ 8717 @RemotableViewMethod 8718 public void setLayoutDirection(@LayoutDir int layoutDirection) { 8719 if (getRawLayoutDirection() != layoutDirection) { 8720 // Reset the current layout direction and the resolved one 8721 mPrivateFlags2 &= ~PFLAG2_LAYOUT_DIRECTION_MASK; 8722 resetRtlProperties(); 8723 // Set the new layout direction (filtered) 8724 mPrivateFlags2 |= 8725 ((layoutDirection << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT) & PFLAG2_LAYOUT_DIRECTION_MASK); 8726 // We need to resolve all RTL properties as they all depend on layout direction 8727 resolveRtlPropertiesIfNeeded(); 8728 requestLayout(); 8729 invalidate(true); 8730 } 8731 } 8732 8733 /** 8734 * Returns the resolved layout direction for this view. 8735 * 8736 * @return {@link #LAYOUT_DIRECTION_RTL} if the layout direction is RTL or returns 8737 * {@link #LAYOUT_DIRECTION_LTR} if the layout direction is not RTL. 8738 * 8739 * For compatibility, this will return {@link #LAYOUT_DIRECTION_LTR} if API version 8740 * is lower than {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR1}. 8741 * 8742 * @attr ref android.R.styleable#View_layoutDirection 8743 */ 8744 @ViewDebug.ExportedProperty(category = "layout", mapping = { 8745 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_LTR, to = "RESOLVED_DIRECTION_LTR"), 8746 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_RTL, to = "RESOLVED_DIRECTION_RTL") 8747 }) 8748 @ResolvedLayoutDir 8749 public int getLayoutDirection() { 8750 final int targetSdkVersion = getContext().getApplicationInfo().targetSdkVersion; 8751 if (targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR1) { 8752 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED; 8753 return LAYOUT_DIRECTION_RESOLVED_DEFAULT; 8754 } 8755 return ((mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL) == 8756 PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL) ? LAYOUT_DIRECTION_RTL : LAYOUT_DIRECTION_LTR; 8757 } 8758 8759 /** 8760 * Indicates whether or not this view's layout is right-to-left. This is resolved from 8761 * layout attribute and/or the inherited value from the parent 8762 * 8763 * @return true if the layout is right-to-left. 8764 * 8765 * @hide 8766 */ 8767 @ViewDebug.ExportedProperty(category = "layout") 8768 public boolean isLayoutRtl() { 8769 return (getLayoutDirection() == LAYOUT_DIRECTION_RTL); 8770 } 8771 8772 /** 8773 * Indicates whether the view is currently tracking transient state that the 8774 * app should not need to concern itself with saving and restoring, but that 8775 * the framework should take special note to preserve when possible. 8776 * 8777 * <p>A view with transient state cannot be trivially rebound from an external 8778 * data source, such as an adapter binding item views in a list. This may be 8779 * because the view is performing an animation, tracking user selection 8780 * of content, or similar.</p> 8781 * 8782 * @return true if the view has transient state 8783 */ 8784 @ViewDebug.ExportedProperty(category = "layout") 8785 public boolean hasTransientState() { 8786 return (mPrivateFlags2 & PFLAG2_HAS_TRANSIENT_STATE) == PFLAG2_HAS_TRANSIENT_STATE; 8787 } 8788 8789 /** 8790 * Set whether this view is currently tracking transient state that the 8791 * framework should attempt to preserve when possible. This flag is reference counted, 8792 * so every call to setHasTransientState(true) should be paired with a later call 8793 * to setHasTransientState(false). 8794 * 8795 * <p>A view with transient state cannot be trivially rebound from an external 8796 * data source, such as an adapter binding item views in a list. This may be 8797 * because the view is performing an animation, tracking user selection 8798 * of content, or similar.</p> 8799 * 8800 * @param hasTransientState true if this view has transient state 8801 */ 8802 public void setHasTransientState(boolean hasTransientState) { 8803 mTransientStateCount = hasTransientState ? mTransientStateCount + 1 : 8804 mTransientStateCount - 1; 8805 if (mTransientStateCount < 0) { 8806 mTransientStateCount = 0; 8807 Log.e(VIEW_LOG_TAG, "hasTransientState decremented below 0: " + 8808 "unmatched pair of setHasTransientState calls"); 8809 } else if ((hasTransientState && mTransientStateCount == 1) || 8810 (!hasTransientState && mTransientStateCount == 0)) { 8811 // update flag if we've just incremented up from 0 or decremented down to 0 8812 mPrivateFlags2 = (mPrivateFlags2 & ~PFLAG2_HAS_TRANSIENT_STATE) | 8813 (hasTransientState ? PFLAG2_HAS_TRANSIENT_STATE : 0); 8814 if (mParent != null) { 8815 try { 8816 mParent.childHasTransientStateChanged(this, hasTransientState); 8817 } catch (AbstractMethodError e) { 8818 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 8819 " does not fully implement ViewParent", e); 8820 } 8821 } 8822 } 8823 } 8824 8825 /** 8826 * Returns true if this view is currently attached to a window. 8827 */ 8828 public boolean isAttachedToWindow() { 8829 return mAttachInfo != null; 8830 } 8831 8832 /** 8833 * Returns true if this view has been through at least one layout since it 8834 * was last attached to or detached from a window. 8835 */ 8836 public boolean isLaidOut() { 8837 return (mPrivateFlags3 & PFLAG3_IS_LAID_OUT) == PFLAG3_IS_LAID_OUT; 8838 } 8839 8840 /** 8841 * If this view doesn't do any drawing on its own, set this flag to 8842 * allow further optimizations. By default, this flag is not set on 8843 * View, but could be set on some View subclasses such as ViewGroup. 8844 * 8845 * Typically, if you override {@link #onDraw(android.graphics.Canvas)} 8846 * you should clear this flag. 8847 * 8848 * @param willNotDraw whether or not this View draw on its own 8849 */ 8850 public void setWillNotDraw(boolean willNotDraw) { 8851 setFlags(willNotDraw ? WILL_NOT_DRAW : 0, DRAW_MASK); 8852 } 8853 8854 /** 8855 * Returns whether or not this View draws on its own. 8856 * 8857 * @return true if this view has nothing to draw, false otherwise 8858 */ 8859 @ViewDebug.ExportedProperty(category = "drawing") 8860 public boolean willNotDraw() { 8861 return (mViewFlags & DRAW_MASK) == WILL_NOT_DRAW; 8862 } 8863 8864 /** 8865 * When a View's drawing cache is enabled, drawing is redirected to an 8866 * offscreen bitmap. Some views, like an ImageView, must be able to 8867 * bypass this mechanism if they already draw a single bitmap, to avoid 8868 * unnecessary usage of the memory. 8869 * 8870 * @param willNotCacheDrawing true if this view does not cache its 8871 * drawing, false otherwise 8872 */ 8873 public void setWillNotCacheDrawing(boolean willNotCacheDrawing) { 8874 setFlags(willNotCacheDrawing ? WILL_NOT_CACHE_DRAWING : 0, WILL_NOT_CACHE_DRAWING); 8875 } 8876 8877 /** 8878 * Returns whether or not this View can cache its drawing or not. 8879 * 8880 * @return true if this view does not cache its drawing, false otherwise 8881 */ 8882 @ViewDebug.ExportedProperty(category = "drawing") 8883 public boolean willNotCacheDrawing() { 8884 return (mViewFlags & WILL_NOT_CACHE_DRAWING) == WILL_NOT_CACHE_DRAWING; 8885 } 8886 8887 /** 8888 * Indicates whether this view reacts to click events or not. 8889 * 8890 * @return true if the view is clickable, false otherwise 8891 * 8892 * @see #setClickable(boolean) 8893 * @attr ref android.R.styleable#View_clickable 8894 */ 8895 @ViewDebug.ExportedProperty 8896 public boolean isClickable() { 8897 return (mViewFlags & CLICKABLE) == CLICKABLE; 8898 } 8899 8900 /** 8901 * Enables or disables click events for this view. When a view 8902 * is clickable it will change its state to "pressed" on every click. 8903 * Subclasses should set the view clickable to visually react to 8904 * user's clicks. 8905 * 8906 * @param clickable true to make the view clickable, false otherwise 8907 * 8908 * @see #isClickable() 8909 * @attr ref android.R.styleable#View_clickable 8910 */ 8911 public void setClickable(boolean clickable) { 8912 setFlags(clickable ? CLICKABLE : 0, CLICKABLE); 8913 } 8914 8915 /** 8916 * Indicates whether this view reacts to long click events or not. 8917 * 8918 * @return true if the view is long clickable, false otherwise 8919 * 8920 * @see #setLongClickable(boolean) 8921 * @attr ref android.R.styleable#View_longClickable 8922 */ 8923 public boolean isLongClickable() { 8924 return (mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE; 8925 } 8926 8927 /** 8928 * Enables or disables long click events for this view. When a view is long 8929 * clickable it reacts to the user holding down the button for a longer 8930 * duration than a tap. This event can either launch the listener or a 8931 * context menu. 8932 * 8933 * @param longClickable true to make the view long clickable, false otherwise 8934 * @see #isLongClickable() 8935 * @attr ref android.R.styleable#View_longClickable 8936 */ 8937 public void setLongClickable(boolean longClickable) { 8938 setFlags(longClickable ? LONG_CLICKABLE : 0, LONG_CLICKABLE); 8939 } 8940 8941 /** 8942 * Indicates whether this view reacts to context clicks or not. 8943 * 8944 * @return true if the view is context clickable, false otherwise 8945 * @see #setContextClickable(boolean) 8946 * @attr ref android.R.styleable#View_contextClickable 8947 */ 8948 public boolean isContextClickable() { 8949 return (mViewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE; 8950 } 8951 8952 /** 8953 * Enables or disables context clicking for this view. This event can launch the listener. 8954 * 8955 * @param contextClickable true to make the view react to a context click, false otherwise 8956 * @see #isContextClickable() 8957 * @attr ref android.R.styleable#View_contextClickable 8958 */ 8959 public void setContextClickable(boolean contextClickable) { 8960 setFlags(contextClickable ? CONTEXT_CLICKABLE : 0, CONTEXT_CLICKABLE); 8961 } 8962 8963 /** 8964 * Sets the pressed state for this view and provides a touch coordinate for 8965 * animation hinting. 8966 * 8967 * @param pressed Pass true to set the View's internal state to "pressed", 8968 * or false to reverts the View's internal state from a 8969 * previously set "pressed" state. 8970 * @param x The x coordinate of the touch that caused the press 8971 * @param y The y coordinate of the touch that caused the press 8972 */ 8973 private void setPressed(boolean pressed, float x, float y) { 8974 if (pressed) { 8975 drawableHotspotChanged(x, y); 8976 } 8977 8978 setPressed(pressed); 8979 } 8980 8981 /** 8982 * Sets the pressed state for this view. 8983 * 8984 * @see #isClickable() 8985 * @see #setClickable(boolean) 8986 * 8987 * @param pressed Pass true to set the View's internal state to "pressed", or false to reverts 8988 * the View's internal state from a previously set "pressed" state. 8989 */ 8990 public void setPressed(boolean pressed) { 8991 final boolean needsRefresh = pressed != ((mPrivateFlags & PFLAG_PRESSED) == PFLAG_PRESSED); 8992 8993 if (pressed) { 8994 mPrivateFlags |= PFLAG_PRESSED; 8995 } else { 8996 mPrivateFlags &= ~PFLAG_PRESSED; 8997 } 8998 8999 if (needsRefresh) { 9000 refreshDrawableState(); 9001 } 9002 dispatchSetPressed(pressed); 9003 } 9004 9005 /** 9006 * Dispatch setPressed to all of this View's children. 9007 * 9008 * @see #setPressed(boolean) 9009 * 9010 * @param pressed The new pressed state 9011 */ 9012 protected void dispatchSetPressed(boolean pressed) { 9013 } 9014 9015 /** 9016 * Indicates whether the view is currently in pressed state. Unless 9017 * {@link #setPressed(boolean)} is explicitly called, only clickable views can enter 9018 * the pressed state. 9019 * 9020 * @see #setPressed(boolean) 9021 * @see #isClickable() 9022 * @see #setClickable(boolean) 9023 * 9024 * @return true if the view is currently pressed, false otherwise 9025 */ 9026 @ViewDebug.ExportedProperty 9027 public boolean isPressed() { 9028 return (mPrivateFlags & PFLAG_PRESSED) == PFLAG_PRESSED; 9029 } 9030 9031 /** 9032 * @hide 9033 * Indicates whether this view will participate in data collection through 9034 * {@link ViewStructure}. If true, it will not provide any data 9035 * for itself or its children. If false, the normal data collection will be allowed. 9036 * 9037 * @return Returns false if assist data collection is not blocked, else true. 9038 * 9039 * @see #setAssistBlocked(boolean) 9040 * @attr ref android.R.styleable#View_assistBlocked 9041 */ 9042 public boolean isAssistBlocked() { 9043 return (mPrivateFlags3 & PFLAG3_ASSIST_BLOCKED) != 0; 9044 } 9045 9046 /** 9047 * @hide 9048 * Indicates whether this view will participate in data collection through 9049 * {@link ViewStructure} for auto-fill purposes. 9050 * 9051 * <p>If {@code true}, it will not provide any data for itself or its children. 9052 * <p>If {@code false}, the normal data collection will be allowed. 9053 * 9054 * @return Returns {@code false} if assist data collection for auto-fill is not blocked, 9055 * else {@code true}. 9056 * 9057 * TODO(b/33197203): update / remove javadoc tags below 9058 * @see #setAssistBlocked(boolean) 9059 * @attr ref android.R.styleable#View_assistBlocked 9060 */ 9061 public boolean isAutoFillBlocked() { 9062 return false; // TODO(b/33197203): properly implement it 9063 } 9064 9065 /** 9066 * @hide 9067 * Controls whether assist data collection from this view and its children is enabled 9068 * (that is, whether {@link #onProvideStructure} and 9069 * {@link #onProvideVirtualStructure} will be called). The default value is false, 9070 * allowing normal assist collection. Setting this to false will disable assist collection. 9071 * 9072 * @param enabled Set to true to <em>disable</em> assist data collection, or false 9073 * (the default) to allow it. 9074 * 9075 * @see #isAssistBlocked() 9076 * @see #onProvideStructure 9077 * @see #onProvideVirtualStructure 9078 * @attr ref android.R.styleable#View_assistBlocked 9079 */ 9080 public void setAssistBlocked(boolean enabled) { 9081 if (enabled) { 9082 mPrivateFlags3 |= PFLAG3_ASSIST_BLOCKED; 9083 } else { 9084 mPrivateFlags3 &= ~PFLAG3_ASSIST_BLOCKED; 9085 } 9086 } 9087 9088 /** 9089 * Indicates whether this view will save its state (that is, 9090 * whether its {@link #onSaveInstanceState} method will be called). 9091 * 9092 * @return Returns true if the view state saving is enabled, else false. 9093 * 9094 * @see #setSaveEnabled(boolean) 9095 * @attr ref android.R.styleable#View_saveEnabled 9096 */ 9097 public boolean isSaveEnabled() { 9098 return (mViewFlags & SAVE_DISABLED_MASK) != SAVE_DISABLED; 9099 } 9100 9101 /** 9102 * Controls whether the saving of this view's state is 9103 * enabled (that is, whether its {@link #onSaveInstanceState} method 9104 * will be called). Note that even if freezing is enabled, the 9105 * view still must have an id assigned to it (via {@link #setId(int)}) 9106 * for its state to be saved. This flag can only disable the 9107 * saving of this view; any child views may still have their state saved. 9108 * 9109 * @param enabled Set to false to <em>disable</em> state saving, or true 9110 * (the default) to allow it. 9111 * 9112 * @see #isSaveEnabled() 9113 * @see #setId(int) 9114 * @see #onSaveInstanceState() 9115 * @attr ref android.R.styleable#View_saveEnabled 9116 */ 9117 public void setSaveEnabled(boolean enabled) { 9118 setFlags(enabled ? 0 : SAVE_DISABLED, SAVE_DISABLED_MASK); 9119 } 9120 9121 /** 9122 * Gets whether the framework should discard touches when the view's 9123 * window is obscured by another visible window. 9124 * Refer to the {@link View} security documentation for more details. 9125 * 9126 * @return True if touch filtering is enabled. 9127 * 9128 * @see #setFilterTouchesWhenObscured(boolean) 9129 * @attr ref android.R.styleable#View_filterTouchesWhenObscured 9130 */ 9131 @ViewDebug.ExportedProperty 9132 public boolean getFilterTouchesWhenObscured() { 9133 return (mViewFlags & FILTER_TOUCHES_WHEN_OBSCURED) != 0; 9134 } 9135 9136 /** 9137 * Sets whether the framework should discard touches when the view's 9138 * window is obscured by another visible window. 9139 * Refer to the {@link View} security documentation for more details. 9140 * 9141 * @param enabled True if touch filtering should be enabled. 9142 * 9143 * @see #getFilterTouchesWhenObscured 9144 * @attr ref android.R.styleable#View_filterTouchesWhenObscured 9145 */ 9146 public void setFilterTouchesWhenObscured(boolean enabled) { 9147 setFlags(enabled ? FILTER_TOUCHES_WHEN_OBSCURED : 0, 9148 FILTER_TOUCHES_WHEN_OBSCURED); 9149 } 9150 9151 /** 9152 * Indicates whether the entire hierarchy under this view will save its 9153 * state when a state saving traversal occurs from its parent. The default 9154 * is true; if false, these views will not be saved unless 9155 * {@link #saveHierarchyState(SparseArray)} is called directly on this view. 9156 * 9157 * @return Returns true if the view state saving from parent is enabled, else false. 9158 * 9159 * @see #setSaveFromParentEnabled(boolean) 9160 */ 9161 public boolean isSaveFromParentEnabled() { 9162 return (mViewFlags & PARENT_SAVE_DISABLED_MASK) != PARENT_SAVE_DISABLED; 9163 } 9164 9165 /** 9166 * Controls whether the entire hierarchy under this view will save its 9167 * state when a state saving traversal occurs from its parent. The default 9168 * is true; if false, these views will not be saved unless 9169 * {@link #saveHierarchyState(SparseArray)} is called directly on this view. 9170 * 9171 * @param enabled Set to false to <em>disable</em> state saving, or true 9172 * (the default) to allow it. 9173 * 9174 * @see #isSaveFromParentEnabled() 9175 * @see #setId(int) 9176 * @see #onSaveInstanceState() 9177 */ 9178 public void setSaveFromParentEnabled(boolean enabled) { 9179 setFlags(enabled ? 0 : PARENT_SAVE_DISABLED, PARENT_SAVE_DISABLED_MASK); 9180 } 9181 9182 9183 /** 9184 * Returns whether this View is currently able to take focus. 9185 * 9186 * @return True if this view can take focus, or false otherwise. 9187 */ 9188 @ViewDebug.ExportedProperty(category = "focus") 9189 public final boolean isFocusable() { 9190 return FOCUSABLE == (mViewFlags & FOCUSABLE); 9191 } 9192 9193 /** 9194 * Returns the focusable setting for this view. 9195 * 9196 * @return One of {@link #NOT_FOCUSABLE}, {@link #FOCUSABLE}, or {@link #FOCUSABLE_AUTO}. 9197 * @attr ref android.R.styleable#View_focusable 9198 */ 9199 @ViewDebug.ExportedProperty(mapping = { 9200 @ViewDebug.IntToString(from = NOT_FOCUSABLE, to = "NOT_FOCUSABLE"), 9201 @ViewDebug.IntToString(from = FOCUSABLE, to = "FOCUSABLE"), 9202 @ViewDebug.IntToString(from = FOCUSABLE_AUTO, to = "FOCUSABLE_AUTO") 9203 }) 9204 @Focusable 9205 public int getFocusable() { 9206 return (mViewFlags & FOCUSABLE_AUTO) > 0 ? FOCUSABLE_AUTO : mViewFlags & FOCUSABLE; 9207 } 9208 9209 /** 9210 * When a view is focusable, it may not want to take focus when in touch mode. 9211 * For example, a button would like focus when the user is navigating via a D-pad 9212 * so that the user can click on it, but once the user starts touching the screen, 9213 * the button shouldn't take focus 9214 * @return Whether the view is focusable in touch mode. 9215 * @attr ref android.R.styleable#View_focusableInTouchMode 9216 */ 9217 @ViewDebug.ExportedProperty 9218 public final boolean isFocusableInTouchMode() { 9219 return FOCUSABLE_IN_TOUCH_MODE == (mViewFlags & FOCUSABLE_IN_TOUCH_MODE); 9220 } 9221 9222 /** 9223 * Find the nearest view in the specified direction that can take focus. 9224 * This does not actually give focus to that view. 9225 * 9226 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT 9227 * 9228 * @return The nearest focusable in the specified direction, or null if none 9229 * can be found. 9230 */ 9231 public View focusSearch(@FocusRealDirection int direction) { 9232 if (mParent != null) { 9233 return mParent.focusSearch(this, direction); 9234 } else { 9235 return null; 9236 } 9237 } 9238 9239 /** 9240 * Returns whether this View is a root of a keyboard navigation cluster. 9241 * 9242 * @return True if this view is a root of a cluster, or false otherwise. 9243 * @attr ref android.R.styleable#View_keyboardNavigationCluster 9244 */ 9245 @ViewDebug.ExportedProperty(category = "keyboardNavigationCluster") 9246 public final boolean isKeyboardNavigationCluster() { 9247 return (mPrivateFlags3 & PFLAG3_CLUSTER) != 0; 9248 } 9249 9250 /** 9251 * Set whether this view is a root of a keyboard navigation cluster. 9252 * 9253 * @param isCluster If true, this view is a root of a cluster. 9254 * 9255 * @attr ref android.R.styleable#View_keyboardNavigationCluster 9256 */ 9257 public void setKeyboardNavigationCluster(boolean isCluster) { 9258 if (isCluster) { 9259 mPrivateFlags3 |= PFLAG3_CLUSTER; 9260 } else { 9261 mPrivateFlags3 &= ~PFLAG3_CLUSTER; 9262 } 9263 } 9264 9265 /** 9266 * Sets this View as the one which receives focus the next time cluster navigation jumps 9267 * to the cluster containing this View. This does NOT change focus even if the cluster 9268 * containing this view is current. 9269 * 9270 * @hide 9271 */ 9272 public void setFocusedInCluster() { 9273 if (mParent instanceof ViewGroup) { 9274 ((ViewGroup) mParent).setFocusInCluster(this); 9275 } 9276 } 9277 9278 /** 9279 * Returns whether this View should receive focus when the focus is restored for the view 9280 * hierarchy containing this view. 9281 * <p> 9282 * Focus gets restored for a view hierarchy when the root of the hierarchy gets added to a 9283 * window or serves as a target of cluster navigation. 9284 * 9285 * @see #restoreDefaultFocus(int) 9286 * 9287 * @return {@code true} if this view is the default-focus view, {@code false} otherwise 9288 * @attr ref android.R.styleable#View_focusedByDefault 9289 */ 9290 @ViewDebug.ExportedProperty(category = "focusedByDefault") 9291 public final boolean isFocusedByDefault() { 9292 return (mPrivateFlags3 & PFLAG3_FOCUSED_BY_DEFAULT) != 0; 9293 } 9294 9295 /** 9296 * Sets whether this View should receive focus when the focus is restored for the view 9297 * hierarchy containing this view. 9298 * <p> 9299 * Focus gets restored for a view hierarchy when the root of the hierarchy gets added to a 9300 * window or serves as a target of cluster navigation. 9301 * 9302 * @param isFocusedByDefault {@code true} to set this view as the default-focus view, 9303 * {@code false} otherwise. 9304 * 9305 * @see #restoreDefaultFocus(int) 9306 * 9307 * @attr ref android.R.styleable#View_focusedByDefault 9308 */ 9309 public void setFocusedByDefault(boolean isFocusedByDefault) { 9310 if (isFocusedByDefault == ((mPrivateFlags3 & PFLAG3_FOCUSED_BY_DEFAULT) != 0)) { 9311 return; 9312 } 9313 9314 if (isFocusedByDefault) { 9315 mPrivateFlags3 |= PFLAG3_FOCUSED_BY_DEFAULT; 9316 } else { 9317 mPrivateFlags3 &= ~PFLAG3_FOCUSED_BY_DEFAULT; 9318 } 9319 9320 if (mParent instanceof ViewGroup) { 9321 if (isFocusedByDefault) { 9322 ((ViewGroup) mParent).setDefaultFocus(this); 9323 } else { 9324 ((ViewGroup) mParent).clearDefaultFocus(this); 9325 } 9326 } 9327 } 9328 9329 /** 9330 * Returns whether the view hierarchy with this view as a root contain a default-focus view. 9331 * 9332 * @return {@code true} if this view has default focus, {@code false} otherwise 9333 */ 9334 boolean hasDefaultFocus() { 9335 return isFocusedByDefault(); 9336 } 9337 9338 /** 9339 * Find the nearest keyboard navigation cluster in the specified direction. 9340 * This does not actually give focus to that cluster. 9341 * 9342 * @param currentCluster The starting point of the search. Null means the current cluster is not 9343 * found yet 9344 * @param direction Direction to look 9345 * 9346 * @return The nearest keyboard navigation cluster in the specified direction, or null if none 9347 * can be found 9348 */ 9349 public View keyboardNavigationClusterSearch(View currentCluster, int direction) { 9350 if (isKeyboardNavigationCluster()) { 9351 currentCluster = this; 9352 } 9353 if (isRootNamespace()) { 9354 // Root namespace means we should consider ourselves the top of the 9355 // tree for group searching; otherwise we could be group searching 9356 // into other tabs. see LocalActivityManager and TabHost for more info. 9357 return FocusFinder.getInstance().findNextKeyboardNavigationCluster( 9358 this, currentCluster, direction); 9359 } else if (mParent != null) { 9360 return mParent.keyboardNavigationClusterSearch(currentCluster, direction); 9361 } 9362 return null; 9363 } 9364 9365 /** 9366 * This method is the last chance for the focused view and its ancestors to 9367 * respond to an arrow key. This is called when the focused view did not 9368 * consume the key internally, nor could the view system find a new view in 9369 * the requested direction to give focus to. 9370 * 9371 * @param focused The currently focused view. 9372 * @param direction The direction focus wants to move. One of FOCUS_UP, 9373 * FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT. 9374 * @return True if the this view consumed this unhandled move. 9375 */ 9376 public boolean dispatchUnhandledMove(View focused, @FocusRealDirection int direction) { 9377 return false; 9378 } 9379 9380 /** 9381 * If a user manually specified the next view id for a particular direction, 9382 * use the root to look up the view. 9383 * @param root The root view of the hierarchy containing this view. 9384 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, FOCUS_RIGHT, FOCUS_FORWARD, 9385 * or FOCUS_BACKWARD. 9386 * @return The user specified next view, or null if there is none. 9387 */ 9388 View findUserSetNextFocus(View root, @FocusDirection int direction) { 9389 switch (direction) { 9390 case FOCUS_LEFT: 9391 if (mNextFocusLeftId == View.NO_ID) return null; 9392 return findViewInsideOutShouldExist(root, mNextFocusLeftId); 9393 case FOCUS_RIGHT: 9394 if (mNextFocusRightId == View.NO_ID) return null; 9395 return findViewInsideOutShouldExist(root, mNextFocusRightId); 9396 case FOCUS_UP: 9397 if (mNextFocusUpId == View.NO_ID) return null; 9398 return findViewInsideOutShouldExist(root, mNextFocusUpId); 9399 case FOCUS_DOWN: 9400 if (mNextFocusDownId == View.NO_ID) return null; 9401 return findViewInsideOutShouldExist(root, mNextFocusDownId); 9402 case FOCUS_FORWARD: 9403 if (mNextFocusForwardId == View.NO_ID) return null; 9404 return findViewInsideOutShouldExist(root, mNextFocusForwardId); 9405 case FOCUS_BACKWARD: { 9406 if (mID == View.NO_ID) return null; 9407 final int id = mID; 9408 return root.findViewByPredicateInsideOut(this, new Predicate<View>() { 9409 @Override 9410 public boolean test(View t) { 9411 return t.mNextFocusForwardId == id; 9412 } 9413 }); 9414 } 9415 } 9416 return null; 9417 } 9418 9419 private View findViewInsideOutShouldExist(View root, int id) { 9420 if (mMatchIdPredicate == null) { 9421 mMatchIdPredicate = new MatchIdPredicate(); 9422 } 9423 mMatchIdPredicate.mId = id; 9424 View result = root.findViewByPredicateInsideOut(this, mMatchIdPredicate); 9425 if (result == null) { 9426 Log.w(VIEW_LOG_TAG, "couldn't find view with id " + id); 9427 } 9428 return result; 9429 } 9430 9431 /** 9432 * Find and return all focusable views that are descendants of this view, 9433 * possibly including this view if it is focusable itself. 9434 * 9435 * @param direction The direction of the focus 9436 * @return A list of focusable views 9437 */ 9438 public ArrayList<View> getFocusables(@FocusDirection int direction) { 9439 ArrayList<View> result = new ArrayList<View>(24); 9440 addFocusables(result, direction); 9441 return result; 9442 } 9443 9444 /** 9445 * Add any focusable views that are descendants of this view (possibly 9446 * including this view if it is focusable itself) to views. If we are in touch mode, 9447 * only add views that are also focusable in touch mode. 9448 * 9449 * @param views Focusable views found so far 9450 * @param direction The direction of the focus 9451 */ 9452 public void addFocusables(ArrayList<View> views, @FocusDirection int direction) { 9453 addFocusables(views, direction, isInTouchMode() ? FOCUSABLES_TOUCH_MODE : FOCUSABLES_ALL); 9454 } 9455 9456 /** 9457 * Adds any focusable views that are descendants of this view (possibly 9458 * including this view if it is focusable itself) to views. This method 9459 * adds all focusable views regardless if we are in touch mode or 9460 * only views focusable in touch mode if we are in touch mode or 9461 * only views that can take accessibility focus if accessibility is enabled 9462 * depending on the focusable mode parameter. 9463 * 9464 * @param views Focusable views found so far or null if all we are interested is 9465 * the number of focusables. 9466 * @param direction The direction of the focus. 9467 * @param focusableMode The type of focusables to be added. 9468 * 9469 * @see #FOCUSABLES_ALL 9470 * @see #FOCUSABLES_TOUCH_MODE 9471 */ 9472 public void addFocusables(ArrayList<View> views, @FocusDirection int direction, 9473 @FocusableMode int focusableMode) { 9474 if (views == null) { 9475 return; 9476 } 9477 if (!isFocusable()) { 9478 return; 9479 } 9480 if ((focusableMode & FOCUSABLES_TOUCH_MODE) == FOCUSABLES_TOUCH_MODE 9481 && !isFocusableInTouchMode()) { 9482 return; 9483 } 9484 views.add(this); 9485 } 9486 9487 /** 9488 * Adds any keyboard navigation cluster roots that are descendants of this view (possibly 9489 * including this view if it is a cluster root itself) to views. 9490 * 9491 * @param views Keyboard navigation cluster roots found so far 9492 * @param direction Direction to look 9493 */ 9494 public void addKeyboardNavigationClusters( 9495 @NonNull Collection<View> views, 9496 int direction) { 9497 if (!isKeyboardNavigationCluster()) { 9498 return; 9499 } 9500 if (!hasFocusable()) { 9501 return; 9502 } 9503 views.add(this); 9504 } 9505 9506 /** 9507 * Finds the Views that contain given text. The containment is case insensitive. 9508 * The search is performed by either the text that the View renders or the content 9509 * description that describes the view for accessibility purposes and the view does 9510 * not render or both. Clients can specify how the search is to be performed via 9511 * passing the {@link #FIND_VIEWS_WITH_TEXT} and 9512 * {@link #FIND_VIEWS_WITH_CONTENT_DESCRIPTION} flags. 9513 * 9514 * @param outViews The output list of matching Views. 9515 * @param searched The text to match against. 9516 * 9517 * @see #FIND_VIEWS_WITH_TEXT 9518 * @see #FIND_VIEWS_WITH_CONTENT_DESCRIPTION 9519 * @see #setContentDescription(CharSequence) 9520 */ 9521 public void findViewsWithText(ArrayList<View> outViews, CharSequence searched, 9522 @FindViewFlags int flags) { 9523 if (getAccessibilityNodeProvider() != null) { 9524 if ((flags & FIND_VIEWS_WITH_ACCESSIBILITY_NODE_PROVIDERS) != 0) { 9525 outViews.add(this); 9526 } 9527 } else if ((flags & FIND_VIEWS_WITH_CONTENT_DESCRIPTION) != 0 9528 && (searched != null && searched.length() > 0) 9529 && (mContentDescription != null && mContentDescription.length() > 0)) { 9530 String searchedLowerCase = searched.toString().toLowerCase(); 9531 String contentDescriptionLowerCase = mContentDescription.toString().toLowerCase(); 9532 if (contentDescriptionLowerCase.contains(searchedLowerCase)) { 9533 outViews.add(this); 9534 } 9535 } 9536 } 9537 9538 /** 9539 * Find and return all touchable views that are descendants of this view, 9540 * possibly including this view if it is touchable itself. 9541 * 9542 * @return A list of touchable views 9543 */ 9544 public ArrayList<View> getTouchables() { 9545 ArrayList<View> result = new ArrayList<View>(); 9546 addTouchables(result); 9547 return result; 9548 } 9549 9550 /** 9551 * Add any touchable views that are descendants of this view (possibly 9552 * including this view if it is touchable itself) to views. 9553 * 9554 * @param views Touchable views found so far 9555 */ 9556 public void addTouchables(ArrayList<View> views) { 9557 final int viewFlags = mViewFlags; 9558 9559 if (((viewFlags & CLICKABLE) == CLICKABLE || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE 9560 || (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE) 9561 && (viewFlags & ENABLED_MASK) == ENABLED) { 9562 views.add(this); 9563 } 9564 } 9565 9566 /** 9567 * Returns whether this View is accessibility focused. 9568 * 9569 * @return True if this View is accessibility focused. 9570 */ 9571 public boolean isAccessibilityFocused() { 9572 return (mPrivateFlags2 & PFLAG2_ACCESSIBILITY_FOCUSED) != 0; 9573 } 9574 9575 /** 9576 * Call this to try to give accessibility focus to this view. 9577 * 9578 * A view will not actually take focus if {@link AccessibilityManager#isEnabled()} 9579 * returns false or the view is no visible or the view already has accessibility 9580 * focus. 9581 * 9582 * See also {@link #focusSearch(int)}, which is what you call to say that you 9583 * have focus, and you want your parent to look for the next one. 9584 * 9585 * @return Whether this view actually took accessibility focus. 9586 * 9587 * @hide 9588 */ 9589 public boolean requestAccessibilityFocus() { 9590 AccessibilityManager manager = AccessibilityManager.getInstance(mContext); 9591 if (!manager.isEnabled() || !manager.isTouchExplorationEnabled()) { 9592 return false; 9593 } 9594 if ((mViewFlags & VISIBILITY_MASK) != VISIBLE) { 9595 return false; 9596 } 9597 if ((mPrivateFlags2 & PFLAG2_ACCESSIBILITY_FOCUSED) == 0) { 9598 mPrivateFlags2 |= PFLAG2_ACCESSIBILITY_FOCUSED; 9599 ViewRootImpl viewRootImpl = getViewRootImpl(); 9600 if (viewRootImpl != null) { 9601 viewRootImpl.setAccessibilityFocus(this, null); 9602 } 9603 invalidate(); 9604 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED); 9605 return true; 9606 } 9607 return false; 9608 } 9609 9610 /** 9611 * Call this to try to clear accessibility focus of this view. 9612 * 9613 * See also {@link #focusSearch(int)}, which is what you call to say that you 9614 * have focus, and you want your parent to look for the next one. 9615 * 9616 * @hide 9617 */ 9618 public void clearAccessibilityFocus() { 9619 clearAccessibilityFocusNoCallbacks(0); 9620 9621 // Clear the global reference of accessibility focus if this view or 9622 // any of its descendants had accessibility focus. This will NOT send 9623 // an event or update internal state if focus is cleared from a 9624 // descendant view, which may leave views in inconsistent states. 9625 final ViewRootImpl viewRootImpl = getViewRootImpl(); 9626 if (viewRootImpl != null) { 9627 final View focusHost = viewRootImpl.getAccessibilityFocusedHost(); 9628 if (focusHost != null && ViewRootImpl.isViewDescendantOf(focusHost, this)) { 9629 viewRootImpl.setAccessibilityFocus(null, null); 9630 } 9631 } 9632 } 9633 9634 private void sendAccessibilityHoverEvent(int eventType) { 9635 // Since we are not delivering to a client accessibility events from not 9636 // important views (unless the clinet request that) we need to fire the 9637 // event from the deepest view exposed to the client. As a consequence if 9638 // the user crosses a not exposed view the client will see enter and exit 9639 // of the exposed predecessor followed by and enter and exit of that same 9640 // predecessor when entering and exiting the not exposed descendant. This 9641 // is fine since the client has a clear idea which view is hovered at the 9642 // price of a couple more events being sent. This is a simple and 9643 // working solution. 9644 View source = this; 9645 while (true) { 9646 if (source.includeForAccessibility()) { 9647 source.sendAccessibilityEvent(eventType); 9648 return; 9649 } 9650 ViewParent parent = source.getParent(); 9651 if (parent instanceof View) { 9652 source = (View) parent; 9653 } else { 9654 return; 9655 } 9656 } 9657 } 9658 9659 /** 9660 * Clears accessibility focus without calling any callback methods 9661 * normally invoked in {@link #clearAccessibilityFocus()}. This method 9662 * is used separately from that one for clearing accessibility focus when 9663 * giving this focus to another view. 9664 * 9665 * @param action The action, if any, that led to focus being cleared. Set to 9666 * AccessibilityNodeInfo#ACTION_ACCESSIBILITY_FOCUS to specify that focus is moving within 9667 * the window. 9668 */ 9669 void clearAccessibilityFocusNoCallbacks(int action) { 9670 if ((mPrivateFlags2 & PFLAG2_ACCESSIBILITY_FOCUSED) != 0) { 9671 mPrivateFlags2 &= ~PFLAG2_ACCESSIBILITY_FOCUSED; 9672 invalidate(); 9673 if (AccessibilityManager.getInstance(mContext).isEnabled()) { 9674 AccessibilityEvent event = AccessibilityEvent.obtain( 9675 AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED); 9676 event.setAction(action); 9677 if (mAccessibilityDelegate != null) { 9678 mAccessibilityDelegate.sendAccessibilityEventUnchecked(this, event); 9679 } else { 9680 sendAccessibilityEventUnchecked(event); 9681 } 9682 } 9683 } 9684 } 9685 9686 /** 9687 * Call this to try to give focus to a specific view or to one of its 9688 * descendants. 9689 * 9690 * A view will not actually take focus if it is not focusable ({@link #isFocusable} returns 9691 * false), or if it is focusable and it is not focusable in touch mode 9692 * ({@link #isFocusableInTouchMode}) while the device is in touch mode. 9693 * 9694 * See also {@link #focusSearch(int)}, which is what you call to say that you 9695 * have focus, and you want your parent to look for the next one. 9696 * 9697 * This is equivalent to calling {@link #requestFocus(int, Rect)} with arguments 9698 * {@link #FOCUS_DOWN} and <code>null</code>. 9699 * 9700 * @return Whether this view or one of its descendants actually took focus. 9701 */ 9702 public final boolean requestFocus() { 9703 return requestFocus(View.FOCUS_DOWN); 9704 } 9705 9706 /** 9707 * This will request focus for whichever View was last focused within this 9708 * cluster before a focus-jump out of it. 9709 * 9710 * @hide 9711 */ 9712 @TestApi 9713 public boolean restoreFocusInCluster(@FocusRealDirection int direction) { 9714 // Prioritize focusableByDefault over algorithmic focus selection. 9715 if (restoreDefaultFocus()) { 9716 return true; 9717 } 9718 return requestFocus(direction); 9719 } 9720 9721 /** 9722 * This will request focus for whichever View not in a cluster was last focused before a 9723 * focus-jump to a cluster. If no non-cluster View has previously had focus, this will focus 9724 * the "first" focusable view it finds. 9725 * 9726 * @hide 9727 */ 9728 @TestApi 9729 public boolean restoreFocusNotInCluster() { 9730 return requestFocus(View.FOCUS_DOWN); 9731 } 9732 9733 /** 9734 * Gives focus to the default-focus view in the view hierarchy that has this view as a root. 9735 * If the default-focus view cannot be found, falls back to calling {@link #requestFocus(int)}. 9736 * 9737 * @return Whether this view or one of its descendants actually took focus 9738 */ 9739 public boolean restoreDefaultFocus() { 9740 return requestFocus(View.FOCUS_DOWN); 9741 } 9742 9743 /** 9744 * Call this to try to give focus to a specific view or to one of its 9745 * descendants and give it a hint about what direction focus is heading. 9746 * 9747 * A view will not actually take focus if it is not focusable ({@link #isFocusable} returns 9748 * false), or if it is focusable and it is not focusable in touch mode 9749 * ({@link #isFocusableInTouchMode}) while the device is in touch mode. 9750 * 9751 * See also {@link #focusSearch(int)}, which is what you call to say that you 9752 * have focus, and you want your parent to look for the next one. 9753 * 9754 * This is equivalent to calling {@link #requestFocus(int, Rect)} with 9755 * <code>null</code> set for the previously focused rectangle. 9756 * 9757 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT 9758 * @return Whether this view or one of its descendants actually took focus. 9759 */ 9760 public final boolean requestFocus(int direction) { 9761 return requestFocus(direction, null); 9762 } 9763 9764 /** 9765 * Call this to try to give focus to a specific view or to one of its descendants 9766 * and give it hints about the direction and a specific rectangle that the focus 9767 * is coming from. The rectangle can help give larger views a finer grained hint 9768 * about where focus is coming from, and therefore, where to show selection, or 9769 * forward focus change internally. 9770 * 9771 * A view will not actually take focus if it is not focusable ({@link #isFocusable} returns 9772 * false), or if it is focusable and it is not focusable in touch mode 9773 * ({@link #isFocusableInTouchMode}) while the device is in touch mode. 9774 * 9775 * A View will not take focus if it is not visible. 9776 * 9777 * A View will not take focus if one of its parents has 9778 * {@link android.view.ViewGroup#getDescendantFocusability()} equal to 9779 * {@link ViewGroup#FOCUS_BLOCK_DESCENDANTS}. 9780 * 9781 * See also {@link #focusSearch(int)}, which is what you call to say that you 9782 * have focus, and you want your parent to look for the next one. 9783 * 9784 * You may wish to override this method if your custom {@link View} has an internal 9785 * {@link View} that it wishes to forward the request to. 9786 * 9787 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT 9788 * @param previouslyFocusedRect The rectangle (in this View's coordinate system) 9789 * to give a finer grained hint about where focus is coming from. May be null 9790 * if there is no hint. 9791 * @return Whether this view or one of its descendants actually took focus. 9792 */ 9793 public boolean requestFocus(int direction, Rect previouslyFocusedRect) { 9794 return requestFocusNoSearch(direction, previouslyFocusedRect); 9795 } 9796 9797 private boolean requestFocusNoSearch(int direction, Rect previouslyFocusedRect) { 9798 // need to be focusable 9799 if ((mViewFlags & FOCUSABLE) != FOCUSABLE 9800 || (mViewFlags & VISIBILITY_MASK) != VISIBLE) { 9801 return false; 9802 } 9803 9804 // need to be focusable in touch mode if in touch mode 9805 if (isInTouchMode() && 9806 (FOCUSABLE_IN_TOUCH_MODE != (mViewFlags & FOCUSABLE_IN_TOUCH_MODE))) { 9807 return false; 9808 } 9809 9810 // need to not have any parents blocking us 9811 if (hasAncestorThatBlocksDescendantFocus()) { 9812 return false; 9813 } 9814 9815 handleFocusGainInternal(direction, previouslyFocusedRect); 9816 return true; 9817 } 9818 9819 /** 9820 * Call this to try to give focus to a specific view or to one of its descendants. This is a 9821 * special variant of {@link #requestFocus() } that will allow views that are not focusable in 9822 * touch mode to request focus when they are touched. 9823 * 9824 * @return Whether this view or one of its descendants actually took focus. 9825 * 9826 * @see #isInTouchMode() 9827 * 9828 */ 9829 public final boolean requestFocusFromTouch() { 9830 // Leave touch mode if we need to 9831 if (isInTouchMode()) { 9832 ViewRootImpl viewRoot = getViewRootImpl(); 9833 if (viewRoot != null) { 9834 viewRoot.ensureTouchMode(false); 9835 } 9836 } 9837 return requestFocus(View.FOCUS_DOWN); 9838 } 9839 9840 /** 9841 * @return Whether any ancestor of this view blocks descendant focus. 9842 */ 9843 private boolean hasAncestorThatBlocksDescendantFocus() { 9844 final boolean focusableInTouchMode = isFocusableInTouchMode(); 9845 ViewParent ancestor = mParent; 9846 while (ancestor instanceof ViewGroup) { 9847 final ViewGroup vgAncestor = (ViewGroup) ancestor; 9848 if (vgAncestor.getDescendantFocusability() == ViewGroup.FOCUS_BLOCK_DESCENDANTS 9849 || (!focusableInTouchMode && vgAncestor.shouldBlockFocusForTouchscreen())) { 9850 return true; 9851 } else { 9852 ancestor = vgAncestor.getParent(); 9853 } 9854 } 9855 return false; 9856 } 9857 9858 /** 9859 * Gets the mode for determining whether this View is important for accessibility. 9860 * A view is important for accessibility if it fires accessibility events and if it 9861 * is reported to accessibility services that query the screen. 9862 * 9863 * @return The mode for determining whether a view is important for accessibility, one 9864 * of {@link #IMPORTANT_FOR_ACCESSIBILITY_AUTO}, {@link #IMPORTANT_FOR_ACCESSIBILITY_YES}, 9865 * {@link #IMPORTANT_FOR_ACCESSIBILITY_NO}, or 9866 * {@link #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS}. 9867 * 9868 * @attr ref android.R.styleable#View_importantForAccessibility 9869 * 9870 * @see #IMPORTANT_FOR_ACCESSIBILITY_YES 9871 * @see #IMPORTANT_FOR_ACCESSIBILITY_NO 9872 * @see #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS 9873 * @see #IMPORTANT_FOR_ACCESSIBILITY_AUTO 9874 */ 9875 @ViewDebug.ExportedProperty(category = "accessibility", mapping = { 9876 @ViewDebug.IntToString(from = IMPORTANT_FOR_ACCESSIBILITY_AUTO, to = "auto"), 9877 @ViewDebug.IntToString(from = IMPORTANT_FOR_ACCESSIBILITY_YES, to = "yes"), 9878 @ViewDebug.IntToString(from = IMPORTANT_FOR_ACCESSIBILITY_NO, to = "no"), 9879 @ViewDebug.IntToString(from = IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS, 9880 to = "noHideDescendants") 9881 }) 9882 public int getImportantForAccessibility() { 9883 return (mPrivateFlags2 & PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK) 9884 >> PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT; 9885 } 9886 9887 /** 9888 * Sets the live region mode for this view. This indicates to accessibility 9889 * services whether they should automatically notify the user about changes 9890 * to the view's content description or text, or to the content descriptions 9891 * or text of the view's children (where applicable). 9892 * <p> 9893 * For example, in a login screen with a TextView that displays an "incorrect 9894 * password" notification, that view should be marked as a live region with 9895 * mode {@link #ACCESSIBILITY_LIVE_REGION_POLITE}. 9896 * <p> 9897 * To disable change notifications for this view, use 9898 * {@link #ACCESSIBILITY_LIVE_REGION_NONE}. This is the default live region 9899 * mode for most views. 9900 * <p> 9901 * To indicate that the user should be notified of changes, use 9902 * {@link #ACCESSIBILITY_LIVE_REGION_POLITE}. 9903 * <p> 9904 * If the view's changes should interrupt ongoing speech and notify the user 9905 * immediately, use {@link #ACCESSIBILITY_LIVE_REGION_ASSERTIVE}. 9906 * 9907 * @param mode The live region mode for this view, one of: 9908 * <ul> 9909 * <li>{@link #ACCESSIBILITY_LIVE_REGION_NONE} 9910 * <li>{@link #ACCESSIBILITY_LIVE_REGION_POLITE} 9911 * <li>{@link #ACCESSIBILITY_LIVE_REGION_ASSERTIVE} 9912 * </ul> 9913 * @attr ref android.R.styleable#View_accessibilityLiveRegion 9914 */ 9915 public void setAccessibilityLiveRegion(int mode) { 9916 if (mode != getAccessibilityLiveRegion()) { 9917 mPrivateFlags2 &= ~PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK; 9918 mPrivateFlags2 |= (mode << PFLAG2_ACCESSIBILITY_LIVE_REGION_SHIFT) 9919 & PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK; 9920 notifyViewAccessibilityStateChangedIfNeeded( 9921 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 9922 } 9923 } 9924 9925 /** 9926 * Gets the live region mode for this View. 9927 * 9928 * @return The live region mode for the view. 9929 * 9930 * @attr ref android.R.styleable#View_accessibilityLiveRegion 9931 * 9932 * @see #setAccessibilityLiveRegion(int) 9933 */ 9934 public int getAccessibilityLiveRegion() { 9935 return (mPrivateFlags2 & PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK) 9936 >> PFLAG2_ACCESSIBILITY_LIVE_REGION_SHIFT; 9937 } 9938 9939 /** 9940 * Sets how to determine whether this view is important for accessibility 9941 * which is if it fires accessibility events and if it is reported to 9942 * accessibility services that query the screen. 9943 * 9944 * @param mode How to determine whether this view is important for accessibility. 9945 * 9946 * @attr ref android.R.styleable#View_importantForAccessibility 9947 * 9948 * @see #IMPORTANT_FOR_ACCESSIBILITY_YES 9949 * @see #IMPORTANT_FOR_ACCESSIBILITY_NO 9950 * @see #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS 9951 * @see #IMPORTANT_FOR_ACCESSIBILITY_AUTO 9952 */ 9953 public void setImportantForAccessibility(int mode) { 9954 final int oldMode = getImportantForAccessibility(); 9955 if (mode != oldMode) { 9956 final boolean hideDescendants = 9957 mode == IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS; 9958 9959 // If this node or its descendants are no longer important, try to 9960 // clear accessibility focus. 9961 if (mode == IMPORTANT_FOR_ACCESSIBILITY_NO || hideDescendants) { 9962 final View focusHost = findAccessibilityFocusHost(hideDescendants); 9963 if (focusHost != null) { 9964 focusHost.clearAccessibilityFocus(); 9965 } 9966 } 9967 9968 // If we're moving between AUTO and another state, we might not need 9969 // to send a subtree changed notification. We'll store the computed 9970 // importance, since we'll need to check it later to make sure. 9971 final boolean maySkipNotify = oldMode == IMPORTANT_FOR_ACCESSIBILITY_AUTO 9972 || mode == IMPORTANT_FOR_ACCESSIBILITY_AUTO; 9973 final boolean oldIncludeForAccessibility = maySkipNotify && includeForAccessibility(); 9974 mPrivateFlags2 &= ~PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK; 9975 mPrivateFlags2 |= (mode << PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT) 9976 & PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK; 9977 if (!maySkipNotify || oldIncludeForAccessibility != includeForAccessibility()) { 9978 notifySubtreeAccessibilityStateChangedIfNeeded(); 9979 } else { 9980 notifyViewAccessibilityStateChangedIfNeeded( 9981 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 9982 } 9983 } 9984 } 9985 9986 /** 9987 * Returns the view within this view's hierarchy that is hosting 9988 * accessibility focus. 9989 * 9990 * @param searchDescendants whether to search for focus in descendant views 9991 * @return the view hosting accessibility focus, or {@code null} 9992 */ 9993 private View findAccessibilityFocusHost(boolean searchDescendants) { 9994 if (isAccessibilityFocusedViewOrHost()) { 9995 return this; 9996 } 9997 9998 if (searchDescendants) { 9999 final ViewRootImpl viewRoot = getViewRootImpl(); 10000 if (viewRoot != null) { 10001 final View focusHost = viewRoot.getAccessibilityFocusedHost(); 10002 if (focusHost != null && ViewRootImpl.isViewDescendantOf(focusHost, this)) { 10003 return focusHost; 10004 } 10005 } 10006 } 10007 10008 return null; 10009 } 10010 10011 /** 10012 * Computes whether this view should be exposed for accessibility. In 10013 * general, views that are interactive or provide information are exposed 10014 * while views that serve only as containers are hidden. 10015 * <p> 10016 * If an ancestor of this view has importance 10017 * {@link #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS}, this method 10018 * returns <code>false</code>. 10019 * <p> 10020 * Otherwise, the value is computed according to the view's 10021 * {@link #getImportantForAccessibility()} value: 10022 * <ol> 10023 * <li>{@link #IMPORTANT_FOR_ACCESSIBILITY_NO} or 10024 * {@link #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS}, return <code>false 10025 * </code> 10026 * <li>{@link #IMPORTANT_FOR_ACCESSIBILITY_YES}, return <code>true</code> 10027 * <li>{@link #IMPORTANT_FOR_ACCESSIBILITY_AUTO}, return <code>true</code> if 10028 * view satisfies any of the following: 10029 * <ul> 10030 * <li>Is actionable, e.g. {@link #isClickable()}, 10031 * {@link #isLongClickable()}, or {@link #isFocusable()} 10032 * <li>Has an {@link AccessibilityDelegate} 10033 * <li>Has an interaction listener, e.g. {@link OnTouchListener}, 10034 * {@link OnKeyListener}, etc. 10035 * <li>Is an accessibility live region, e.g. 10036 * {@link #getAccessibilityLiveRegion()} is not 10037 * {@link #ACCESSIBILITY_LIVE_REGION_NONE}. 10038 * </ul> 10039 * </ol> 10040 * 10041 * @return Whether the view is exposed for accessibility. 10042 * @see #setImportantForAccessibility(int) 10043 * @see #getImportantForAccessibility() 10044 */ 10045 public boolean isImportantForAccessibility() { 10046 final int mode = (mPrivateFlags2 & PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK) 10047 >> PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT; 10048 if (mode == IMPORTANT_FOR_ACCESSIBILITY_NO 10049 || mode == IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS) { 10050 return false; 10051 } 10052 10053 // Check parent mode to ensure we're not hidden. 10054 ViewParent parent = mParent; 10055 while (parent instanceof View) { 10056 if (((View) parent).getImportantForAccessibility() 10057 == IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS) { 10058 return false; 10059 } 10060 parent = parent.getParent(); 10061 } 10062 10063 return mode == IMPORTANT_FOR_ACCESSIBILITY_YES || isActionableForAccessibility() 10064 || hasListenersForAccessibility() || getAccessibilityNodeProvider() != null 10065 || getAccessibilityLiveRegion() != ACCESSIBILITY_LIVE_REGION_NONE; 10066 } 10067 10068 /** 10069 * Gets the parent for accessibility purposes. Note that the parent for 10070 * accessibility is not necessary the immediate parent. It is the first 10071 * predecessor that is important for accessibility. 10072 * 10073 * @return The parent for accessibility purposes. 10074 */ 10075 public ViewParent getParentForAccessibility() { 10076 if (mParent instanceof View) { 10077 View parentView = (View) mParent; 10078 if (parentView.includeForAccessibility()) { 10079 return mParent; 10080 } else { 10081 return mParent.getParentForAccessibility(); 10082 } 10083 } 10084 return null; 10085 } 10086 10087 /** 10088 * Adds the children of this View relevant for accessibility to the given list 10089 * as output. Since some Views are not important for accessibility the added 10090 * child views are not necessarily direct children of this view, rather they are 10091 * the first level of descendants important for accessibility. 10092 * 10093 * @param outChildren The output list that will receive children for accessibility. 10094 */ 10095 public void addChildrenForAccessibility(ArrayList<View> outChildren) { 10096 10097 } 10098 10099 /** 10100 * Whether to regard this view for accessibility. A view is regarded for 10101 * accessibility if it is important for accessibility or the querying 10102 * accessibility service has explicitly requested that view not 10103 * important for accessibility are regarded. 10104 * 10105 * @return Whether to regard the view for accessibility. 10106 * 10107 * @hide 10108 */ 10109 public boolean includeForAccessibility() { 10110 if (mAttachInfo != null) { 10111 return (mAttachInfo.mAccessibilityFetchFlags 10112 & AccessibilityNodeInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS) != 0 10113 || isImportantForAccessibility(); 10114 } 10115 return false; 10116 } 10117 10118 /** 10119 * Returns whether the View is considered actionable from 10120 * accessibility perspective. Such view are important for 10121 * accessibility. 10122 * 10123 * @return True if the view is actionable for accessibility. 10124 * 10125 * @hide 10126 */ 10127 public boolean isActionableForAccessibility() { 10128 return (isClickable() || isLongClickable() || isFocusable()); 10129 } 10130 10131 /** 10132 * Returns whether the View has registered callbacks which makes it 10133 * important for accessibility. 10134 * 10135 * @return True if the view is actionable for accessibility. 10136 */ 10137 private boolean hasListenersForAccessibility() { 10138 ListenerInfo info = getListenerInfo(); 10139 return mTouchDelegate != null || info.mOnKeyListener != null 10140 || info.mOnTouchListener != null || info.mOnGenericMotionListener != null 10141 || info.mOnHoverListener != null || info.mOnDragListener != null; 10142 } 10143 10144 /** 10145 * Notifies that the accessibility state of this view changed. The change 10146 * is local to this view and does not represent structural changes such 10147 * as children and parent. For example, the view became focusable. The 10148 * notification is at at most once every 10149 * {@link ViewConfiguration#getSendRecurringAccessibilityEventsInterval()} 10150 * to avoid unnecessary load to the system. Also once a view has a pending 10151 * notification this method is a NOP until the notification has been sent. 10152 * 10153 * @hide 10154 */ 10155 public void notifyViewAccessibilityStateChangedIfNeeded(int changeType) { 10156 if (!AccessibilityManager.getInstance(mContext).isEnabled() || mAttachInfo == null) { 10157 return; 10158 } 10159 if (mSendViewStateChangedAccessibilityEvent == null) { 10160 mSendViewStateChangedAccessibilityEvent = 10161 new SendViewStateChangedAccessibilityEvent(); 10162 } 10163 mSendViewStateChangedAccessibilityEvent.runOrPost(changeType); 10164 } 10165 10166 /** 10167 * Notifies that the accessibility state of this view changed. The change 10168 * is *not* local to this view and does represent structural changes such 10169 * as children and parent. For example, the view size changed. The 10170 * notification is at at most once every 10171 * {@link ViewConfiguration#getSendRecurringAccessibilityEventsInterval()} 10172 * to avoid unnecessary load to the system. Also once a view has a pending 10173 * notification this method is a NOP until the notification has been sent. 10174 * 10175 * @hide 10176 */ 10177 public void notifySubtreeAccessibilityStateChangedIfNeeded() { 10178 if (!AccessibilityManager.getInstance(mContext).isEnabled() || mAttachInfo == null) { 10179 return; 10180 } 10181 if ((mPrivateFlags2 & PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED) == 0) { 10182 mPrivateFlags2 |= PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED; 10183 if (mParent != null) { 10184 try { 10185 mParent.notifySubtreeAccessibilityStateChanged( 10186 this, this, AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE); 10187 } catch (AbstractMethodError e) { 10188 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 10189 " does not fully implement ViewParent", e); 10190 } 10191 } 10192 } 10193 } 10194 10195 /** 10196 * Change the visibility of the View without triggering any other changes. This is 10197 * important for transitions, where visibility changes should not adjust focus or 10198 * trigger a new layout. This is only used when the visibility has already been changed 10199 * and we need a transient value during an animation. When the animation completes, 10200 * the original visibility value is always restored. 10201 * 10202 * @param visibility One of {@link #VISIBLE}, {@link #INVISIBLE}, or {@link #GONE}. 10203 * @hide 10204 */ 10205 public void setTransitionVisibility(@Visibility int visibility) { 10206 mViewFlags = (mViewFlags & ~View.VISIBILITY_MASK) | visibility; 10207 } 10208 10209 /** 10210 * Reset the flag indicating the accessibility state of the subtree rooted 10211 * at this view changed. 10212 */ 10213 void resetSubtreeAccessibilityStateChanged() { 10214 mPrivateFlags2 &= ~PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED; 10215 } 10216 10217 /** 10218 * Report an accessibility action to this view's parents for delegated processing. 10219 * 10220 * <p>Implementations of {@link #performAccessibilityAction(int, Bundle)} may internally 10221 * call this method to delegate an accessibility action to a supporting parent. If the parent 10222 * returns true from its 10223 * {@link ViewParent#onNestedPrePerformAccessibilityAction(View, int, android.os.Bundle)} 10224 * method this method will return true to signify that the action was consumed.</p> 10225 * 10226 * <p>This method is useful for implementing nested scrolling child views. If 10227 * {@link #isNestedScrollingEnabled()} returns true and the action is a scrolling action 10228 * a custom view implementation may invoke this method to allow a parent to consume the 10229 * scroll first. If this method returns true the custom view should skip its own scrolling 10230 * behavior.</p> 10231 * 10232 * @param action Accessibility action to delegate 10233 * @param arguments Optional action arguments 10234 * @return true if the action was consumed by a parent 10235 */ 10236 public boolean dispatchNestedPrePerformAccessibilityAction(int action, Bundle arguments) { 10237 for (ViewParent p = getParent(); p != null; p = p.getParent()) { 10238 if (p.onNestedPrePerformAccessibilityAction(this, action, arguments)) { 10239 return true; 10240 } 10241 } 10242 return false; 10243 } 10244 10245 /** 10246 * Performs the specified accessibility action on the view. For 10247 * possible accessibility actions look at {@link AccessibilityNodeInfo}. 10248 * <p> 10249 * If an {@link AccessibilityDelegate} has been specified via calling 10250 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 10251 * {@link AccessibilityDelegate#performAccessibilityAction(View, int, Bundle)} 10252 * is responsible for handling this call. 10253 * </p> 10254 * 10255 * <p>The default implementation will delegate 10256 * {@link AccessibilityNodeInfo#ACTION_SCROLL_BACKWARD} and 10257 * {@link AccessibilityNodeInfo#ACTION_SCROLL_FORWARD} to nested scrolling parents if 10258 * {@link #isNestedScrollingEnabled() nested scrolling is enabled} on this view.</p> 10259 * 10260 * @param action The action to perform. 10261 * @param arguments Optional action arguments. 10262 * @return Whether the action was performed. 10263 */ 10264 public boolean performAccessibilityAction(int action, Bundle arguments) { 10265 if (mAccessibilityDelegate != null) { 10266 return mAccessibilityDelegate.performAccessibilityAction(this, action, arguments); 10267 } else { 10268 return performAccessibilityActionInternal(action, arguments); 10269 } 10270 } 10271 10272 /** 10273 * @see #performAccessibilityAction(int, Bundle) 10274 * 10275 * Note: Called from the default {@link AccessibilityDelegate}. 10276 * 10277 * @hide 10278 */ 10279 public boolean performAccessibilityActionInternal(int action, Bundle arguments) { 10280 if (isNestedScrollingEnabled() 10281 && (action == AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD 10282 || action == AccessibilityNodeInfo.ACTION_SCROLL_FORWARD 10283 || action == R.id.accessibilityActionScrollUp 10284 || action == R.id.accessibilityActionScrollLeft 10285 || action == R.id.accessibilityActionScrollDown 10286 || action == R.id.accessibilityActionScrollRight)) { 10287 if (dispatchNestedPrePerformAccessibilityAction(action, arguments)) { 10288 return true; 10289 } 10290 } 10291 10292 switch (action) { 10293 case AccessibilityNodeInfo.ACTION_CLICK: { 10294 if (isClickable()) { 10295 performClick(); 10296 return true; 10297 } 10298 } break; 10299 case AccessibilityNodeInfo.ACTION_LONG_CLICK: { 10300 if (isLongClickable()) { 10301 performLongClick(); 10302 return true; 10303 } 10304 } break; 10305 case AccessibilityNodeInfo.ACTION_FOCUS: { 10306 if (!hasFocus()) { 10307 // Get out of touch mode since accessibility 10308 // wants to move focus around. 10309 getViewRootImpl().ensureTouchMode(false); 10310 return requestFocus(); 10311 } 10312 } break; 10313 case AccessibilityNodeInfo.ACTION_CLEAR_FOCUS: { 10314 if (hasFocus()) { 10315 clearFocus(); 10316 return !isFocused(); 10317 } 10318 } break; 10319 case AccessibilityNodeInfo.ACTION_SELECT: { 10320 if (!isSelected()) { 10321 setSelected(true); 10322 return isSelected(); 10323 } 10324 } break; 10325 case AccessibilityNodeInfo.ACTION_CLEAR_SELECTION: { 10326 if (isSelected()) { 10327 setSelected(false); 10328 return !isSelected(); 10329 } 10330 } break; 10331 case AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS: { 10332 if (!isAccessibilityFocused()) { 10333 return requestAccessibilityFocus(); 10334 } 10335 } break; 10336 case AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS: { 10337 if (isAccessibilityFocused()) { 10338 clearAccessibilityFocus(); 10339 return true; 10340 } 10341 } break; 10342 case AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY: { 10343 if (arguments != null) { 10344 final int granularity = arguments.getInt( 10345 AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT); 10346 final boolean extendSelection = arguments.getBoolean( 10347 AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN); 10348 return traverseAtGranularity(granularity, true, extendSelection); 10349 } 10350 } break; 10351 case AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY: { 10352 if (arguments != null) { 10353 final int granularity = arguments.getInt( 10354 AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT); 10355 final boolean extendSelection = arguments.getBoolean( 10356 AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN); 10357 return traverseAtGranularity(granularity, false, extendSelection); 10358 } 10359 } break; 10360 case AccessibilityNodeInfo.ACTION_SET_SELECTION: { 10361 CharSequence text = getIterableTextForAccessibility(); 10362 if (text == null) { 10363 return false; 10364 } 10365 final int start = (arguments != null) ? arguments.getInt( 10366 AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT, -1) : -1; 10367 final int end = (arguments != null) ? arguments.getInt( 10368 AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT, -1) : -1; 10369 // Only cursor position can be specified (selection length == 0) 10370 if ((getAccessibilitySelectionStart() != start 10371 || getAccessibilitySelectionEnd() != end) 10372 && (start == end)) { 10373 setAccessibilitySelection(start, end); 10374 notifyViewAccessibilityStateChangedIfNeeded( 10375 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 10376 return true; 10377 } 10378 } break; 10379 case R.id.accessibilityActionShowOnScreen: { 10380 if (mAttachInfo != null) { 10381 final Rect r = mAttachInfo.mTmpInvalRect; 10382 getDrawingRect(r); 10383 return requestRectangleOnScreen(r, true); 10384 } 10385 } break; 10386 case R.id.accessibilityActionContextClick: { 10387 if (isContextClickable()) { 10388 performContextClick(); 10389 return true; 10390 } 10391 } break; 10392 } 10393 return false; 10394 } 10395 10396 private boolean traverseAtGranularity(int granularity, boolean forward, 10397 boolean extendSelection) { 10398 CharSequence text = getIterableTextForAccessibility(); 10399 if (text == null || text.length() == 0) { 10400 return false; 10401 } 10402 TextSegmentIterator iterator = getIteratorForGranularity(granularity); 10403 if (iterator == null) { 10404 return false; 10405 } 10406 int current = getAccessibilitySelectionEnd(); 10407 if (current == ACCESSIBILITY_CURSOR_POSITION_UNDEFINED) { 10408 current = forward ? 0 : text.length(); 10409 } 10410 final int[] range = forward ? iterator.following(current) : iterator.preceding(current); 10411 if (range == null) { 10412 return false; 10413 } 10414 final int segmentStart = range[0]; 10415 final int segmentEnd = range[1]; 10416 int selectionStart; 10417 int selectionEnd; 10418 if (extendSelection && isAccessibilitySelectionExtendable()) { 10419 selectionStart = getAccessibilitySelectionStart(); 10420 if (selectionStart == ACCESSIBILITY_CURSOR_POSITION_UNDEFINED) { 10421 selectionStart = forward ? segmentStart : segmentEnd; 10422 } 10423 selectionEnd = forward ? segmentEnd : segmentStart; 10424 } else { 10425 selectionStart = selectionEnd= forward ? segmentEnd : segmentStart; 10426 } 10427 setAccessibilitySelection(selectionStart, selectionEnd); 10428 final int action = forward ? AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY 10429 : AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY; 10430 sendViewTextTraversedAtGranularityEvent(action, granularity, segmentStart, segmentEnd); 10431 return true; 10432 } 10433 10434 /** 10435 * Gets the text reported for accessibility purposes. 10436 * 10437 * @return The accessibility text. 10438 * 10439 * @hide 10440 */ 10441 public CharSequence getIterableTextForAccessibility() { 10442 return getContentDescription(); 10443 } 10444 10445 /** 10446 * Gets whether accessibility selection can be extended. 10447 * 10448 * @return If selection is extensible. 10449 * 10450 * @hide 10451 */ 10452 public boolean isAccessibilitySelectionExtendable() { 10453 return false; 10454 } 10455 10456 /** 10457 * @hide 10458 */ 10459 public int getAccessibilitySelectionStart() { 10460 return mAccessibilityCursorPosition; 10461 } 10462 10463 /** 10464 * @hide 10465 */ 10466 public int getAccessibilitySelectionEnd() { 10467 return getAccessibilitySelectionStart(); 10468 } 10469 10470 /** 10471 * @hide 10472 */ 10473 public void setAccessibilitySelection(int start, int end) { 10474 if (start == end && end == mAccessibilityCursorPosition) { 10475 return; 10476 } 10477 if (start >= 0 && start == end && end <= getIterableTextForAccessibility().length()) { 10478 mAccessibilityCursorPosition = start; 10479 } else { 10480 mAccessibilityCursorPosition = ACCESSIBILITY_CURSOR_POSITION_UNDEFINED; 10481 } 10482 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED); 10483 } 10484 10485 private void sendViewTextTraversedAtGranularityEvent(int action, int granularity, 10486 int fromIndex, int toIndex) { 10487 if (mParent == null) { 10488 return; 10489 } 10490 AccessibilityEvent event = AccessibilityEvent.obtain( 10491 AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY); 10492 onInitializeAccessibilityEvent(event); 10493 onPopulateAccessibilityEvent(event); 10494 event.setFromIndex(fromIndex); 10495 event.setToIndex(toIndex); 10496 event.setAction(action); 10497 event.setMovementGranularity(granularity); 10498 mParent.requestSendAccessibilityEvent(this, event); 10499 } 10500 10501 /** 10502 * @hide 10503 */ 10504 public TextSegmentIterator getIteratorForGranularity(int granularity) { 10505 switch (granularity) { 10506 case AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER: { 10507 CharSequence text = getIterableTextForAccessibility(); 10508 if (text != null && text.length() > 0) { 10509 CharacterTextSegmentIterator iterator = 10510 CharacterTextSegmentIterator.getInstance( 10511 mContext.getResources().getConfiguration().locale); 10512 iterator.initialize(text.toString()); 10513 return iterator; 10514 } 10515 } break; 10516 case AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD: { 10517 CharSequence text = getIterableTextForAccessibility(); 10518 if (text != null && text.length() > 0) { 10519 WordTextSegmentIterator iterator = 10520 WordTextSegmentIterator.getInstance( 10521 mContext.getResources().getConfiguration().locale); 10522 iterator.initialize(text.toString()); 10523 return iterator; 10524 } 10525 } break; 10526 case AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH: { 10527 CharSequence text = getIterableTextForAccessibility(); 10528 if (text != null && text.length() > 0) { 10529 ParagraphTextSegmentIterator iterator = 10530 ParagraphTextSegmentIterator.getInstance(); 10531 iterator.initialize(text.toString()); 10532 return iterator; 10533 } 10534 } break; 10535 } 10536 return null; 10537 } 10538 10539 /** 10540 * Tells whether the {@link View} is in the state between {@link #onStartTemporaryDetach()} 10541 * and {@link #onFinishTemporaryDetach()}. 10542 * 10543 * <p>This method always returns {@code true} when called directly or indirectly from 10544 * {@link #onStartTemporaryDetach()}. The return value when called directly or indirectly from 10545 * {@link #onFinishTemporaryDetach()}, however, depends on the OS version. 10546 * <ul> 10547 * <li>{@code true} on {@link android.os.Build.VERSION_CODES#N API 24}</li> 10548 * <li>{@code false} on {@link android.os.Build.VERSION_CODES#N_MR1 API 25}} and later</li> 10549 * </ul> 10550 * </p> 10551 * 10552 * @return {@code true} when the View is in the state between {@link #onStartTemporaryDetach()} 10553 * and {@link #onFinishTemporaryDetach()}. 10554 */ 10555 public final boolean isTemporarilyDetached() { 10556 return (mPrivateFlags3 & PFLAG3_TEMPORARY_DETACH) != 0; 10557 } 10558 10559 /** 10560 * Dispatch {@link #onStartTemporaryDetach()} to this View and its direct children if this is 10561 * a container View. 10562 */ 10563 @CallSuper 10564 public void dispatchStartTemporaryDetach() { 10565 mPrivateFlags3 |= PFLAG3_TEMPORARY_DETACH; 10566 onStartTemporaryDetach(); 10567 } 10568 10569 /** 10570 * This is called when a container is going to temporarily detach a child, with 10571 * {@link ViewGroup#detachViewFromParent(View) ViewGroup.detachViewFromParent}. 10572 * It will either be followed by {@link #onFinishTemporaryDetach()} or 10573 * {@link #onDetachedFromWindow()} when the container is done. 10574 */ 10575 public void onStartTemporaryDetach() { 10576 removeUnsetPressCallback(); 10577 mPrivateFlags |= PFLAG_CANCEL_NEXT_UP_EVENT; 10578 } 10579 10580 /** 10581 * Dispatch {@link #onFinishTemporaryDetach()} to this View and its direct children if this is 10582 * a container View. 10583 */ 10584 @CallSuper 10585 public void dispatchFinishTemporaryDetach() { 10586 mPrivateFlags3 &= ~PFLAG3_TEMPORARY_DETACH; 10587 onFinishTemporaryDetach(); 10588 if (hasWindowFocus() && hasFocus()) { 10589 InputMethodManager.getInstance().focusIn(this); 10590 } 10591 } 10592 10593 /** 10594 * Called after {@link #onStartTemporaryDetach} when the container is done 10595 * changing the view. 10596 */ 10597 public void onFinishTemporaryDetach() { 10598 } 10599 10600 /** 10601 * Return the global {@link KeyEvent.DispatcherState KeyEvent.DispatcherState} 10602 * for this view's window. Returns null if the view is not currently attached 10603 * to the window. Normally you will not need to use this directly, but 10604 * just use the standard high-level event callbacks like 10605 * {@link #onKeyDown(int, KeyEvent)}. 10606 */ 10607 public KeyEvent.DispatcherState getKeyDispatcherState() { 10608 return mAttachInfo != null ? mAttachInfo.mKeyDispatchState : null; 10609 } 10610 10611 /** 10612 * Dispatch a key event before it is processed by any input method 10613 * associated with the view hierarchy. This can be used to intercept 10614 * key events in special situations before the IME consumes them; a 10615 * typical example would be handling the BACK key to update the application's 10616 * UI instead of allowing the IME to see it and close itself. 10617 * 10618 * @param event The key event to be dispatched. 10619 * @return True if the event was handled, false otherwise. 10620 */ 10621 public boolean dispatchKeyEventPreIme(KeyEvent event) { 10622 return onKeyPreIme(event.getKeyCode(), event); 10623 } 10624 10625 /** 10626 * Dispatch a key event to the next view on the focus path. This path runs 10627 * from the top of the view tree down to the currently focused view. If this 10628 * view has focus, it will dispatch to itself. Otherwise it will dispatch 10629 * the next node down the focus path. This method also fires any key 10630 * listeners. 10631 * 10632 * @param event The key event to be dispatched. 10633 * @return True if the event was handled, false otherwise. 10634 */ 10635 public boolean dispatchKeyEvent(KeyEvent event) { 10636 if (mInputEventConsistencyVerifier != null) { 10637 mInputEventConsistencyVerifier.onKeyEvent(event, 0); 10638 } 10639 10640 // Give any attached key listener a first crack at the event. 10641 //noinspection SimplifiableIfStatement 10642 ListenerInfo li = mListenerInfo; 10643 if (li != null && li.mOnKeyListener != null && (mViewFlags & ENABLED_MASK) == ENABLED 10644 && li.mOnKeyListener.onKey(this, event.getKeyCode(), event)) { 10645 return true; 10646 } 10647 10648 if (event.dispatch(this, mAttachInfo != null 10649 ? mAttachInfo.mKeyDispatchState : null, this)) { 10650 return true; 10651 } 10652 10653 if (mInputEventConsistencyVerifier != null) { 10654 mInputEventConsistencyVerifier.onUnhandledEvent(event, 0); 10655 } 10656 return false; 10657 } 10658 10659 /** 10660 * Dispatches a key shortcut event. 10661 * 10662 * @param event The key event to be dispatched. 10663 * @return True if the event was handled by the view, false otherwise. 10664 */ 10665 public boolean dispatchKeyShortcutEvent(KeyEvent event) { 10666 return onKeyShortcut(event.getKeyCode(), event); 10667 } 10668 10669 /** 10670 * Pass the touch screen motion event down to the target view, or this 10671 * view if it is the target. 10672 * 10673 * @param event The motion event to be dispatched. 10674 * @return True if the event was handled by the view, false otherwise. 10675 */ 10676 public boolean dispatchTouchEvent(MotionEvent event) { 10677 // If the event should be handled by accessibility focus first. 10678 if (event.isTargetAccessibilityFocus()) { 10679 // We don't have focus or no virtual descendant has it, do not handle the event. 10680 if (!isAccessibilityFocusedViewOrHost()) { 10681 return false; 10682 } 10683 // We have focus and got the event, then use normal event dispatch. 10684 event.setTargetAccessibilityFocus(false); 10685 } 10686 10687 boolean result = false; 10688 10689 if (mInputEventConsistencyVerifier != null) { 10690 mInputEventConsistencyVerifier.onTouchEvent(event, 0); 10691 } 10692 10693 final int actionMasked = event.getActionMasked(); 10694 if (actionMasked == MotionEvent.ACTION_DOWN) { 10695 // Defensive cleanup for new gesture 10696 stopNestedScroll(); 10697 } 10698 10699 if (onFilterTouchEventForSecurity(event)) { 10700 if ((mViewFlags & ENABLED_MASK) == ENABLED && handleScrollBarDragging(event)) { 10701 result = true; 10702 } 10703 //noinspection SimplifiableIfStatement 10704 ListenerInfo li = mListenerInfo; 10705 if (li != null && li.mOnTouchListener != null 10706 && (mViewFlags & ENABLED_MASK) == ENABLED 10707 && li.mOnTouchListener.onTouch(this, event)) { 10708 result = true; 10709 } 10710 10711 if (!result && onTouchEvent(event)) { 10712 result = true; 10713 } 10714 } 10715 10716 if (!result && mInputEventConsistencyVerifier != null) { 10717 mInputEventConsistencyVerifier.onUnhandledEvent(event, 0); 10718 } 10719 10720 // Clean up after nested scrolls if this is the end of a gesture; 10721 // also cancel it if we tried an ACTION_DOWN but we didn't want the rest 10722 // of the gesture. 10723 if (actionMasked == MotionEvent.ACTION_UP || 10724 actionMasked == MotionEvent.ACTION_CANCEL || 10725 (actionMasked == MotionEvent.ACTION_DOWN && !result)) { 10726 stopNestedScroll(); 10727 } 10728 10729 return result; 10730 } 10731 10732 boolean isAccessibilityFocusedViewOrHost() { 10733 return isAccessibilityFocused() || (getViewRootImpl() != null && getViewRootImpl() 10734 .getAccessibilityFocusedHost() == this); 10735 } 10736 10737 /** 10738 * Filter the touch event to apply security policies. 10739 * 10740 * @param event The motion event to be filtered. 10741 * @return True if the event should be dispatched, false if the event should be dropped. 10742 * 10743 * @see #getFilterTouchesWhenObscured 10744 */ 10745 public boolean onFilterTouchEventForSecurity(MotionEvent event) { 10746 //noinspection RedundantIfStatement 10747 if ((mViewFlags & FILTER_TOUCHES_WHEN_OBSCURED) != 0 10748 && (event.getFlags() & MotionEvent.FLAG_WINDOW_IS_OBSCURED) != 0) { 10749 // Window is obscured, drop this touch. 10750 return false; 10751 } 10752 return true; 10753 } 10754 10755 /** 10756 * Pass a trackball motion event down to the focused view. 10757 * 10758 * @param event The motion event to be dispatched. 10759 * @return True if the event was handled by the view, false otherwise. 10760 */ 10761 public boolean dispatchTrackballEvent(MotionEvent event) { 10762 if (mInputEventConsistencyVerifier != null) { 10763 mInputEventConsistencyVerifier.onTrackballEvent(event, 0); 10764 } 10765 10766 return onTrackballEvent(event); 10767 } 10768 10769 /** 10770 * Pass a captured pointer event down to the focused view. 10771 * 10772 * @param event The motion event to be dispatched. 10773 * @return True if the event was handled by the view, false otherwise. 10774 */ 10775 public boolean dispatchCapturedPointerEvent(MotionEvent event) { 10776 if (!hasPointerCapture()) { 10777 return false; 10778 } 10779 //noinspection SimplifiableIfStatement 10780 ListenerInfo li = mListenerInfo; 10781 if (li != null && li.mOnCapturedPointerListener != null 10782 && li.mOnCapturedPointerListener.onCapturedPointer(this, event)) { 10783 return true; 10784 } 10785 return onCapturedPointerEvent(event); 10786 } 10787 10788 /** 10789 * Dispatch a generic motion event. 10790 * <p> 10791 * Generic motion events with source class {@link InputDevice#SOURCE_CLASS_POINTER} 10792 * are delivered to the view under the pointer. All other generic motion events are 10793 * delivered to the focused view. Hover events are handled specially and are delivered 10794 * to {@link #onHoverEvent(MotionEvent)}. 10795 * </p> 10796 * 10797 * @param event The motion event to be dispatched. 10798 * @return True if the event was handled by the view, false otherwise. 10799 */ 10800 public boolean dispatchGenericMotionEvent(MotionEvent event) { 10801 if (mInputEventConsistencyVerifier != null) { 10802 mInputEventConsistencyVerifier.onGenericMotionEvent(event, 0); 10803 } 10804 10805 final int source = event.getSource(); 10806 if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) { 10807 final int action = event.getAction(); 10808 if (action == MotionEvent.ACTION_HOVER_ENTER 10809 || action == MotionEvent.ACTION_HOVER_MOVE 10810 || action == MotionEvent.ACTION_HOVER_EXIT) { 10811 if (dispatchHoverEvent(event)) { 10812 return true; 10813 } 10814 } else if (dispatchGenericPointerEvent(event)) { 10815 return true; 10816 } 10817 } else if (dispatchGenericFocusedEvent(event)) { 10818 return true; 10819 } 10820 10821 if (dispatchGenericMotionEventInternal(event)) { 10822 return true; 10823 } 10824 10825 if (mInputEventConsistencyVerifier != null) { 10826 mInputEventConsistencyVerifier.onUnhandledEvent(event, 0); 10827 } 10828 return false; 10829 } 10830 10831 private boolean dispatchGenericMotionEventInternal(MotionEvent event) { 10832 //noinspection SimplifiableIfStatement 10833 ListenerInfo li = mListenerInfo; 10834 if (li != null && li.mOnGenericMotionListener != null 10835 && (mViewFlags & ENABLED_MASK) == ENABLED 10836 && li.mOnGenericMotionListener.onGenericMotion(this, event)) { 10837 return true; 10838 } 10839 10840 if (onGenericMotionEvent(event)) { 10841 return true; 10842 } 10843 10844 final int actionButton = event.getActionButton(); 10845 switch (event.getActionMasked()) { 10846 case MotionEvent.ACTION_BUTTON_PRESS: 10847 if (isContextClickable() && !mInContextButtonPress && !mHasPerformedLongPress 10848 && (actionButton == MotionEvent.BUTTON_STYLUS_PRIMARY 10849 || actionButton == MotionEvent.BUTTON_SECONDARY)) { 10850 if (performContextClick(event.getX(), event.getY())) { 10851 mInContextButtonPress = true; 10852 setPressed(true, event.getX(), event.getY()); 10853 removeTapCallback(); 10854 removeLongPressCallback(); 10855 return true; 10856 } 10857 } 10858 break; 10859 10860 case MotionEvent.ACTION_BUTTON_RELEASE: 10861 if (mInContextButtonPress && (actionButton == MotionEvent.BUTTON_STYLUS_PRIMARY 10862 || actionButton == MotionEvent.BUTTON_SECONDARY)) { 10863 mInContextButtonPress = false; 10864 mIgnoreNextUpEvent = true; 10865 } 10866 break; 10867 } 10868 10869 if (mInputEventConsistencyVerifier != null) { 10870 mInputEventConsistencyVerifier.onUnhandledEvent(event, 0); 10871 } 10872 return false; 10873 } 10874 10875 /** 10876 * Dispatch a hover event. 10877 * <p> 10878 * Do not call this method directly. 10879 * Call {@link #dispatchGenericMotionEvent(MotionEvent)} instead. 10880 * </p> 10881 * 10882 * @param event The motion event to be dispatched. 10883 * @return True if the event was handled by the view, false otherwise. 10884 */ 10885 protected boolean dispatchHoverEvent(MotionEvent event) { 10886 ListenerInfo li = mListenerInfo; 10887 //noinspection SimplifiableIfStatement 10888 if (li != null && li.mOnHoverListener != null 10889 && (mViewFlags & ENABLED_MASK) == ENABLED 10890 && li.mOnHoverListener.onHover(this, event)) { 10891 return true; 10892 } 10893 10894 return onHoverEvent(event); 10895 } 10896 10897 /** 10898 * Returns true if the view has a child to which it has recently sent 10899 * {@link MotionEvent#ACTION_HOVER_ENTER}. If this view is hovered and 10900 * it does not have a hovered child, then it must be the innermost hovered view. 10901 * @hide 10902 */ 10903 protected boolean hasHoveredChild() { 10904 return false; 10905 } 10906 10907 /** 10908 * Dispatch a generic motion event to the view under the first pointer. 10909 * <p> 10910 * Do not call this method directly. 10911 * Call {@link #dispatchGenericMotionEvent(MotionEvent)} instead. 10912 * </p> 10913 * 10914 * @param event The motion event to be dispatched. 10915 * @return True if the event was handled by the view, false otherwise. 10916 */ 10917 protected boolean dispatchGenericPointerEvent(MotionEvent event) { 10918 return false; 10919 } 10920 10921 /** 10922 * Dispatch a generic motion event to the currently focused view. 10923 * <p> 10924 * Do not call this method directly. 10925 * Call {@link #dispatchGenericMotionEvent(MotionEvent)} instead. 10926 * </p> 10927 * 10928 * @param event The motion event to be dispatched. 10929 * @return True if the event was handled by the view, false otherwise. 10930 */ 10931 protected boolean dispatchGenericFocusedEvent(MotionEvent event) { 10932 return false; 10933 } 10934 10935 /** 10936 * Dispatch a pointer event. 10937 * <p> 10938 * Dispatches touch related pointer events to {@link #onTouchEvent(MotionEvent)} and all 10939 * other events to {@link #onGenericMotionEvent(MotionEvent)}. This separation of concerns 10940 * reinforces the invariant that {@link #onTouchEvent(MotionEvent)} is really about touches 10941 * and should not be expected to handle other pointing device features. 10942 * </p> 10943 * 10944 * @param event The motion event to be dispatched. 10945 * @return True if the event was handled by the view, false otherwise. 10946 * @hide 10947 */ 10948 public final boolean dispatchPointerEvent(MotionEvent event) { 10949 if (event.isTouchEvent()) { 10950 return dispatchTouchEvent(event); 10951 } else { 10952 return dispatchGenericMotionEvent(event); 10953 } 10954 } 10955 10956 /** 10957 * Called when the window containing this view gains or loses window focus. 10958 * ViewGroups should override to route to their children. 10959 * 10960 * @param hasFocus True if the window containing this view now has focus, 10961 * false otherwise. 10962 */ 10963 public void dispatchWindowFocusChanged(boolean hasFocus) { 10964 onWindowFocusChanged(hasFocus); 10965 } 10966 10967 /** 10968 * Called when the window containing this view gains or loses focus. Note 10969 * that this is separate from view focus: to receive key events, both 10970 * your view and its window must have focus. If a window is displayed 10971 * on top of yours that takes input focus, then your own window will lose 10972 * focus but the view focus will remain unchanged. 10973 * 10974 * @param hasWindowFocus True if the window containing this view now has 10975 * focus, false otherwise. 10976 */ 10977 public void onWindowFocusChanged(boolean hasWindowFocus) { 10978 InputMethodManager imm = InputMethodManager.peekInstance(); 10979 if (!hasWindowFocus) { 10980 if (isPressed()) { 10981 setPressed(false); 10982 } 10983 mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN; 10984 if (imm != null && (mPrivateFlags & PFLAG_FOCUSED) != 0) { 10985 imm.focusOut(this); 10986 } 10987 removeLongPressCallback(); 10988 removeTapCallback(); 10989 onFocusLost(); 10990 } else if (imm != null && (mPrivateFlags & PFLAG_FOCUSED) != 0) { 10991 imm.focusIn(this); 10992 } 10993 refreshDrawableState(); 10994 } 10995 10996 /** 10997 * Returns true if this view is in a window that currently has window focus. 10998 * Note that this is not the same as the view itself having focus. 10999 * 11000 * @return True if this view is in a window that currently has window focus. 11001 */ 11002 public boolean hasWindowFocus() { 11003 return mAttachInfo != null && mAttachInfo.mHasWindowFocus; 11004 } 11005 11006 /** 11007 * Dispatch a view visibility change down the view hierarchy. 11008 * ViewGroups should override to route to their children. 11009 * @param changedView The view whose visibility changed. Could be 'this' or 11010 * an ancestor view. 11011 * @param visibility The new visibility of changedView: {@link #VISIBLE}, 11012 * {@link #INVISIBLE} or {@link #GONE}. 11013 */ 11014 protected void dispatchVisibilityChanged(@NonNull View changedView, 11015 @Visibility int visibility) { 11016 onVisibilityChanged(changedView, visibility); 11017 } 11018 11019 /** 11020 * Called when the visibility of the view or an ancestor of the view has 11021 * changed. 11022 * 11023 * @param changedView The view whose visibility changed. May be 11024 * {@code this} or an ancestor view. 11025 * @param visibility The new visibility, one of {@link #VISIBLE}, 11026 * {@link #INVISIBLE} or {@link #GONE}. 11027 */ 11028 protected void onVisibilityChanged(@NonNull View changedView, @Visibility int visibility) { 11029 } 11030 11031 /** 11032 * Dispatch a hint about whether this view is displayed. For instance, when 11033 * a View moves out of the screen, it might receives a display hint indicating 11034 * the view is not displayed. Applications should not <em>rely</em> on this hint 11035 * as there is no guarantee that they will receive one. 11036 * 11037 * @param hint A hint about whether or not this view is displayed: 11038 * {@link #VISIBLE} or {@link #INVISIBLE}. 11039 */ 11040 public void dispatchDisplayHint(@Visibility int hint) { 11041 onDisplayHint(hint); 11042 } 11043 11044 /** 11045 * Gives this view a hint about whether is displayed or not. For instance, when 11046 * a View moves out of the screen, it might receives a display hint indicating 11047 * the view is not displayed. Applications should not <em>rely</em> on this hint 11048 * as there is no guarantee that they will receive one. 11049 * 11050 * @param hint A hint about whether or not this view is displayed: 11051 * {@link #VISIBLE} or {@link #INVISIBLE}. 11052 */ 11053 protected void onDisplayHint(@Visibility int hint) { 11054 } 11055 11056 /** 11057 * Dispatch a window visibility change down the view hierarchy. 11058 * ViewGroups should override to route to their children. 11059 * 11060 * @param visibility The new visibility of the window. 11061 * 11062 * @see #onWindowVisibilityChanged(int) 11063 */ 11064 public void dispatchWindowVisibilityChanged(@Visibility int visibility) { 11065 onWindowVisibilityChanged(visibility); 11066 } 11067 11068 /** 11069 * Called when the window containing has change its visibility 11070 * (between {@link #GONE}, {@link #INVISIBLE}, and {@link #VISIBLE}). Note 11071 * that this tells you whether or not your window is being made visible 11072 * to the window manager; this does <em>not</em> tell you whether or not 11073 * your window is obscured by other windows on the screen, even if it 11074 * is itself visible. 11075 * 11076 * @param visibility The new visibility of the window. 11077 */ 11078 protected void onWindowVisibilityChanged(@Visibility int visibility) { 11079 if (visibility == VISIBLE) { 11080 initialAwakenScrollBars(); 11081 } 11082 } 11083 11084 /** 11085 * Internal dispatching method for {@link #onVisibilityAggregated}. Overridden by 11086 * ViewGroup. Intended to only be called when {@link #isAttachedToWindow()}, 11087 * {@link #getWindowVisibility()} is {@link #VISIBLE} and this view's parent {@link #isShown()}. 11088 * 11089 * @param isVisible true if this view's visibility to the user is uninterrupted by its 11090 * ancestors or by window visibility 11091 * @return true if this view is visible to the user, not counting clipping or overlapping 11092 */ 11093 boolean dispatchVisibilityAggregated(boolean isVisible) { 11094 final boolean thisVisible = getVisibility() == VISIBLE; 11095 // If we're not visible but something is telling us we are, ignore it. 11096 if (thisVisible || !isVisible) { 11097 onVisibilityAggregated(isVisible); 11098 } 11099 return thisVisible && isVisible; 11100 } 11101 11102 /** 11103 * Called when the user-visibility of this View is potentially affected by a change 11104 * to this view itself, an ancestor view or the window this view is attached to. 11105 * 11106 * @param isVisible true if this view and all of its ancestors are {@link #VISIBLE} 11107 * and this view's window is also visible 11108 */ 11109 @CallSuper 11110 public void onVisibilityAggregated(boolean isVisible) { 11111 if (isVisible && mAttachInfo != null) { 11112 initialAwakenScrollBars(); 11113 } 11114 11115 final Drawable dr = mBackground; 11116 if (dr != null && isVisible != dr.isVisible()) { 11117 dr.setVisible(isVisible, false); 11118 } 11119 final Drawable fg = mForegroundInfo != null ? mForegroundInfo.mDrawable : null; 11120 if (fg != null && isVisible != fg.isVisible()) { 11121 fg.setVisible(isVisible, false); 11122 } 11123 } 11124 11125 /** 11126 * Returns the current visibility of the window this view is attached to 11127 * (either {@link #GONE}, {@link #INVISIBLE}, or {@link #VISIBLE}). 11128 * 11129 * @return Returns the current visibility of the view's window. 11130 */ 11131 @Visibility 11132 public int getWindowVisibility() { 11133 return mAttachInfo != null ? mAttachInfo.mWindowVisibility : GONE; 11134 } 11135 11136 /** 11137 * Retrieve the overall visible display size in which the window this view is 11138 * attached to has been positioned in. This takes into account screen 11139 * decorations above the window, for both cases where the window itself 11140 * is being position inside of them or the window is being placed under 11141 * then and covered insets are used for the window to position its content 11142 * inside. In effect, this tells you the available area where content can 11143 * be placed and remain visible to users. 11144 * 11145 * <p>This function requires an IPC back to the window manager to retrieve 11146 * the requested information, so should not be used in performance critical 11147 * code like drawing. 11148 * 11149 * @param outRect Filled in with the visible display frame. If the view 11150 * is not attached to a window, this is simply the raw display size. 11151 */ 11152 public void getWindowVisibleDisplayFrame(Rect outRect) { 11153 if (mAttachInfo != null) { 11154 try { 11155 mAttachInfo.mSession.getDisplayFrame(mAttachInfo.mWindow, outRect); 11156 } catch (RemoteException e) { 11157 return; 11158 } 11159 // XXX This is really broken, and probably all needs to be done 11160 // in the window manager, and we need to know more about whether 11161 // we want the area behind or in front of the IME. 11162 final Rect insets = mAttachInfo.mVisibleInsets; 11163 outRect.left += insets.left; 11164 outRect.top += insets.top; 11165 outRect.right -= insets.right; 11166 outRect.bottom -= insets.bottom; 11167 return; 11168 } 11169 // The view is not attached to a display so we don't have a context. 11170 // Make a best guess about the display size. 11171 Display d = DisplayManagerGlobal.getInstance().getRealDisplay(Display.DEFAULT_DISPLAY); 11172 d.getRectSize(outRect); 11173 } 11174 11175 /** 11176 * Like {@link #getWindowVisibleDisplayFrame}, but returns the "full" display frame this window 11177 * is currently in without any insets. 11178 * 11179 * @hide 11180 */ 11181 public void getWindowDisplayFrame(Rect outRect) { 11182 if (mAttachInfo != null) { 11183 try { 11184 mAttachInfo.mSession.getDisplayFrame(mAttachInfo.mWindow, outRect); 11185 } catch (RemoteException e) { 11186 return; 11187 } 11188 return; 11189 } 11190 // The view is not attached to a display so we don't have a context. 11191 // Make a best guess about the display size. 11192 Display d = DisplayManagerGlobal.getInstance().getRealDisplay(Display.DEFAULT_DISPLAY); 11193 d.getRectSize(outRect); 11194 } 11195 11196 /** 11197 * Dispatch a notification about a resource configuration change down 11198 * the view hierarchy. 11199 * ViewGroups should override to route to their children. 11200 * 11201 * @param newConfig The new resource configuration. 11202 * 11203 * @see #onConfigurationChanged(android.content.res.Configuration) 11204 */ 11205 public void dispatchConfigurationChanged(Configuration newConfig) { 11206 onConfigurationChanged(newConfig); 11207 } 11208 11209 /** 11210 * Called when the current configuration of the resources being used 11211 * by the application have changed. You can use this to decide when 11212 * to reload resources that can changed based on orientation and other 11213 * configuration characteristics. You only need to use this if you are 11214 * not relying on the normal {@link android.app.Activity} mechanism of 11215 * recreating the activity instance upon a configuration change. 11216 * 11217 * @param newConfig The new resource configuration. 11218 */ 11219 protected void onConfigurationChanged(Configuration newConfig) { 11220 } 11221 11222 /** 11223 * Private function to aggregate all per-view attributes in to the view 11224 * root. 11225 */ 11226 void dispatchCollectViewAttributes(AttachInfo attachInfo, int visibility) { 11227 performCollectViewAttributes(attachInfo, visibility); 11228 } 11229 11230 void performCollectViewAttributes(AttachInfo attachInfo, int visibility) { 11231 if ((visibility & VISIBILITY_MASK) == VISIBLE) { 11232 if ((mViewFlags & KEEP_SCREEN_ON) == KEEP_SCREEN_ON) { 11233 attachInfo.mKeepScreenOn = true; 11234 } 11235 attachInfo.mSystemUiVisibility |= mSystemUiVisibility; 11236 ListenerInfo li = mListenerInfo; 11237 if (li != null && li.mOnSystemUiVisibilityChangeListener != null) { 11238 attachInfo.mHasSystemUiListeners = true; 11239 } 11240 } 11241 } 11242 11243 void needGlobalAttributesUpdate(boolean force) { 11244 final AttachInfo ai = mAttachInfo; 11245 if (ai != null && !ai.mRecomputeGlobalAttributes) { 11246 if (force || ai.mKeepScreenOn || (ai.mSystemUiVisibility != 0) 11247 || ai.mHasSystemUiListeners) { 11248 ai.mRecomputeGlobalAttributes = true; 11249 } 11250 } 11251 } 11252 11253 /** 11254 * Returns whether the device is currently in touch mode. Touch mode is entered 11255 * once the user begins interacting with the device by touch, and affects various 11256 * things like whether focus is always visible to the user. 11257 * 11258 * @return Whether the device is in touch mode. 11259 */ 11260 @ViewDebug.ExportedProperty 11261 public boolean isInTouchMode() { 11262 if (mAttachInfo != null) { 11263 return mAttachInfo.mInTouchMode; 11264 } else { 11265 return ViewRootImpl.isInTouchMode(); 11266 } 11267 } 11268 11269 /** 11270 * Returns the context the view is running in, through which it can 11271 * access the current theme, resources, etc. 11272 * 11273 * @return The view's Context. 11274 */ 11275 @ViewDebug.CapturedViewProperty 11276 public final Context getContext() { 11277 return mContext; 11278 } 11279 11280 /** 11281 * Handle a key event before it is processed by any input method 11282 * associated with the view hierarchy. This can be used to intercept 11283 * key events in special situations before the IME consumes them; a 11284 * typical example would be handling the BACK key to update the application's 11285 * UI instead of allowing the IME to see it and close itself. 11286 * 11287 * @param keyCode The value in event.getKeyCode(). 11288 * @param event Description of the key event. 11289 * @return If you handled the event, return true. If you want to allow the 11290 * event to be handled by the next receiver, return false. 11291 */ 11292 public boolean onKeyPreIme(int keyCode, KeyEvent event) { 11293 return false; 11294 } 11295 11296 /** 11297 * Default implementation of {@link KeyEvent.Callback#onKeyDown(int, KeyEvent) 11298 * KeyEvent.Callback.onKeyDown()}: perform press of the view 11299 * when {@link KeyEvent#KEYCODE_DPAD_CENTER} or {@link KeyEvent#KEYCODE_ENTER} 11300 * is released, if the view is enabled and clickable. 11301 * <p> 11302 * Key presses in software keyboards will generally NOT trigger this 11303 * listener, although some may elect to do so in some situations. Do not 11304 * rely on this to catch software key presses. 11305 * 11306 * @param keyCode a key code that represents the button pressed, from 11307 * {@link android.view.KeyEvent} 11308 * @param event the KeyEvent object that defines the button action 11309 */ 11310 public boolean onKeyDown(int keyCode, KeyEvent event) { 11311 if (KeyEvent.isConfirmKey(keyCode)) { 11312 if ((mViewFlags & ENABLED_MASK) == DISABLED) { 11313 return true; 11314 } 11315 11316 if (event.getRepeatCount() == 0) { 11317 // Long clickable items don't necessarily have to be clickable. 11318 final boolean clickable = (mViewFlags & CLICKABLE) == CLICKABLE 11319 || (mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE; 11320 if (clickable || (mViewFlags & TOOLTIP) == TOOLTIP) { 11321 // For the purposes of menu anchoring and drawable hotspots, 11322 // key events are considered to be at the center of the view. 11323 final float x = getWidth() / 2f; 11324 final float y = getHeight() / 2f; 11325 if (clickable) { 11326 setPressed(true, x, y); 11327 } 11328 checkForLongClick(0, x, y); 11329 return true; 11330 } 11331 } 11332 } 11333 11334 return false; 11335 } 11336 11337 /** 11338 * Default implementation of {@link KeyEvent.Callback#onKeyLongPress(int, KeyEvent) 11339 * KeyEvent.Callback.onKeyLongPress()}: always returns false (doesn't handle 11340 * the event). 11341 * <p>Key presses in software keyboards will generally NOT trigger this listener, 11342 * although some may elect to do so in some situations. Do not rely on this to 11343 * catch software key presses. 11344 */ 11345 public boolean onKeyLongPress(int keyCode, KeyEvent event) { 11346 return false; 11347 } 11348 11349 /** 11350 * Default implementation of {@link KeyEvent.Callback#onKeyUp(int, KeyEvent) 11351 * KeyEvent.Callback.onKeyUp()}: perform clicking of the view 11352 * when {@link KeyEvent#KEYCODE_DPAD_CENTER}, {@link KeyEvent#KEYCODE_ENTER} 11353 * or {@link KeyEvent#KEYCODE_SPACE} is released. 11354 * <p>Key presses in software keyboards will generally NOT trigger this listener, 11355 * although some may elect to do so in some situations. Do not rely on this to 11356 * catch software key presses. 11357 * 11358 * @param keyCode A key code that represents the button pressed, from 11359 * {@link android.view.KeyEvent}. 11360 * @param event The KeyEvent object that defines the button action. 11361 */ 11362 public boolean onKeyUp(int keyCode, KeyEvent event) { 11363 if (KeyEvent.isConfirmKey(keyCode)) { 11364 if ((mViewFlags & ENABLED_MASK) == DISABLED) { 11365 return true; 11366 } 11367 if ((mViewFlags & CLICKABLE) == CLICKABLE && isPressed()) { 11368 setPressed(false); 11369 11370 if (!mHasPerformedLongPress) { 11371 // This is a tap, so remove the longpress check 11372 removeLongPressCallback(); 11373 return performClick(); 11374 } 11375 } 11376 } 11377 return false; 11378 } 11379 11380 /** 11381 * Default implementation of {@link KeyEvent.Callback#onKeyMultiple(int, int, KeyEvent) 11382 * KeyEvent.Callback.onKeyMultiple()}: always returns false (doesn't handle 11383 * the event). 11384 * <p>Key presses in software keyboards will generally NOT trigger this listener, 11385 * although some may elect to do so in some situations. Do not rely on this to 11386 * catch software key presses. 11387 * 11388 * @param keyCode A key code that represents the button pressed, from 11389 * {@link android.view.KeyEvent}. 11390 * @param repeatCount The number of times the action was made. 11391 * @param event The KeyEvent object that defines the button action. 11392 */ 11393 public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event) { 11394 return false; 11395 } 11396 11397 /** 11398 * Called on the focused view when a key shortcut event is not handled. 11399 * Override this method to implement local key shortcuts for the View. 11400 * Key shortcuts can also be implemented by setting the 11401 * {@link MenuItem#setShortcut(char, char) shortcut} property of menu items. 11402 * 11403 * @param keyCode The value in event.getKeyCode(). 11404 * @param event Description of the key event. 11405 * @return If you handled the event, return true. If you want to allow the 11406 * event to be handled by the next receiver, return false. 11407 */ 11408 public boolean onKeyShortcut(int keyCode, KeyEvent event) { 11409 return false; 11410 } 11411 11412 /** 11413 * Check whether the called view is a text editor, in which case it 11414 * would make sense to automatically display a soft input window for 11415 * it. Subclasses should override this if they implement 11416 * {@link #onCreateInputConnection(EditorInfo)} to return true if 11417 * a call on that method would return a non-null InputConnection, and 11418 * they are really a first-class editor that the user would normally 11419 * start typing on when the go into a window containing your view. 11420 * 11421 * <p>The default implementation always returns false. This does 11422 * <em>not</em> mean that its {@link #onCreateInputConnection(EditorInfo)} 11423 * will not be called or the user can not otherwise perform edits on your 11424 * view; it is just a hint to the system that this is not the primary 11425 * purpose of this view. 11426 * 11427 * @return Returns true if this view is a text editor, else false. 11428 */ 11429 public boolean onCheckIsTextEditor() { 11430 return false; 11431 } 11432 11433 /** 11434 * Create a new InputConnection for an InputMethod to interact 11435 * with the view. The default implementation returns null, since it doesn't 11436 * support input methods. You can override this to implement such support. 11437 * This is only needed for views that take focus and text input. 11438 * 11439 * <p>When implementing this, you probably also want to implement 11440 * {@link #onCheckIsTextEditor()} to indicate you will return a 11441 * non-null InputConnection.</p> 11442 * 11443 * <p>Also, take good care to fill in the {@link android.view.inputmethod.EditorInfo} 11444 * object correctly and in its entirety, so that the connected IME can rely 11445 * on its values. For example, {@link android.view.inputmethod.EditorInfo#initialSelStart} 11446 * and {@link android.view.inputmethod.EditorInfo#initialSelEnd} members 11447 * must be filled in with the correct cursor position for IMEs to work correctly 11448 * with your application.</p> 11449 * 11450 * @param outAttrs Fill in with attribute information about the connection. 11451 */ 11452 public InputConnection onCreateInputConnection(EditorInfo outAttrs) { 11453 return null; 11454 } 11455 11456 /** 11457 * Called by the {@link android.view.inputmethod.InputMethodManager} 11458 * when a view who is not the current 11459 * input connection target is trying to make a call on the manager. The 11460 * default implementation returns false; you can override this to return 11461 * true for certain views if you are performing InputConnection proxying 11462 * to them. 11463 * @param view The View that is making the InputMethodManager call. 11464 * @return Return true to allow the call, false to reject. 11465 */ 11466 public boolean checkInputConnectionProxy(View view) { 11467 return false; 11468 } 11469 11470 /** 11471 * Show the context menu for this view. It is not safe to hold on to the 11472 * menu after returning from this method. 11473 * 11474 * You should normally not overload this method. Overload 11475 * {@link #onCreateContextMenu(ContextMenu)} or define an 11476 * {@link OnCreateContextMenuListener} to add items to the context menu. 11477 * 11478 * @param menu The context menu to populate 11479 */ 11480 public void createContextMenu(ContextMenu menu) { 11481 ContextMenuInfo menuInfo = getContextMenuInfo(); 11482 11483 // Sets the current menu info so all items added to menu will have 11484 // my extra info set. 11485 ((MenuBuilder)menu).setCurrentMenuInfo(menuInfo); 11486 11487 onCreateContextMenu(menu); 11488 ListenerInfo li = mListenerInfo; 11489 if (li != null && li.mOnCreateContextMenuListener != null) { 11490 li.mOnCreateContextMenuListener.onCreateContextMenu(menu, this, menuInfo); 11491 } 11492 11493 // Clear the extra information so subsequent items that aren't mine don't 11494 // have my extra info. 11495 ((MenuBuilder)menu).setCurrentMenuInfo(null); 11496 11497 if (mParent != null) { 11498 mParent.createContextMenu(menu); 11499 } 11500 } 11501 11502 /** 11503 * Views should implement this if they have extra information to associate 11504 * with the context menu. The return result is supplied as a parameter to 11505 * the {@link OnCreateContextMenuListener#onCreateContextMenu(ContextMenu, View, ContextMenuInfo)} 11506 * callback. 11507 * 11508 * @return Extra information about the item for which the context menu 11509 * should be shown. This information will vary across different 11510 * subclasses of View. 11511 */ 11512 protected ContextMenuInfo getContextMenuInfo() { 11513 return null; 11514 } 11515 11516 /** 11517 * Views should implement this if the view itself is going to add items to 11518 * the context menu. 11519 * 11520 * @param menu the context menu to populate 11521 */ 11522 protected void onCreateContextMenu(ContextMenu menu) { 11523 } 11524 11525 /** 11526 * Implement this method to handle trackball motion events. The 11527 * <em>relative</em> movement of the trackball since the last event 11528 * can be retrieve with {@link MotionEvent#getX MotionEvent.getX()} and 11529 * {@link MotionEvent#getY MotionEvent.getY()}. These are normalized so 11530 * that a movement of 1 corresponds to the user pressing one DPAD key (so 11531 * they will often be fractional values, representing the more fine-grained 11532 * movement information available from a trackball). 11533 * 11534 * @param event The motion event. 11535 * @return True if the event was handled, false otherwise. 11536 */ 11537 public boolean onTrackballEvent(MotionEvent event) { 11538 return false; 11539 } 11540 11541 /** 11542 * Implement this method to handle generic motion events. 11543 * <p> 11544 * Generic motion events describe joystick movements, mouse hovers, track pad 11545 * touches, scroll wheel movements and other input events. The 11546 * {@link MotionEvent#getSource() source} of the motion event specifies 11547 * the class of input that was received. Implementations of this method 11548 * must examine the bits in the source before processing the event. 11549 * The following code example shows how this is done. 11550 * </p><p> 11551 * Generic motion events with source class {@link InputDevice#SOURCE_CLASS_POINTER} 11552 * are delivered to the view under the pointer. All other generic motion events are 11553 * delivered to the focused view. 11554 * </p> 11555 * <pre> public boolean onGenericMotionEvent(MotionEvent event) { 11556 * if (event.isFromSource(InputDevice.SOURCE_CLASS_JOYSTICK)) { 11557 * if (event.getAction() == MotionEvent.ACTION_MOVE) { 11558 * // process the joystick movement... 11559 * return true; 11560 * } 11561 * } 11562 * if (event.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) { 11563 * switch (event.getAction()) { 11564 * case MotionEvent.ACTION_HOVER_MOVE: 11565 * // process the mouse hover movement... 11566 * return true; 11567 * case MotionEvent.ACTION_SCROLL: 11568 * // process the scroll wheel movement... 11569 * return true; 11570 * } 11571 * } 11572 * return super.onGenericMotionEvent(event); 11573 * }</pre> 11574 * 11575 * @param event The generic motion event being processed. 11576 * @return True if the event was handled, false otherwise. 11577 */ 11578 public boolean onGenericMotionEvent(MotionEvent event) { 11579 return false; 11580 } 11581 11582 /** 11583 * Implement this method to handle hover events. 11584 * <p> 11585 * This method is called whenever a pointer is hovering into, over, or out of the 11586 * bounds of a view and the view is not currently being touched. 11587 * Hover events are represented as pointer events with action 11588 * {@link MotionEvent#ACTION_HOVER_ENTER}, {@link MotionEvent#ACTION_HOVER_MOVE}, 11589 * or {@link MotionEvent#ACTION_HOVER_EXIT}. 11590 * </p> 11591 * <ul> 11592 * <li>The view receives a hover event with action {@link MotionEvent#ACTION_HOVER_ENTER} 11593 * when the pointer enters the bounds of the view.</li> 11594 * <li>The view receives a hover event with action {@link MotionEvent#ACTION_HOVER_MOVE} 11595 * when the pointer has already entered the bounds of the view and has moved.</li> 11596 * <li>The view receives a hover event with action {@link MotionEvent#ACTION_HOVER_EXIT} 11597 * when the pointer has exited the bounds of the view or when the pointer is 11598 * about to go down due to a button click, tap, or similar user action that 11599 * causes the view to be touched.</li> 11600 * </ul> 11601 * <p> 11602 * The view should implement this method to return true to indicate that it is 11603 * handling the hover event, such as by changing its drawable state. 11604 * </p><p> 11605 * The default implementation calls {@link #setHovered} to update the hovered state 11606 * of the view when a hover enter or hover exit event is received, if the view 11607 * is enabled and is clickable. The default implementation also sends hover 11608 * accessibility events. 11609 * </p> 11610 * 11611 * @param event The motion event that describes the hover. 11612 * @return True if the view handled the hover event. 11613 * 11614 * @see #isHovered 11615 * @see #setHovered 11616 * @see #onHoverChanged 11617 */ 11618 public boolean onHoverEvent(MotionEvent event) { 11619 // The root view may receive hover (or touch) events that are outside the bounds of 11620 // the window. This code ensures that we only send accessibility events for 11621 // hovers that are actually within the bounds of the root view. 11622 final int action = event.getActionMasked(); 11623 if (!mSendingHoverAccessibilityEvents) { 11624 if ((action == MotionEvent.ACTION_HOVER_ENTER 11625 || action == MotionEvent.ACTION_HOVER_MOVE) 11626 && !hasHoveredChild() 11627 && pointInView(event.getX(), event.getY())) { 11628 sendAccessibilityHoverEvent(AccessibilityEvent.TYPE_VIEW_HOVER_ENTER); 11629 mSendingHoverAccessibilityEvents = true; 11630 } 11631 } else { 11632 if (action == MotionEvent.ACTION_HOVER_EXIT 11633 || (action == MotionEvent.ACTION_MOVE 11634 && !pointInView(event.getX(), event.getY()))) { 11635 mSendingHoverAccessibilityEvents = false; 11636 sendAccessibilityHoverEvent(AccessibilityEvent.TYPE_VIEW_HOVER_EXIT); 11637 } 11638 } 11639 11640 if ((action == MotionEvent.ACTION_HOVER_ENTER || action == MotionEvent.ACTION_HOVER_MOVE) 11641 && event.isFromSource(InputDevice.SOURCE_MOUSE) 11642 && isOnScrollbar(event.getX(), event.getY())) { 11643 awakenScrollBars(); 11644 } 11645 if (isHoverable()) { 11646 switch (action) { 11647 case MotionEvent.ACTION_HOVER_ENTER: 11648 setHovered(true); 11649 break; 11650 case MotionEvent.ACTION_HOVER_EXIT: 11651 setHovered(false); 11652 break; 11653 } 11654 11655 // Dispatch the event to onGenericMotionEvent before returning true. 11656 // This is to provide compatibility with existing applications that 11657 // handled HOVER_MOVE events in onGenericMotionEvent and that would 11658 // break because of the new default handling for hoverable views 11659 // in onHoverEvent. 11660 // Note that onGenericMotionEvent will be called by default when 11661 // onHoverEvent returns false (refer to dispatchGenericMotionEvent). 11662 dispatchGenericMotionEventInternal(event); 11663 // The event was already handled by calling setHovered(), so always 11664 // return true. 11665 return true; 11666 } 11667 11668 return false; 11669 } 11670 11671 /** 11672 * Returns true if the view should handle {@link #onHoverEvent} 11673 * by calling {@link #setHovered} to change its hovered state. 11674 * 11675 * @return True if the view is hoverable. 11676 */ 11677 private boolean isHoverable() { 11678 final int viewFlags = mViewFlags; 11679 if ((viewFlags & ENABLED_MASK) == DISABLED) { 11680 return false; 11681 } 11682 11683 return (viewFlags & CLICKABLE) == CLICKABLE 11684 || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE 11685 || (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE; 11686 } 11687 11688 /** 11689 * Returns true if the view is currently hovered. 11690 * 11691 * @return True if the view is currently hovered. 11692 * 11693 * @see #setHovered 11694 * @see #onHoverChanged 11695 */ 11696 @ViewDebug.ExportedProperty 11697 public boolean isHovered() { 11698 return (mPrivateFlags & PFLAG_HOVERED) != 0; 11699 } 11700 11701 /** 11702 * Sets whether the view is currently hovered. 11703 * <p> 11704 * Calling this method also changes the drawable state of the view. This 11705 * enables the view to react to hover by using different drawable resources 11706 * to change its appearance. 11707 * </p><p> 11708 * The {@link #onHoverChanged} method is called when the hovered state changes. 11709 * </p> 11710 * 11711 * @param hovered True if the view is hovered. 11712 * 11713 * @see #isHovered 11714 * @see #onHoverChanged 11715 */ 11716 public void setHovered(boolean hovered) { 11717 if (hovered) { 11718 if ((mPrivateFlags & PFLAG_HOVERED) == 0) { 11719 mPrivateFlags |= PFLAG_HOVERED; 11720 refreshDrawableState(); 11721 onHoverChanged(true); 11722 } 11723 } else { 11724 if ((mPrivateFlags & PFLAG_HOVERED) != 0) { 11725 mPrivateFlags &= ~PFLAG_HOVERED; 11726 refreshDrawableState(); 11727 onHoverChanged(false); 11728 } 11729 } 11730 } 11731 11732 /** 11733 * Implement this method to handle hover state changes. 11734 * <p> 11735 * This method is called whenever the hover state changes as a result of a 11736 * call to {@link #setHovered}. 11737 * </p> 11738 * 11739 * @param hovered The current hover state, as returned by {@link #isHovered}. 11740 * 11741 * @see #isHovered 11742 * @see #setHovered 11743 */ 11744 public void onHoverChanged(boolean hovered) { 11745 } 11746 11747 /** 11748 * Handles scroll bar dragging by mouse input. 11749 * 11750 * @hide 11751 * @param event The motion event. 11752 * 11753 * @return true if the event was handled as a scroll bar dragging, false otherwise. 11754 */ 11755 protected boolean handleScrollBarDragging(MotionEvent event) { 11756 if (mScrollCache == null) { 11757 return false; 11758 } 11759 final float x = event.getX(); 11760 final float y = event.getY(); 11761 final int action = event.getAction(); 11762 if ((mScrollCache.mScrollBarDraggingState == ScrollabilityCache.NOT_DRAGGING 11763 && action != MotionEvent.ACTION_DOWN) 11764 || !event.isFromSource(InputDevice.SOURCE_MOUSE) 11765 || !event.isButtonPressed(MotionEvent.BUTTON_PRIMARY)) { 11766 mScrollCache.mScrollBarDraggingState = ScrollabilityCache.NOT_DRAGGING; 11767 return false; 11768 } 11769 11770 switch (action) { 11771 case MotionEvent.ACTION_MOVE: 11772 if (mScrollCache.mScrollBarDraggingState == ScrollabilityCache.NOT_DRAGGING) { 11773 return false; 11774 } 11775 if (mScrollCache.mScrollBarDraggingState 11776 == ScrollabilityCache.DRAGGING_VERTICAL_SCROLL_BAR) { 11777 final Rect bounds = mScrollCache.mScrollBarBounds; 11778 getVerticalScrollBarBounds(bounds, null); 11779 final int range = computeVerticalScrollRange(); 11780 final int offset = computeVerticalScrollOffset(); 11781 final int extent = computeVerticalScrollExtent(); 11782 11783 final int thumbLength = ScrollBarUtils.getThumbLength( 11784 bounds.height(), bounds.width(), extent, range); 11785 final int thumbOffset = ScrollBarUtils.getThumbOffset( 11786 bounds.height(), thumbLength, extent, range, offset); 11787 11788 final float diff = y - mScrollCache.mScrollBarDraggingPos; 11789 final float maxThumbOffset = bounds.height() - thumbLength; 11790 final float newThumbOffset = 11791 Math.min(Math.max(thumbOffset + diff, 0.0f), maxThumbOffset); 11792 final int height = getHeight(); 11793 if (Math.round(newThumbOffset) != thumbOffset && maxThumbOffset > 0 11794 && height > 0 && extent > 0) { 11795 final int newY = Math.round((range - extent) 11796 / ((float)extent / height) * (newThumbOffset / maxThumbOffset)); 11797 if (newY != getScrollY()) { 11798 mScrollCache.mScrollBarDraggingPos = y; 11799 setScrollY(newY); 11800 } 11801 } 11802 return true; 11803 } 11804 if (mScrollCache.mScrollBarDraggingState 11805 == ScrollabilityCache.DRAGGING_HORIZONTAL_SCROLL_BAR) { 11806 final Rect bounds = mScrollCache.mScrollBarBounds; 11807 getHorizontalScrollBarBounds(bounds, null); 11808 final int range = computeHorizontalScrollRange(); 11809 final int offset = computeHorizontalScrollOffset(); 11810 final int extent = computeHorizontalScrollExtent(); 11811 11812 final int thumbLength = ScrollBarUtils.getThumbLength( 11813 bounds.width(), bounds.height(), extent, range); 11814 final int thumbOffset = ScrollBarUtils.getThumbOffset( 11815 bounds.width(), thumbLength, extent, range, offset); 11816 11817 final float diff = x - mScrollCache.mScrollBarDraggingPos; 11818 final float maxThumbOffset = bounds.width() - thumbLength; 11819 final float newThumbOffset = 11820 Math.min(Math.max(thumbOffset + diff, 0.0f), maxThumbOffset); 11821 final int width = getWidth(); 11822 if (Math.round(newThumbOffset) != thumbOffset && maxThumbOffset > 0 11823 && width > 0 && extent > 0) { 11824 final int newX = Math.round((range - extent) 11825 / ((float)extent / width) * (newThumbOffset / maxThumbOffset)); 11826 if (newX != getScrollX()) { 11827 mScrollCache.mScrollBarDraggingPos = x; 11828 setScrollX(newX); 11829 } 11830 } 11831 return true; 11832 } 11833 case MotionEvent.ACTION_DOWN: 11834 if (mScrollCache.state == ScrollabilityCache.OFF) { 11835 return false; 11836 } 11837 if (isOnVerticalScrollbarThumb(x, y)) { 11838 mScrollCache.mScrollBarDraggingState = 11839 ScrollabilityCache.DRAGGING_VERTICAL_SCROLL_BAR; 11840 mScrollCache.mScrollBarDraggingPos = y; 11841 return true; 11842 } 11843 if (isOnHorizontalScrollbarThumb(x, y)) { 11844 mScrollCache.mScrollBarDraggingState = 11845 ScrollabilityCache.DRAGGING_HORIZONTAL_SCROLL_BAR; 11846 mScrollCache.mScrollBarDraggingPos = x; 11847 return true; 11848 } 11849 } 11850 mScrollCache.mScrollBarDraggingState = ScrollabilityCache.NOT_DRAGGING; 11851 return false; 11852 } 11853 11854 /** 11855 * Implement this method to handle touch screen motion events. 11856 * <p> 11857 * If this method is used to detect click actions, it is recommended that 11858 * the actions be performed by implementing and calling 11859 * {@link #performClick()}. This will ensure consistent system behavior, 11860 * including: 11861 * <ul> 11862 * <li>obeying click sound preferences 11863 * <li>dispatching OnClickListener calls 11864 * <li>handling {@link AccessibilityNodeInfo#ACTION_CLICK ACTION_CLICK} when 11865 * accessibility features are enabled 11866 * </ul> 11867 * 11868 * @param event The motion event. 11869 * @return True if the event was handled, false otherwise. 11870 */ 11871 public boolean onTouchEvent(MotionEvent event) { 11872 final float x = event.getX(); 11873 final float y = event.getY(); 11874 final int viewFlags = mViewFlags; 11875 final int action = event.getAction(); 11876 11877 final boolean clickable = ((viewFlags & CLICKABLE) == CLICKABLE 11878 || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE) 11879 || (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE; 11880 11881 if ((viewFlags & ENABLED_MASK) == DISABLED) { 11882 if (action == MotionEvent.ACTION_UP && (mPrivateFlags & PFLAG_PRESSED) != 0) { 11883 setPressed(false); 11884 } 11885 mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN; 11886 // A disabled view that is clickable still consumes the touch 11887 // events, it just doesn't respond to them. 11888 return clickable; 11889 } 11890 if (mTouchDelegate != null) { 11891 if (mTouchDelegate.onTouchEvent(event)) { 11892 return true; 11893 } 11894 } 11895 11896 if (clickable || (viewFlags & TOOLTIP) == TOOLTIP) { 11897 switch (action) { 11898 case MotionEvent.ACTION_UP: 11899 mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN; 11900 if ((viewFlags & TOOLTIP) == TOOLTIP) { 11901 handleTooltipUp(); 11902 } 11903 if (!clickable) { 11904 removeTapCallback(); 11905 removeLongPressCallback(); 11906 mInContextButtonPress = false; 11907 mHasPerformedLongPress = false; 11908 mIgnoreNextUpEvent = false; 11909 break; 11910 } 11911 boolean prepressed = (mPrivateFlags & PFLAG_PREPRESSED) != 0; 11912 if ((mPrivateFlags & PFLAG_PRESSED) != 0 || prepressed) { 11913 // take focus if we don't have it already and we should in 11914 // touch mode. 11915 boolean focusTaken = false; 11916 if (isFocusable() && isFocusableInTouchMode() && !isFocused()) { 11917 focusTaken = requestFocus(); 11918 } 11919 11920 if (prepressed) { 11921 // The button is being released before we actually 11922 // showed it as pressed. Make it show the pressed 11923 // state now (before scheduling the click) to ensure 11924 // the user sees it. 11925 setPressed(true, x, y); 11926 } 11927 11928 if (!mHasPerformedLongPress && !mIgnoreNextUpEvent) { 11929 // This is a tap, so remove the longpress check 11930 removeLongPressCallback(); 11931 11932 // Only perform take click actions if we were in the pressed state 11933 if (!focusTaken) { 11934 // Use a Runnable and post this rather than calling 11935 // performClick directly. This lets other visual state 11936 // of the view update before click actions start. 11937 if (mPerformClick == null) { 11938 mPerformClick = new PerformClick(); 11939 } 11940 if (!post(mPerformClick)) { 11941 performClick(); 11942 } 11943 } 11944 } 11945 11946 if (mUnsetPressedState == null) { 11947 mUnsetPressedState = new UnsetPressedState(); 11948 } 11949 11950 if (prepressed) { 11951 postDelayed(mUnsetPressedState, 11952 ViewConfiguration.getPressedStateDuration()); 11953 } else if (!post(mUnsetPressedState)) { 11954 // If the post failed, unpress right now 11955 mUnsetPressedState.run(); 11956 } 11957 11958 removeTapCallback(); 11959 } 11960 mIgnoreNextUpEvent = false; 11961 break; 11962 11963 case MotionEvent.ACTION_DOWN: 11964 if (event.getSource() == InputDevice.SOURCE_TOUCHSCREEN) { 11965 mPrivateFlags3 |= PFLAG3_FINGER_DOWN; 11966 } 11967 mHasPerformedLongPress = false; 11968 11969 if (!clickable) { 11970 checkForLongClick(0, x, y); 11971 break; 11972 } 11973 11974 if (performButtonActionOnTouchDown(event)) { 11975 break; 11976 } 11977 11978 // Walk up the hierarchy to determine if we're inside a scrolling container. 11979 boolean isInScrollingContainer = isInScrollingContainer(); 11980 11981 // For views inside a scrolling container, delay the pressed feedback for 11982 // a short period in case this is a scroll. 11983 if (isInScrollingContainer) { 11984 mPrivateFlags |= PFLAG_PREPRESSED; 11985 if (mPendingCheckForTap == null) { 11986 mPendingCheckForTap = new CheckForTap(); 11987 } 11988 mPendingCheckForTap.x = event.getX(); 11989 mPendingCheckForTap.y = event.getY(); 11990 postDelayed(mPendingCheckForTap, ViewConfiguration.getTapTimeout()); 11991 } else { 11992 // Not inside a scrolling container, so show the feedback right away 11993 setPressed(true, x, y); 11994 checkForLongClick(0, x, y); 11995 } 11996 break; 11997 11998 case MotionEvent.ACTION_CANCEL: 11999 if (clickable) { 12000 setPressed(false); 12001 } 12002 removeTapCallback(); 12003 removeLongPressCallback(); 12004 mInContextButtonPress = false; 12005 mHasPerformedLongPress = false; 12006 mIgnoreNextUpEvent = false; 12007 mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN; 12008 break; 12009 12010 case MotionEvent.ACTION_MOVE: 12011 if (clickable) { 12012 drawableHotspotChanged(x, y); 12013 } 12014 12015 // Be lenient about moving outside of buttons 12016 if (!pointInView(x, y, mTouchSlop)) { 12017 // Outside button 12018 // Remove any future long press/tap checks 12019 removeTapCallback(); 12020 removeLongPressCallback(); 12021 if ((mPrivateFlags & PFLAG_PRESSED) != 0) { 12022 setPressed(false); 12023 } 12024 mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN; 12025 } 12026 break; 12027 } 12028 12029 return true; 12030 } 12031 12032 return false; 12033 } 12034 12035 /** 12036 * @hide 12037 */ 12038 public boolean isInScrollingContainer() { 12039 ViewParent p = getParent(); 12040 while (p != null && p instanceof ViewGroup) { 12041 if (((ViewGroup) p).shouldDelayChildPressedState()) { 12042 return true; 12043 } 12044 p = p.getParent(); 12045 } 12046 return false; 12047 } 12048 12049 /** 12050 * Remove the longpress detection timer. 12051 */ 12052 private void removeLongPressCallback() { 12053 if (mPendingCheckForLongPress != null) { 12054 removeCallbacks(mPendingCheckForLongPress); 12055 } 12056 } 12057 12058 /** 12059 * Remove the pending click action 12060 */ 12061 private void removePerformClickCallback() { 12062 if (mPerformClick != null) { 12063 removeCallbacks(mPerformClick); 12064 } 12065 } 12066 12067 /** 12068 * Remove the prepress detection timer. 12069 */ 12070 private void removeUnsetPressCallback() { 12071 if ((mPrivateFlags & PFLAG_PRESSED) != 0 && mUnsetPressedState != null) { 12072 setPressed(false); 12073 removeCallbacks(mUnsetPressedState); 12074 } 12075 } 12076 12077 /** 12078 * Remove the tap detection timer. 12079 */ 12080 private void removeTapCallback() { 12081 if (mPendingCheckForTap != null) { 12082 mPrivateFlags &= ~PFLAG_PREPRESSED; 12083 removeCallbacks(mPendingCheckForTap); 12084 } 12085 } 12086 12087 /** 12088 * Cancels a pending long press. Your subclass can use this if you 12089 * want the context menu to come up if the user presses and holds 12090 * at the same place, but you don't want it to come up if they press 12091 * and then move around enough to cause scrolling. 12092 */ 12093 public void cancelLongPress() { 12094 removeLongPressCallback(); 12095 12096 /* 12097 * The prepressed state handled by the tap callback is a display 12098 * construct, but the tap callback will post a long press callback 12099 * less its own timeout. Remove it here. 12100 */ 12101 removeTapCallback(); 12102 } 12103 12104 /** 12105 * Remove the pending callback for sending a 12106 * {@link AccessibilityEvent#TYPE_VIEW_SCROLLED} accessibility event. 12107 */ 12108 private void removeSendViewScrolledAccessibilityEventCallback() { 12109 if (mSendViewScrolledAccessibilityEvent != null) { 12110 removeCallbacks(mSendViewScrolledAccessibilityEvent); 12111 mSendViewScrolledAccessibilityEvent.mIsPending = false; 12112 } 12113 } 12114 12115 /** 12116 * Sets the TouchDelegate for this View. 12117 */ 12118 public void setTouchDelegate(TouchDelegate delegate) { 12119 mTouchDelegate = delegate; 12120 } 12121 12122 /** 12123 * Gets the TouchDelegate for this View. 12124 */ 12125 public TouchDelegate getTouchDelegate() { 12126 return mTouchDelegate; 12127 } 12128 12129 /** 12130 * Request unbuffered dispatch of the given stream of MotionEvents to this View. 12131 * 12132 * Until this View receives a corresponding {@link MotionEvent#ACTION_UP}, ask that the input 12133 * system not batch {@link MotionEvent}s but instead deliver them as soon as they're 12134 * available. This method should only be called for touch events. 12135 * 12136 * <p class="note">This api is not intended for most applications. Buffered dispatch 12137 * provides many of benefits, and just requesting unbuffered dispatch on most MotionEvent 12138 * streams will not improve your input latency. Side effects include: increased latency, 12139 * jittery scrolls and inability to take advantage of system resampling. Talk to your input 12140 * professional to see if {@link #requestUnbufferedDispatch(MotionEvent)} is right for 12141 * you.</p> 12142 */ 12143 public final void requestUnbufferedDispatch(MotionEvent event) { 12144 final int action = event.getAction(); 12145 if (mAttachInfo == null 12146 || action != MotionEvent.ACTION_DOWN && action != MotionEvent.ACTION_MOVE 12147 || !event.isTouchEvent()) { 12148 return; 12149 } 12150 mAttachInfo.mUnbufferedDispatchRequested = true; 12151 } 12152 12153 /** 12154 * Set flags controlling behavior of this view. 12155 * 12156 * @param flags Constant indicating the value which should be set 12157 * @param mask Constant indicating the bit range that should be changed 12158 */ 12159 void setFlags(int flags, int mask) { 12160 final boolean accessibilityEnabled = 12161 AccessibilityManager.getInstance(mContext).isEnabled(); 12162 final boolean oldIncludeForAccessibility = accessibilityEnabled && includeForAccessibility(); 12163 12164 int old = mViewFlags; 12165 mViewFlags = (mViewFlags & ~mask) | (flags & mask); 12166 12167 int changed = mViewFlags ^ old; 12168 if (changed == 0) { 12169 return; 12170 } 12171 int privateFlags = mPrivateFlags; 12172 12173 // If focusable is auto, update the FOCUSABLE bit. 12174 int focusableChangedByAuto = 0; 12175 if (((mViewFlags & FOCUSABLE_AUTO) != 0) 12176 && (changed & (FOCUSABLE_MASK | CLICKABLE | FOCUSABLE_IN_TOUCH_MODE)) != 0) { 12177 int newFocus = NOT_FOCUSABLE; 12178 if ((mViewFlags & (CLICKABLE | FOCUSABLE_IN_TOUCH_MODE)) != 0) { 12179 newFocus = FOCUSABLE; 12180 } else { 12181 mViewFlags = (mViewFlags & ~FOCUSABLE_IN_TOUCH_MODE); 12182 } 12183 mViewFlags = (mViewFlags & ~FOCUSABLE) | newFocus; 12184 focusableChangedByAuto = (old & FOCUSABLE) ^ (newFocus & FOCUSABLE); 12185 changed = (changed & ~FOCUSABLE) | focusableChangedByAuto; 12186 } 12187 12188 /* Check if the FOCUSABLE bit has changed */ 12189 if (((changed & FOCUSABLE) != 0) && ((privateFlags & PFLAG_HAS_BOUNDS) != 0)) { 12190 if (((old & FOCUSABLE) == FOCUSABLE) 12191 && ((privateFlags & PFLAG_FOCUSED) != 0)) { 12192 /* Give up focus if we are no longer focusable */ 12193 clearFocus(); 12194 } else if (((old & FOCUSABLE) == NOT_FOCUSABLE) 12195 && ((privateFlags & PFLAG_FOCUSED) == 0)) { 12196 /* 12197 * Tell the view system that we are now available to take focus 12198 * if no one else already has it. 12199 */ 12200 if (mParent != null) { 12201 ViewRootImpl viewRootImpl = getViewRootImpl(); 12202 if (!sAutoFocusableOffUIThreadWontNotifyParents 12203 || focusableChangedByAuto == 0 12204 || viewRootImpl == null 12205 || viewRootImpl.mThread == Thread.currentThread()) { 12206 mParent.focusableViewAvailable(this); 12207 } 12208 } 12209 } 12210 } 12211 12212 final int newVisibility = flags & VISIBILITY_MASK; 12213 if (newVisibility == VISIBLE) { 12214 if ((changed & VISIBILITY_MASK) != 0) { 12215 /* 12216 * If this view is becoming visible, invalidate it in case it changed while 12217 * it was not visible. Marking it drawn ensures that the invalidation will 12218 * go through. 12219 */ 12220 mPrivateFlags |= PFLAG_DRAWN; 12221 invalidate(true); 12222 12223 needGlobalAttributesUpdate(true); 12224 12225 // a view becoming visible is worth notifying the parent 12226 // about in case nothing has focus. even if this specific view 12227 // isn't focusable, it may contain something that is, so let 12228 // the root view try to give this focus if nothing else does. 12229 if ((mParent != null) && (mBottom > mTop) && (mRight > mLeft)) { 12230 mParent.focusableViewAvailable(this); 12231 } 12232 } 12233 } 12234 12235 /* Check if the GONE bit has changed */ 12236 if ((changed & GONE) != 0) { 12237 needGlobalAttributesUpdate(false); 12238 requestLayout(); 12239 12240 if (((mViewFlags & VISIBILITY_MASK) == GONE)) { 12241 if (hasFocus()) clearFocus(); 12242 clearAccessibilityFocus(); 12243 destroyDrawingCache(); 12244 if (mParent instanceof View) { 12245 // GONE views noop invalidation, so invalidate the parent 12246 ((View) mParent).invalidate(true); 12247 } 12248 // Mark the view drawn to ensure that it gets invalidated properly the next 12249 // time it is visible and gets invalidated 12250 mPrivateFlags |= PFLAG_DRAWN; 12251 } 12252 if (mAttachInfo != null) { 12253 mAttachInfo.mViewVisibilityChanged = true; 12254 } 12255 } 12256 12257 /* Check if the VISIBLE bit has changed */ 12258 if ((changed & INVISIBLE) != 0) { 12259 needGlobalAttributesUpdate(false); 12260 /* 12261 * If this view is becoming invisible, set the DRAWN flag so that 12262 * the next invalidate() will not be skipped. 12263 */ 12264 mPrivateFlags |= PFLAG_DRAWN; 12265 12266 if (((mViewFlags & VISIBILITY_MASK) == INVISIBLE)) { 12267 // root view becoming invisible shouldn't clear focus and accessibility focus 12268 if (getRootView() != this) { 12269 if (hasFocus()) clearFocus(); 12270 clearAccessibilityFocus(); 12271 } 12272 } 12273 if (mAttachInfo != null) { 12274 mAttachInfo.mViewVisibilityChanged = true; 12275 } 12276 } 12277 12278 if ((changed & VISIBILITY_MASK) != 0) { 12279 // If the view is invisible, cleanup its display list to free up resources 12280 if (newVisibility != VISIBLE && mAttachInfo != null) { 12281 cleanupDraw(); 12282 } 12283 12284 if (mParent instanceof ViewGroup) { 12285 ((ViewGroup) mParent).onChildVisibilityChanged(this, 12286 (changed & VISIBILITY_MASK), newVisibility); 12287 ((View) mParent).invalidate(true); 12288 } else if (mParent != null) { 12289 mParent.invalidateChild(this, null); 12290 } 12291 12292 if (mAttachInfo != null) { 12293 dispatchVisibilityChanged(this, newVisibility); 12294 12295 // Aggregated visibility changes are dispatched to attached views 12296 // in visible windows where the parent is currently shown/drawn 12297 // or the parent is not a ViewGroup (and therefore assumed to be a ViewRoot), 12298 // discounting clipping or overlapping. This makes it a good place 12299 // to change animation states. 12300 if (mParent != null && getWindowVisibility() == VISIBLE && 12301 ((!(mParent instanceof ViewGroup)) || ((ViewGroup) mParent).isShown())) { 12302 dispatchVisibilityAggregated(newVisibility == VISIBLE); 12303 } 12304 notifySubtreeAccessibilityStateChangedIfNeeded(); 12305 } 12306 } 12307 12308 if ((changed & WILL_NOT_CACHE_DRAWING) != 0) { 12309 destroyDrawingCache(); 12310 } 12311 12312 if ((changed & DRAWING_CACHE_ENABLED) != 0) { 12313 destroyDrawingCache(); 12314 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; 12315 invalidateParentCaches(); 12316 } 12317 12318 if ((changed & DRAWING_CACHE_QUALITY_MASK) != 0) { 12319 destroyDrawingCache(); 12320 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; 12321 } 12322 12323 if ((changed & DRAW_MASK) != 0) { 12324 if ((mViewFlags & WILL_NOT_DRAW) != 0) { 12325 if (mBackground != null 12326 || (mForegroundInfo != null && mForegroundInfo.mDrawable != null)) { 12327 mPrivateFlags &= ~PFLAG_SKIP_DRAW; 12328 } else { 12329 mPrivateFlags |= PFLAG_SKIP_DRAW; 12330 } 12331 } else { 12332 mPrivateFlags &= ~PFLAG_SKIP_DRAW; 12333 } 12334 requestLayout(); 12335 invalidate(true); 12336 } 12337 12338 if ((changed & KEEP_SCREEN_ON) != 0) { 12339 if (mParent != null && mAttachInfo != null && !mAttachInfo.mRecomputeGlobalAttributes) { 12340 mParent.recomputeViewAttributes(this); 12341 } 12342 } 12343 12344 if (accessibilityEnabled) { 12345 if ((changed & FOCUSABLE) != 0 || (changed & VISIBILITY_MASK) != 0 12346 || (changed & CLICKABLE) != 0 || (changed & LONG_CLICKABLE) != 0 12347 || (changed & CONTEXT_CLICKABLE) != 0) { 12348 if (oldIncludeForAccessibility != includeForAccessibility()) { 12349 notifySubtreeAccessibilityStateChangedIfNeeded(); 12350 } else { 12351 notifyViewAccessibilityStateChangedIfNeeded( 12352 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 12353 } 12354 } else if ((changed & ENABLED_MASK) != 0) { 12355 notifyViewAccessibilityStateChangedIfNeeded( 12356 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 12357 } 12358 } 12359 } 12360 12361 /** 12362 * Change the view's z order in the tree, so it's on top of other sibling 12363 * views. This ordering change may affect layout, if the parent container 12364 * uses an order-dependent layout scheme (e.g., LinearLayout). Prior 12365 * to {@link android.os.Build.VERSION_CODES#KITKAT} this 12366 * method should be followed by calls to {@link #requestLayout()} and 12367 * {@link View#invalidate()} on the view's parent to force the parent to redraw 12368 * with the new child ordering. 12369 * 12370 * @see ViewGroup#bringChildToFront(View) 12371 */ 12372 public void bringToFront() { 12373 if (mParent != null) { 12374 mParent.bringChildToFront(this); 12375 } 12376 } 12377 12378 /** 12379 * This is called in response to an internal scroll in this view (i.e., the 12380 * view scrolled its own contents). This is typically as a result of 12381 * {@link #scrollBy(int, int)} or {@link #scrollTo(int, int)} having been 12382 * called. 12383 * 12384 * @param l Current horizontal scroll origin. 12385 * @param t Current vertical scroll origin. 12386 * @param oldl Previous horizontal scroll origin. 12387 * @param oldt Previous vertical scroll origin. 12388 */ 12389 protected void onScrollChanged(int l, int t, int oldl, int oldt) { 12390 notifySubtreeAccessibilityStateChangedIfNeeded(); 12391 12392 if (AccessibilityManager.getInstance(mContext).isEnabled()) { 12393 postSendViewScrolledAccessibilityEventCallback(); 12394 } 12395 12396 mBackgroundSizeChanged = true; 12397 if (mForegroundInfo != null) { 12398 mForegroundInfo.mBoundsChanged = true; 12399 } 12400 12401 final AttachInfo ai = mAttachInfo; 12402 if (ai != null) { 12403 ai.mViewScrollChanged = true; 12404 } 12405 12406 if (mListenerInfo != null && mListenerInfo.mOnScrollChangeListener != null) { 12407 mListenerInfo.mOnScrollChangeListener.onScrollChange(this, l, t, oldl, oldt); 12408 } 12409 } 12410 12411 /** 12412 * Interface definition for a callback to be invoked when the scroll 12413 * X or Y positions of a view change. 12414 * <p> 12415 * <b>Note:</b> Some views handle scrolling independently from View and may 12416 * have their own separate listeners for scroll-type events. For example, 12417 * {@link android.widget.ListView ListView} allows clients to register an 12418 * {@link android.widget.ListView#setOnScrollListener(android.widget.AbsListView.OnScrollListener) AbsListView.OnScrollListener} 12419 * to listen for changes in list scroll position. 12420 * 12421 * @see #setOnScrollChangeListener(View.OnScrollChangeListener) 12422 */ 12423 public interface OnScrollChangeListener { 12424 /** 12425 * Called when the scroll position of a view changes. 12426 * 12427 * @param v The view whose scroll position has changed. 12428 * @param scrollX Current horizontal scroll origin. 12429 * @param scrollY Current vertical scroll origin. 12430 * @param oldScrollX Previous horizontal scroll origin. 12431 * @param oldScrollY Previous vertical scroll origin. 12432 */ 12433 void onScrollChange(View v, int scrollX, int scrollY, int oldScrollX, int oldScrollY); 12434 } 12435 12436 /** 12437 * Interface definition for a callback to be invoked when the layout bounds of a view 12438 * changes due to layout processing. 12439 */ 12440 public interface OnLayoutChangeListener { 12441 /** 12442 * Called when the layout bounds of a view changes due to layout processing. 12443 * 12444 * @param v The view whose bounds have changed. 12445 * @param left The new value of the view's left property. 12446 * @param top The new value of the view's top property. 12447 * @param right The new value of the view's right property. 12448 * @param bottom The new value of the view's bottom property. 12449 * @param oldLeft The previous value of the view's left property. 12450 * @param oldTop The previous value of the view's top property. 12451 * @param oldRight The previous value of the view's right property. 12452 * @param oldBottom The previous value of the view's bottom property. 12453 */ 12454 void onLayoutChange(View v, int left, int top, int right, int bottom, 12455 int oldLeft, int oldTop, int oldRight, int oldBottom); 12456 } 12457 12458 /** 12459 * This is called during layout when the size of this view has changed. If 12460 * you were just added to the view hierarchy, you're called with the old 12461 * values of 0. 12462 * 12463 * @param w Current width of this view. 12464 * @param h Current height of this view. 12465 * @param oldw Old width of this view. 12466 * @param oldh Old height of this view. 12467 */ 12468 protected void onSizeChanged(int w, int h, int oldw, int oldh) { 12469 } 12470 12471 /** 12472 * Called by draw to draw the child views. This may be overridden 12473 * by derived classes to gain control just before its children are drawn 12474 * (but after its own view has been drawn). 12475 * @param canvas the canvas on which to draw the view 12476 */ 12477 protected void dispatchDraw(Canvas canvas) { 12478 12479 } 12480 12481 /** 12482 * Gets the parent of this view. Note that the parent is a 12483 * ViewParent and not necessarily a View. 12484 * 12485 * @return Parent of this view. 12486 */ 12487 public final ViewParent getParent() { 12488 return mParent; 12489 } 12490 12491 /** 12492 * Set the horizontal scrolled position of your view. This will cause a call to 12493 * {@link #onScrollChanged(int, int, int, int)} and the view will be 12494 * invalidated. 12495 * @param value the x position to scroll to 12496 */ 12497 public void setScrollX(int value) { 12498 scrollTo(value, mScrollY); 12499 } 12500 12501 /** 12502 * Set the vertical scrolled position of your view. This will cause a call to 12503 * {@link #onScrollChanged(int, int, int, int)} and the view will be 12504 * invalidated. 12505 * @param value the y position to scroll to 12506 */ 12507 public void setScrollY(int value) { 12508 scrollTo(mScrollX, value); 12509 } 12510 12511 /** 12512 * Return the scrolled left position of this view. This is the left edge of 12513 * the displayed part of your view. You do not need to draw any pixels 12514 * farther left, since those are outside of the frame of your view on 12515 * screen. 12516 * 12517 * @return The left edge of the displayed part of your view, in pixels. 12518 */ 12519 public final int getScrollX() { 12520 return mScrollX; 12521 } 12522 12523 /** 12524 * Return the scrolled top position of this view. This is the top edge of 12525 * the displayed part of your view. You do not need to draw any pixels above 12526 * it, since those are outside of the frame of your view on screen. 12527 * 12528 * @return The top edge of the displayed part of your view, in pixels. 12529 */ 12530 public final int getScrollY() { 12531 return mScrollY; 12532 } 12533 12534 /** 12535 * Return the width of the your view. 12536 * 12537 * @return The width of your view, in pixels. 12538 */ 12539 @ViewDebug.ExportedProperty(category = "layout") 12540 public final int getWidth() { 12541 return mRight - mLeft; 12542 } 12543 12544 /** 12545 * Return the height of your view. 12546 * 12547 * @return The height of your view, in pixels. 12548 */ 12549 @ViewDebug.ExportedProperty(category = "layout") 12550 public final int getHeight() { 12551 return mBottom - mTop; 12552 } 12553 12554 /** 12555 * Return the visible drawing bounds of your view. Fills in the output 12556 * rectangle with the values from getScrollX(), getScrollY(), 12557 * getWidth(), and getHeight(). These bounds do not account for any 12558 * transformation properties currently set on the view, such as 12559 * {@link #setScaleX(float)} or {@link #setRotation(float)}. 12560 * 12561 * @param outRect The (scrolled) drawing bounds of the view. 12562 */ 12563 public void getDrawingRect(Rect outRect) { 12564 outRect.left = mScrollX; 12565 outRect.top = mScrollY; 12566 outRect.right = mScrollX + (mRight - mLeft); 12567 outRect.bottom = mScrollY + (mBottom - mTop); 12568 } 12569 12570 /** 12571 * Like {@link #getMeasuredWidthAndState()}, but only returns the 12572 * raw width component (that is the result is masked by 12573 * {@link #MEASURED_SIZE_MASK}). 12574 * 12575 * @return The raw measured width of this view. 12576 */ 12577 public final int getMeasuredWidth() { 12578 return mMeasuredWidth & MEASURED_SIZE_MASK; 12579 } 12580 12581 /** 12582 * Return the full width measurement information for this view as computed 12583 * by the most recent call to {@link #measure(int, int)}. This result is a bit mask 12584 * as defined by {@link #MEASURED_SIZE_MASK} and {@link #MEASURED_STATE_TOO_SMALL}. 12585 * This should be used during measurement and layout calculations only. Use 12586 * {@link #getWidth()} to see how wide a view is after layout. 12587 * 12588 * @return The measured width of this view as a bit mask. 12589 */ 12590 @ViewDebug.ExportedProperty(category = "measurement", flagMapping = { 12591 @ViewDebug.FlagToString(mask = MEASURED_STATE_MASK, equals = MEASURED_STATE_TOO_SMALL, 12592 name = "MEASURED_STATE_TOO_SMALL"), 12593 }) 12594 public final int getMeasuredWidthAndState() { 12595 return mMeasuredWidth; 12596 } 12597 12598 /** 12599 * Like {@link #getMeasuredHeightAndState()}, but only returns the 12600 * raw height component (that is the result is masked by 12601 * {@link #MEASURED_SIZE_MASK}). 12602 * 12603 * @return The raw measured height of this view. 12604 */ 12605 public final int getMeasuredHeight() { 12606 return mMeasuredHeight & MEASURED_SIZE_MASK; 12607 } 12608 12609 /** 12610 * Return the full height measurement information for this view as computed 12611 * by the most recent call to {@link #measure(int, int)}. This result is a bit mask 12612 * as defined by {@link #MEASURED_SIZE_MASK} and {@link #MEASURED_STATE_TOO_SMALL}. 12613 * This should be used during measurement and layout calculations only. Use 12614 * {@link #getHeight()} to see how wide a view is after layout. 12615 * 12616 * @return The measured height of this view as a bit mask. 12617 */ 12618 @ViewDebug.ExportedProperty(category = "measurement", flagMapping = { 12619 @ViewDebug.FlagToString(mask = MEASURED_STATE_MASK, equals = MEASURED_STATE_TOO_SMALL, 12620 name = "MEASURED_STATE_TOO_SMALL"), 12621 }) 12622 public final int getMeasuredHeightAndState() { 12623 return mMeasuredHeight; 12624 } 12625 12626 /** 12627 * Return only the state bits of {@link #getMeasuredWidthAndState()} 12628 * and {@link #getMeasuredHeightAndState()}, combined into one integer. 12629 * The width component is in the regular bits {@link #MEASURED_STATE_MASK} 12630 * and the height component is at the shifted bits 12631 * {@link #MEASURED_HEIGHT_STATE_SHIFT}>>{@link #MEASURED_STATE_MASK}. 12632 */ 12633 public final int getMeasuredState() { 12634 return (mMeasuredWidth&MEASURED_STATE_MASK) 12635 | ((mMeasuredHeight>>MEASURED_HEIGHT_STATE_SHIFT) 12636 & (MEASURED_STATE_MASK>>MEASURED_HEIGHT_STATE_SHIFT)); 12637 } 12638 12639 /** 12640 * The transform matrix of this view, which is calculated based on the current 12641 * rotation, scale, and pivot properties. 12642 * 12643 * @see #getRotation() 12644 * @see #getScaleX() 12645 * @see #getScaleY() 12646 * @see #getPivotX() 12647 * @see #getPivotY() 12648 * @return The current transform matrix for the view 12649 */ 12650 public Matrix getMatrix() { 12651 ensureTransformationInfo(); 12652 final Matrix matrix = mTransformationInfo.mMatrix; 12653 mRenderNode.getMatrix(matrix); 12654 return matrix; 12655 } 12656 12657 /** 12658 * Returns true if the transform matrix is the identity matrix. 12659 * Recomputes the matrix if necessary. 12660 * 12661 * @return True if the transform matrix is the identity matrix, false otherwise. 12662 */ 12663 final boolean hasIdentityMatrix() { 12664 return mRenderNode.hasIdentityMatrix(); 12665 } 12666 12667 void ensureTransformationInfo() { 12668 if (mTransformationInfo == null) { 12669 mTransformationInfo = new TransformationInfo(); 12670 } 12671 } 12672 12673 /** 12674 * Utility method to retrieve the inverse of the current mMatrix property. 12675 * We cache the matrix to avoid recalculating it when transform properties 12676 * have not changed. 12677 * 12678 * @return The inverse of the current matrix of this view. 12679 * @hide 12680 */ 12681 public final Matrix getInverseMatrix() { 12682 ensureTransformationInfo(); 12683 if (mTransformationInfo.mInverseMatrix == null) { 12684 mTransformationInfo.mInverseMatrix = new Matrix(); 12685 } 12686 final Matrix matrix = mTransformationInfo.mInverseMatrix; 12687 mRenderNode.getInverseMatrix(matrix); 12688 return matrix; 12689 } 12690 12691 /** 12692 * Gets the distance along the Z axis from the camera to this view. 12693 * 12694 * @see #setCameraDistance(float) 12695 * 12696 * @return The distance along the Z axis. 12697 */ 12698 public float getCameraDistance() { 12699 final float dpi = mResources.getDisplayMetrics().densityDpi; 12700 return -(mRenderNode.getCameraDistance() * dpi); 12701 } 12702 12703 /** 12704 * <p>Sets the distance along the Z axis (orthogonal to the X/Y plane on which 12705 * views are drawn) from the camera to this view. The camera's distance 12706 * affects 3D transformations, for instance rotations around the X and Y 12707 * axis. If the rotationX or rotationY properties are changed and this view is 12708 * large (more than half the size of the screen), it is recommended to always 12709 * use a camera distance that's greater than the height (X axis rotation) or 12710 * the width (Y axis rotation) of this view.</p> 12711 * 12712 * <p>The distance of the camera from the view plane can have an affect on the 12713 * perspective distortion of the view when it is rotated around the x or y axis. 12714 * For example, a large distance will result in a large viewing angle, and there 12715 * will not be much perspective distortion of the view as it rotates. A short 12716 * distance may cause much more perspective distortion upon rotation, and can 12717 * also result in some drawing artifacts if the rotated view ends up partially 12718 * behind the camera (which is why the recommendation is to use a distance at 12719 * least as far as the size of the view, if the view is to be rotated.)</p> 12720 * 12721 * <p>The distance is expressed in "depth pixels." The default distance depends 12722 * on the screen density. For instance, on a medium density display, the 12723 * default distance is 1280. On a high density display, the default distance 12724 * is 1920.</p> 12725 * 12726 * <p>If you want to specify a distance that leads to visually consistent 12727 * results across various densities, use the following formula:</p> 12728 * <pre> 12729 * float scale = context.getResources().getDisplayMetrics().density; 12730 * view.setCameraDistance(distance * scale); 12731 * </pre> 12732 * 12733 * <p>The density scale factor of a high density display is 1.5, 12734 * and 1920 = 1280 * 1.5.</p> 12735 * 12736 * @param distance The distance in "depth pixels", if negative the opposite 12737 * value is used 12738 * 12739 * @see #setRotationX(float) 12740 * @see #setRotationY(float) 12741 */ 12742 public void setCameraDistance(float distance) { 12743 final float dpi = mResources.getDisplayMetrics().densityDpi; 12744 12745 invalidateViewProperty(true, false); 12746 mRenderNode.setCameraDistance(-Math.abs(distance) / dpi); 12747 invalidateViewProperty(false, false); 12748 12749 invalidateParentIfNeededAndWasQuickRejected(); 12750 } 12751 12752 /** 12753 * The degrees that the view is rotated around the pivot point. 12754 * 12755 * @see #setRotation(float) 12756 * @see #getPivotX() 12757 * @see #getPivotY() 12758 * 12759 * @return The degrees of rotation. 12760 */ 12761 @ViewDebug.ExportedProperty(category = "drawing") 12762 public float getRotation() { 12763 return mRenderNode.getRotation(); 12764 } 12765 12766 /** 12767 * Sets the degrees that the view is rotated around the pivot point. Increasing values 12768 * result in clockwise rotation. 12769 * 12770 * @param rotation The degrees of rotation. 12771 * 12772 * @see #getRotation() 12773 * @see #getPivotX() 12774 * @see #getPivotY() 12775 * @see #setRotationX(float) 12776 * @see #setRotationY(float) 12777 * 12778 * @attr ref android.R.styleable#View_rotation 12779 */ 12780 public void setRotation(float rotation) { 12781 if (rotation != getRotation()) { 12782 // Double-invalidation is necessary to capture view's old and new areas 12783 invalidateViewProperty(true, false); 12784 mRenderNode.setRotation(rotation); 12785 invalidateViewProperty(false, true); 12786 12787 invalidateParentIfNeededAndWasQuickRejected(); 12788 notifySubtreeAccessibilityStateChangedIfNeeded(); 12789 } 12790 } 12791 12792 /** 12793 * The degrees that the view is rotated around the vertical axis through the pivot point. 12794 * 12795 * @see #getPivotX() 12796 * @see #getPivotY() 12797 * @see #setRotationY(float) 12798 * 12799 * @return The degrees of Y rotation. 12800 */ 12801 @ViewDebug.ExportedProperty(category = "drawing") 12802 public float getRotationY() { 12803 return mRenderNode.getRotationY(); 12804 } 12805 12806 /** 12807 * Sets the degrees that the view is rotated around the vertical axis through the pivot point. 12808 * Increasing values result in counter-clockwise rotation from the viewpoint of looking 12809 * down the y axis. 12810 * 12811 * When rotating large views, it is recommended to adjust the camera distance 12812 * accordingly. Refer to {@link #setCameraDistance(float)} for more information. 12813 * 12814 * @param rotationY The degrees of Y rotation. 12815 * 12816 * @see #getRotationY() 12817 * @see #getPivotX() 12818 * @see #getPivotY() 12819 * @see #setRotation(float) 12820 * @see #setRotationX(float) 12821 * @see #setCameraDistance(float) 12822 * 12823 * @attr ref android.R.styleable#View_rotationY 12824 */ 12825 public void setRotationY(float rotationY) { 12826 if (rotationY != getRotationY()) { 12827 invalidateViewProperty(true, false); 12828 mRenderNode.setRotationY(rotationY); 12829 invalidateViewProperty(false, true); 12830 12831 invalidateParentIfNeededAndWasQuickRejected(); 12832 notifySubtreeAccessibilityStateChangedIfNeeded(); 12833 } 12834 } 12835 12836 /** 12837 * The degrees that the view is rotated around the horizontal axis through the pivot point. 12838 * 12839 * @see #getPivotX() 12840 * @see #getPivotY() 12841 * @see #setRotationX(float) 12842 * 12843 * @return The degrees of X rotation. 12844 */ 12845 @ViewDebug.ExportedProperty(category = "drawing") 12846 public float getRotationX() { 12847 return mRenderNode.getRotationX(); 12848 } 12849 12850 /** 12851 * Sets the degrees that the view is rotated around the horizontal axis through the pivot point. 12852 * Increasing values result in clockwise rotation from the viewpoint of looking down the 12853 * x axis. 12854 * 12855 * When rotating large views, it is recommended to adjust the camera distance 12856 * accordingly. Refer to {@link #setCameraDistance(float)} for more information. 12857 * 12858 * @param rotationX The degrees of X rotation. 12859 * 12860 * @see #getRotationX() 12861 * @see #getPivotX() 12862 * @see #getPivotY() 12863 * @see #setRotation(float) 12864 * @see #setRotationY(float) 12865 * @see #setCameraDistance(float) 12866 * 12867 * @attr ref android.R.styleable#View_rotationX 12868 */ 12869 public void setRotationX(float rotationX) { 12870 if (rotationX != getRotationX()) { 12871 invalidateViewProperty(true, false); 12872 mRenderNode.setRotationX(rotationX); 12873 invalidateViewProperty(false, true); 12874 12875 invalidateParentIfNeededAndWasQuickRejected(); 12876 notifySubtreeAccessibilityStateChangedIfNeeded(); 12877 } 12878 } 12879 12880 /** 12881 * The amount that the view is scaled in x around the pivot point, as a proportion of 12882 * the view's unscaled width. A value of 1, the default, means that no scaling is applied. 12883 * 12884 * <p>By default, this is 1.0f. 12885 * 12886 * @see #getPivotX() 12887 * @see #getPivotY() 12888 * @return The scaling factor. 12889 */ 12890 @ViewDebug.ExportedProperty(category = "drawing") 12891 public float getScaleX() { 12892 return mRenderNode.getScaleX(); 12893 } 12894 12895 /** 12896 * Sets the amount that the view is scaled in x around the pivot point, as a proportion of 12897 * the view's unscaled width. A value of 1 means that no scaling is applied. 12898 * 12899 * @param scaleX The scaling factor. 12900 * @see #getPivotX() 12901 * @see #getPivotY() 12902 * 12903 * @attr ref android.R.styleable#View_scaleX 12904 */ 12905 public void setScaleX(float scaleX) { 12906 if (scaleX != getScaleX()) { 12907 invalidateViewProperty(true, false); 12908 mRenderNode.setScaleX(scaleX); 12909 invalidateViewProperty(false, true); 12910 12911 invalidateParentIfNeededAndWasQuickRejected(); 12912 notifySubtreeAccessibilityStateChangedIfNeeded(); 12913 } 12914 } 12915 12916 /** 12917 * The amount that the view is scaled in y around the pivot point, as a proportion of 12918 * the view's unscaled height. A value of 1, the default, means that no scaling is applied. 12919 * 12920 * <p>By default, this is 1.0f. 12921 * 12922 * @see #getPivotX() 12923 * @see #getPivotY() 12924 * @return The scaling factor. 12925 */ 12926 @ViewDebug.ExportedProperty(category = "drawing") 12927 public float getScaleY() { 12928 return mRenderNode.getScaleY(); 12929 } 12930 12931 /** 12932 * Sets the amount that the view is scaled in Y around the pivot point, as a proportion of 12933 * the view's unscaled width. A value of 1 means that no scaling is applied. 12934 * 12935 * @param scaleY The scaling factor. 12936 * @see #getPivotX() 12937 * @see #getPivotY() 12938 * 12939 * @attr ref android.R.styleable#View_scaleY 12940 */ 12941 public void setScaleY(float scaleY) { 12942 if (scaleY != getScaleY()) { 12943 invalidateViewProperty(true, false); 12944 mRenderNode.setScaleY(scaleY); 12945 invalidateViewProperty(false, true); 12946 12947 invalidateParentIfNeededAndWasQuickRejected(); 12948 notifySubtreeAccessibilityStateChangedIfNeeded(); 12949 } 12950 } 12951 12952 /** 12953 * The x location of the point around which the view is {@link #setRotation(float) rotated} 12954 * and {@link #setScaleX(float) scaled}. 12955 * 12956 * @see #getRotation() 12957 * @see #getScaleX() 12958 * @see #getScaleY() 12959 * @see #getPivotY() 12960 * @return The x location of the pivot point. 12961 * 12962 * @attr ref android.R.styleable#View_transformPivotX 12963 */ 12964 @ViewDebug.ExportedProperty(category = "drawing") 12965 public float getPivotX() { 12966 return mRenderNode.getPivotX(); 12967 } 12968 12969 /** 12970 * Sets the x location of the point around which the view is 12971 * {@link #setRotation(float) rotated} and {@link #setScaleX(float) scaled}. 12972 * By default, the pivot point is centered on the object. 12973 * Setting this property disables this behavior and causes the view to use only the 12974 * explicitly set pivotX and pivotY values. 12975 * 12976 * @param pivotX The x location of the pivot point. 12977 * @see #getRotation() 12978 * @see #getScaleX() 12979 * @see #getScaleY() 12980 * @see #getPivotY() 12981 * 12982 * @attr ref android.R.styleable#View_transformPivotX 12983 */ 12984 public void setPivotX(float pivotX) { 12985 if (!mRenderNode.isPivotExplicitlySet() || pivotX != getPivotX()) { 12986 invalidateViewProperty(true, false); 12987 mRenderNode.setPivotX(pivotX); 12988 invalidateViewProperty(false, true); 12989 12990 invalidateParentIfNeededAndWasQuickRejected(); 12991 } 12992 } 12993 12994 /** 12995 * The y location of the point around which the view is {@link #setRotation(float) rotated} 12996 * and {@link #setScaleY(float) scaled}. 12997 * 12998 * @see #getRotation() 12999 * @see #getScaleX() 13000 * @see #getScaleY() 13001 * @see #getPivotY() 13002 * @return The y location of the pivot point. 13003 * 13004 * @attr ref android.R.styleable#View_transformPivotY 13005 */ 13006 @ViewDebug.ExportedProperty(category = "drawing") 13007 public float getPivotY() { 13008 return mRenderNode.getPivotY(); 13009 } 13010 13011 /** 13012 * Sets the y location of the point around which the view is {@link #setRotation(float) rotated} 13013 * and {@link #setScaleY(float) scaled}. By default, the pivot point is centered on the object. 13014 * Setting this property disables this behavior and causes the view to use only the 13015 * explicitly set pivotX and pivotY values. 13016 * 13017 * @param pivotY The y location of the pivot point. 13018 * @see #getRotation() 13019 * @see #getScaleX() 13020 * @see #getScaleY() 13021 * @see #getPivotY() 13022 * 13023 * @attr ref android.R.styleable#View_transformPivotY 13024 */ 13025 public void setPivotY(float pivotY) { 13026 if (!mRenderNode.isPivotExplicitlySet() || pivotY != getPivotY()) { 13027 invalidateViewProperty(true, false); 13028 mRenderNode.setPivotY(pivotY); 13029 invalidateViewProperty(false, true); 13030 13031 invalidateParentIfNeededAndWasQuickRejected(); 13032 } 13033 } 13034 13035 /** 13036 * The opacity of the view. This is a value from 0 to 1, where 0 means the view is 13037 * completely transparent and 1 means the view is completely opaque. 13038 * 13039 * <p>By default this is 1.0f. 13040 * @return The opacity of the view. 13041 */ 13042 @ViewDebug.ExportedProperty(category = "drawing") 13043 public float getAlpha() { 13044 return mTransformationInfo != null ? mTransformationInfo.mAlpha : 1; 13045 } 13046 13047 /** 13048 * Sets the behavior for overlapping rendering for this view (see {@link 13049 * #hasOverlappingRendering()} for more details on this behavior). Calling this method 13050 * is an alternative to overriding {@link #hasOverlappingRendering()} in a subclass, 13051 * providing the value which is then used internally. That is, when {@link 13052 * #forceHasOverlappingRendering(boolean)} is called, the value of {@link 13053 * #hasOverlappingRendering()} is ignored and the value passed into this method is used 13054 * instead. 13055 * 13056 * @param hasOverlappingRendering The value for overlapping rendering to be used internally 13057 * instead of that returned by {@link #hasOverlappingRendering()}. 13058 * 13059 * @attr ref android.R.styleable#View_forceHasOverlappingRendering 13060 */ 13061 public void forceHasOverlappingRendering(boolean hasOverlappingRendering) { 13062 mPrivateFlags3 |= PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED; 13063 if (hasOverlappingRendering) { 13064 mPrivateFlags3 |= PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE; 13065 } else { 13066 mPrivateFlags3 &= ~PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE; 13067 } 13068 } 13069 13070 /** 13071 * Returns the value for overlapping rendering that is used internally. This is either 13072 * the value passed into {@link #forceHasOverlappingRendering(boolean)}, if called, or 13073 * the return value of {@link #hasOverlappingRendering()}, otherwise. 13074 * 13075 * @return The value for overlapping rendering being used internally. 13076 */ 13077 public final boolean getHasOverlappingRendering() { 13078 return (mPrivateFlags3 & PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED) != 0 ? 13079 (mPrivateFlags3 & PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE) != 0 : 13080 hasOverlappingRendering(); 13081 } 13082 13083 /** 13084 * Returns whether this View has content which overlaps. 13085 * 13086 * <p>This function, intended to be overridden by specific View types, is an optimization when 13087 * alpha is set on a view. If rendering overlaps in a view with alpha < 1, that view is drawn to 13088 * an offscreen buffer and then composited into place, which can be expensive. If the view has 13089 * no overlapping rendering, the view can draw each primitive with the appropriate alpha value 13090 * directly. An example of overlapping rendering is a TextView with a background image, such as 13091 * a Button. An example of non-overlapping rendering is a TextView with no background, or an 13092 * ImageView with only the foreground image. The default implementation returns true; subclasses 13093 * should override if they have cases which can be optimized.</p> 13094 * 13095 * <p>The current implementation of the saveLayer and saveLayerAlpha methods in {@link Canvas} 13096 * necessitates that a View return true if it uses the methods internally without passing the 13097 * {@link Canvas#CLIP_TO_LAYER_SAVE_FLAG}.</p> 13098 * 13099 * <p><strong>Note:</strong> The return value of this method is ignored if {@link 13100 * #forceHasOverlappingRendering(boolean)} has been called on this view.</p> 13101 * 13102 * @return true if the content in this view might overlap, false otherwise. 13103 */ 13104 @ViewDebug.ExportedProperty(category = "drawing") 13105 public boolean hasOverlappingRendering() { 13106 return true; 13107 } 13108 13109 /** 13110 * Sets the opacity of the view to a value from 0 to 1, where 0 means the view is 13111 * completely transparent and 1 means the view is completely opaque. 13112 * 13113 * <p class="note"><strong>Note:</strong> setting alpha to a translucent value (0 < alpha < 1) 13114 * can have significant performance implications, especially for large views. It is best to use 13115 * the alpha property sparingly and transiently, as in the case of fading animations.</p> 13116 * 13117 * <p>For a view with a frequently changing alpha, such as during a fading animation, it is 13118 * strongly recommended for performance reasons to either override 13119 * {@link #hasOverlappingRendering()} to return <code>false</code> if appropriate, or setting a 13120 * {@link #setLayerType(int, android.graphics.Paint) layer type} on the view for the duration 13121 * of the animation. On versions {@link android.os.Build.VERSION_CODES#M} and below, 13122 * the default path for rendering an unlayered View with alpha could add multiple milliseconds 13123 * of rendering cost, even for simple or small views. Starting with 13124 * {@link android.os.Build.VERSION_CODES#M}, {@link #LAYER_TYPE_HARDWARE} is automatically 13125 * applied to the view at the rendering level.</p> 13126 * 13127 * <p>If this view overrides {@link #onSetAlpha(int)} to return true, then this view is 13128 * responsible for applying the opacity itself.</p> 13129 * 13130 * <p>On versions {@link android.os.Build.VERSION_CODES#LOLLIPOP_MR1} and below, note that if 13131 * the view is backed by a {@link #setLayerType(int, android.graphics.Paint) layer} and is 13132 * associated with a {@link #setLayerPaint(android.graphics.Paint) layer paint}, setting an 13133 * alpha value less than 1.0 will supersede the alpha of the layer paint.</p> 13134 * 13135 * <p>Starting with {@link android.os.Build.VERSION_CODES#M}, setting a translucent alpha 13136 * value will clip a View to its bounds, unless the View returns <code>false</code> from 13137 * {@link #hasOverlappingRendering}.</p> 13138 * 13139 * @param alpha The opacity of the view. 13140 * 13141 * @see #hasOverlappingRendering() 13142 * @see #setLayerType(int, android.graphics.Paint) 13143 * 13144 * @attr ref android.R.styleable#View_alpha 13145 */ 13146 public void setAlpha(@FloatRange(from=0.0, to=1.0) float alpha) { 13147 ensureTransformationInfo(); 13148 if (mTransformationInfo.mAlpha != alpha) { 13149 // Report visibility changes, which can affect children, to accessibility 13150 if ((alpha == 0) ^ (mTransformationInfo.mAlpha == 0)) { 13151 notifySubtreeAccessibilityStateChangedIfNeeded(); 13152 } 13153 mTransformationInfo.mAlpha = alpha; 13154 if (onSetAlpha((int) (alpha * 255))) { 13155 mPrivateFlags |= PFLAG_ALPHA_SET; 13156 // subclass is handling alpha - don't optimize rendering cache invalidation 13157 invalidateParentCaches(); 13158 invalidate(true); 13159 } else { 13160 mPrivateFlags &= ~PFLAG_ALPHA_SET; 13161 invalidateViewProperty(true, false); 13162 mRenderNode.setAlpha(getFinalAlpha()); 13163 } 13164 } 13165 } 13166 13167 /** 13168 * Faster version of setAlpha() which performs the same steps except there are 13169 * no calls to invalidate(). The caller of this function should perform proper invalidation 13170 * on the parent and this object. The return value indicates whether the subclass handles 13171 * alpha (the return value for onSetAlpha()). 13172 * 13173 * @param alpha The new value for the alpha property 13174 * @return true if the View subclass handles alpha (the return value for onSetAlpha()) and 13175 * the new value for the alpha property is different from the old value 13176 */ 13177 boolean setAlphaNoInvalidation(float alpha) { 13178 ensureTransformationInfo(); 13179 if (mTransformationInfo.mAlpha != alpha) { 13180 mTransformationInfo.mAlpha = alpha; 13181 boolean subclassHandlesAlpha = onSetAlpha((int) (alpha * 255)); 13182 if (subclassHandlesAlpha) { 13183 mPrivateFlags |= PFLAG_ALPHA_SET; 13184 return true; 13185 } else { 13186 mPrivateFlags &= ~PFLAG_ALPHA_SET; 13187 mRenderNode.setAlpha(getFinalAlpha()); 13188 } 13189 } 13190 return false; 13191 } 13192 13193 /** 13194 * This property is hidden and intended only for use by the Fade transition, which 13195 * animates it to produce a visual translucency that does not side-effect (or get 13196 * affected by) the real alpha property. This value is composited with the other 13197 * alpha value (and the AlphaAnimation value, when that is present) to produce 13198 * a final visual translucency result, which is what is passed into the DisplayList. 13199 * 13200 * @hide 13201 */ 13202 public void setTransitionAlpha(float alpha) { 13203 ensureTransformationInfo(); 13204 if (mTransformationInfo.mTransitionAlpha != alpha) { 13205 mTransformationInfo.mTransitionAlpha = alpha; 13206 mPrivateFlags &= ~PFLAG_ALPHA_SET; 13207 invalidateViewProperty(true, false); 13208 mRenderNode.setAlpha(getFinalAlpha()); 13209 } 13210 } 13211 13212 /** 13213 * Calculates the visual alpha of this view, which is a combination of the actual 13214 * alpha value and the transitionAlpha value (if set). 13215 */ 13216 private float getFinalAlpha() { 13217 if (mTransformationInfo != null) { 13218 return mTransformationInfo.mAlpha * mTransformationInfo.mTransitionAlpha; 13219 } 13220 return 1; 13221 } 13222 13223 /** 13224 * This property is hidden and intended only for use by the Fade transition, which 13225 * animates it to produce a visual translucency that does not side-effect (or get 13226 * affected by) the real alpha property. This value is composited with the other 13227 * alpha value (and the AlphaAnimation value, when that is present) to produce 13228 * a final visual translucency result, which is what is passed into the DisplayList. 13229 * 13230 * @hide 13231 */ 13232 @ViewDebug.ExportedProperty(category = "drawing") 13233 public float getTransitionAlpha() { 13234 return mTransformationInfo != null ? mTransformationInfo.mTransitionAlpha : 1; 13235 } 13236 13237 /** 13238 * Top position of this view relative to its parent. 13239 * 13240 * @return The top of this view, in pixels. 13241 */ 13242 @ViewDebug.CapturedViewProperty 13243 public final int getTop() { 13244 return mTop; 13245 } 13246 13247 /** 13248 * Sets the top position of this view relative to its parent. This method is meant to be called 13249 * by the layout system and should not generally be called otherwise, because the property 13250 * may be changed at any time by the layout. 13251 * 13252 * @param top The top of this view, in pixels. 13253 */ 13254 public final void setTop(int top) { 13255 if (top != mTop) { 13256 final boolean matrixIsIdentity = hasIdentityMatrix(); 13257 if (matrixIsIdentity) { 13258 if (mAttachInfo != null) { 13259 int minTop; 13260 int yLoc; 13261 if (top < mTop) { 13262 minTop = top; 13263 yLoc = top - mTop; 13264 } else { 13265 minTop = mTop; 13266 yLoc = 0; 13267 } 13268 invalidate(0, yLoc, mRight - mLeft, mBottom - minTop); 13269 } 13270 } else { 13271 // Double-invalidation is necessary to capture view's old and new areas 13272 invalidate(true); 13273 } 13274 13275 int width = mRight - mLeft; 13276 int oldHeight = mBottom - mTop; 13277 13278 mTop = top; 13279 mRenderNode.setTop(mTop); 13280 13281 sizeChange(width, mBottom - mTop, width, oldHeight); 13282 13283 if (!matrixIsIdentity) { 13284 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 13285 invalidate(true); 13286 } 13287 mBackgroundSizeChanged = true; 13288 if (mForegroundInfo != null) { 13289 mForegroundInfo.mBoundsChanged = true; 13290 } 13291 invalidateParentIfNeeded(); 13292 if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) { 13293 // View was rejected last time it was drawn by its parent; this may have changed 13294 invalidateParentIfNeeded(); 13295 } 13296 } 13297 } 13298 13299 /** 13300 * Bottom position of this view relative to its parent. 13301 * 13302 * @return The bottom of this view, in pixels. 13303 */ 13304 @ViewDebug.CapturedViewProperty 13305 public final int getBottom() { 13306 return mBottom; 13307 } 13308 13309 /** 13310 * True if this view has changed since the last time being drawn. 13311 * 13312 * @return The dirty state of this view. 13313 */ 13314 public boolean isDirty() { 13315 return (mPrivateFlags & PFLAG_DIRTY_MASK) != 0; 13316 } 13317 13318 /** 13319 * Sets the bottom position of this view relative to its parent. This method is meant to be 13320 * called by the layout system and should not generally be called otherwise, because the 13321 * property may be changed at any time by the layout. 13322 * 13323 * @param bottom The bottom of this view, in pixels. 13324 */ 13325 public final void setBottom(int bottom) { 13326 if (bottom != mBottom) { 13327 final boolean matrixIsIdentity = hasIdentityMatrix(); 13328 if (matrixIsIdentity) { 13329 if (mAttachInfo != null) { 13330 int maxBottom; 13331 if (bottom < mBottom) { 13332 maxBottom = mBottom; 13333 } else { 13334 maxBottom = bottom; 13335 } 13336 invalidate(0, 0, mRight - mLeft, maxBottom - mTop); 13337 } 13338 } else { 13339 // Double-invalidation is necessary to capture view's old and new areas 13340 invalidate(true); 13341 } 13342 13343 int width = mRight - mLeft; 13344 int oldHeight = mBottom - mTop; 13345 13346 mBottom = bottom; 13347 mRenderNode.setBottom(mBottom); 13348 13349 sizeChange(width, mBottom - mTop, width, oldHeight); 13350 13351 if (!matrixIsIdentity) { 13352 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 13353 invalidate(true); 13354 } 13355 mBackgroundSizeChanged = true; 13356 if (mForegroundInfo != null) { 13357 mForegroundInfo.mBoundsChanged = true; 13358 } 13359 invalidateParentIfNeeded(); 13360 if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) { 13361 // View was rejected last time it was drawn by its parent; this may have changed 13362 invalidateParentIfNeeded(); 13363 } 13364 } 13365 } 13366 13367 /** 13368 * Left position of this view relative to its parent. 13369 * 13370 * @return The left edge of this view, in pixels. 13371 */ 13372 @ViewDebug.CapturedViewProperty 13373 public final int getLeft() { 13374 return mLeft; 13375 } 13376 13377 /** 13378 * Sets the left position of this view relative to its parent. This method is meant to be called 13379 * by the layout system and should not generally be called otherwise, because the property 13380 * may be changed at any time by the layout. 13381 * 13382 * @param left The left of this view, in pixels. 13383 */ 13384 public final void setLeft(int left) { 13385 if (left != mLeft) { 13386 final boolean matrixIsIdentity = hasIdentityMatrix(); 13387 if (matrixIsIdentity) { 13388 if (mAttachInfo != null) { 13389 int minLeft; 13390 int xLoc; 13391 if (left < mLeft) { 13392 minLeft = left; 13393 xLoc = left - mLeft; 13394 } else { 13395 minLeft = mLeft; 13396 xLoc = 0; 13397 } 13398 invalidate(xLoc, 0, mRight - minLeft, mBottom - mTop); 13399 } 13400 } else { 13401 // Double-invalidation is necessary to capture view's old and new areas 13402 invalidate(true); 13403 } 13404 13405 int oldWidth = mRight - mLeft; 13406 int height = mBottom - mTop; 13407 13408 mLeft = left; 13409 mRenderNode.setLeft(left); 13410 13411 sizeChange(mRight - mLeft, height, oldWidth, height); 13412 13413 if (!matrixIsIdentity) { 13414 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 13415 invalidate(true); 13416 } 13417 mBackgroundSizeChanged = true; 13418 if (mForegroundInfo != null) { 13419 mForegroundInfo.mBoundsChanged = true; 13420 } 13421 invalidateParentIfNeeded(); 13422 if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) { 13423 // View was rejected last time it was drawn by its parent; this may have changed 13424 invalidateParentIfNeeded(); 13425 } 13426 } 13427 } 13428 13429 /** 13430 * Right position of this view relative to its parent. 13431 * 13432 * @return The right edge of this view, in pixels. 13433 */ 13434 @ViewDebug.CapturedViewProperty 13435 public final int getRight() { 13436 return mRight; 13437 } 13438 13439 /** 13440 * Sets the right position of this view relative to its parent. This method is meant to be called 13441 * by the layout system and should not generally be called otherwise, because the property 13442 * may be changed at any time by the layout. 13443 * 13444 * @param right The right of this view, in pixels. 13445 */ 13446 public final void setRight(int right) { 13447 if (right != mRight) { 13448 final boolean matrixIsIdentity = hasIdentityMatrix(); 13449 if (matrixIsIdentity) { 13450 if (mAttachInfo != null) { 13451 int maxRight; 13452 if (right < mRight) { 13453 maxRight = mRight; 13454 } else { 13455 maxRight = right; 13456 } 13457 invalidate(0, 0, maxRight - mLeft, mBottom - mTop); 13458 } 13459 } else { 13460 // Double-invalidation is necessary to capture view's old and new areas 13461 invalidate(true); 13462 } 13463 13464 int oldWidth = mRight - mLeft; 13465 int height = mBottom - mTop; 13466 13467 mRight = right; 13468 mRenderNode.setRight(mRight); 13469 13470 sizeChange(mRight - mLeft, height, oldWidth, height); 13471 13472 if (!matrixIsIdentity) { 13473 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 13474 invalidate(true); 13475 } 13476 mBackgroundSizeChanged = true; 13477 if (mForegroundInfo != null) { 13478 mForegroundInfo.mBoundsChanged = true; 13479 } 13480 invalidateParentIfNeeded(); 13481 if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) { 13482 // View was rejected last time it was drawn by its parent; this may have changed 13483 invalidateParentIfNeeded(); 13484 } 13485 } 13486 } 13487 13488 /** 13489 * The visual x position of this view, in pixels. This is equivalent to the 13490 * {@link #setTranslationX(float) translationX} property plus the current 13491 * {@link #getLeft() left} property. 13492 * 13493 * @return The visual x position of this view, in pixels. 13494 */ 13495 @ViewDebug.ExportedProperty(category = "drawing") 13496 public float getX() { 13497 return mLeft + getTranslationX(); 13498 } 13499 13500 /** 13501 * Sets the visual x position of this view, in pixels. This is equivalent to setting the 13502 * {@link #setTranslationX(float) translationX} property to be the difference between 13503 * the x value passed in and the current {@link #getLeft() left} property. 13504 * 13505 * @param x The visual x position of this view, in pixels. 13506 */ 13507 public void setX(float x) { 13508 setTranslationX(x - mLeft); 13509 } 13510 13511 /** 13512 * The visual y position of this view, in pixels. This is equivalent to the 13513 * {@link #setTranslationY(float) translationY} property plus the current 13514 * {@link #getTop() top} property. 13515 * 13516 * @return The visual y position of this view, in pixels. 13517 */ 13518 @ViewDebug.ExportedProperty(category = "drawing") 13519 public float getY() { 13520 return mTop + getTranslationY(); 13521 } 13522 13523 /** 13524 * Sets the visual y position of this view, in pixels. This is equivalent to setting the 13525 * {@link #setTranslationY(float) translationY} property to be the difference between 13526 * the y value passed in and the current {@link #getTop() top} property. 13527 * 13528 * @param y The visual y position of this view, in pixels. 13529 */ 13530 public void setY(float y) { 13531 setTranslationY(y - mTop); 13532 } 13533 13534 /** 13535 * The visual z position of this view, in pixels. This is equivalent to the 13536 * {@link #setTranslationZ(float) translationZ} property plus the current 13537 * {@link #getElevation() elevation} property. 13538 * 13539 * @return The visual z position of this view, in pixels. 13540 */ 13541 @ViewDebug.ExportedProperty(category = "drawing") 13542 public float getZ() { 13543 return getElevation() + getTranslationZ(); 13544 } 13545 13546 /** 13547 * Sets the visual z position of this view, in pixels. This is equivalent to setting the 13548 * {@link #setTranslationZ(float) translationZ} property to be the difference between 13549 * the x value passed in and the current {@link #getElevation() elevation} property. 13550 * 13551 * @param z The visual z position of this view, in pixels. 13552 */ 13553 public void setZ(float z) { 13554 setTranslationZ(z - getElevation()); 13555 } 13556 13557 /** 13558 * The base elevation of this view relative to its parent, in pixels. 13559 * 13560 * @return The base depth position of the view, in pixels. 13561 */ 13562 @ViewDebug.ExportedProperty(category = "drawing") 13563 public float getElevation() { 13564 return mRenderNode.getElevation(); 13565 } 13566 13567 /** 13568 * Sets the base elevation of this view, in pixels. 13569 * 13570 * @attr ref android.R.styleable#View_elevation 13571 */ 13572 public void setElevation(float elevation) { 13573 if (elevation != getElevation()) { 13574 invalidateViewProperty(true, false); 13575 mRenderNode.setElevation(elevation); 13576 invalidateViewProperty(false, true); 13577 13578 invalidateParentIfNeededAndWasQuickRejected(); 13579 } 13580 } 13581 13582 /** 13583 * The horizontal location of this view relative to its {@link #getLeft() left} position. 13584 * This position is post-layout, in addition to wherever the object's 13585 * layout placed it. 13586 * 13587 * @return The horizontal position of this view relative to its left position, in pixels. 13588 */ 13589 @ViewDebug.ExportedProperty(category = "drawing") 13590 public float getTranslationX() { 13591 return mRenderNode.getTranslationX(); 13592 } 13593 13594 /** 13595 * Sets the horizontal location of this view relative to its {@link #getLeft() left} position. 13596 * This effectively positions the object post-layout, in addition to wherever the object's 13597 * layout placed it. 13598 * 13599 * @param translationX The horizontal position of this view relative to its left position, 13600 * in pixels. 13601 * 13602 * @attr ref android.R.styleable#View_translationX 13603 */ 13604 public void setTranslationX(float translationX) { 13605 if (translationX != getTranslationX()) { 13606 invalidateViewProperty(true, false); 13607 mRenderNode.setTranslationX(translationX); 13608 invalidateViewProperty(false, true); 13609 13610 invalidateParentIfNeededAndWasQuickRejected(); 13611 notifySubtreeAccessibilityStateChangedIfNeeded(); 13612 } 13613 } 13614 13615 /** 13616 * The vertical location of this view relative to its {@link #getTop() top} position. 13617 * This position is post-layout, in addition to wherever the object's 13618 * layout placed it. 13619 * 13620 * @return The vertical position of this view relative to its top position, 13621 * in pixels. 13622 */ 13623 @ViewDebug.ExportedProperty(category = "drawing") 13624 public float getTranslationY() { 13625 return mRenderNode.getTranslationY(); 13626 } 13627 13628 /** 13629 * Sets the vertical location of this view relative to its {@link #getTop() top} position. 13630 * This effectively positions the object post-layout, in addition to wherever the object's 13631 * layout placed it. 13632 * 13633 * @param translationY The vertical position of this view relative to its top position, 13634 * in pixels. 13635 * 13636 * @attr ref android.R.styleable#View_translationY 13637 */ 13638 public void setTranslationY(float translationY) { 13639 if (translationY != getTranslationY()) { 13640 invalidateViewProperty(true, false); 13641 mRenderNode.setTranslationY(translationY); 13642 invalidateViewProperty(false, true); 13643 13644 invalidateParentIfNeededAndWasQuickRejected(); 13645 notifySubtreeAccessibilityStateChangedIfNeeded(); 13646 } 13647 } 13648 13649 /** 13650 * The depth location of this view relative to its {@link #getElevation() elevation}. 13651 * 13652 * @return The depth of this view relative to its elevation. 13653 */ 13654 @ViewDebug.ExportedProperty(category = "drawing") 13655 public float getTranslationZ() { 13656 return mRenderNode.getTranslationZ(); 13657 } 13658 13659 /** 13660 * Sets the depth location of this view relative to its {@link #getElevation() elevation}. 13661 * 13662 * @attr ref android.R.styleable#View_translationZ 13663 */ 13664 public void setTranslationZ(float translationZ) { 13665 if (translationZ != getTranslationZ()) { 13666 invalidateViewProperty(true, false); 13667 mRenderNode.setTranslationZ(translationZ); 13668 invalidateViewProperty(false, true); 13669 13670 invalidateParentIfNeededAndWasQuickRejected(); 13671 } 13672 } 13673 13674 /** @hide */ 13675 public void setAnimationMatrix(Matrix matrix) { 13676 invalidateViewProperty(true, false); 13677 mRenderNode.setAnimationMatrix(matrix); 13678 invalidateViewProperty(false, true); 13679 13680 invalidateParentIfNeededAndWasQuickRejected(); 13681 } 13682 13683 /** 13684 * Returns the current StateListAnimator if exists. 13685 * 13686 * @return StateListAnimator or null if it does not exists 13687 * @see #setStateListAnimator(android.animation.StateListAnimator) 13688 */ 13689 public StateListAnimator getStateListAnimator() { 13690 return mStateListAnimator; 13691 } 13692 13693 /** 13694 * Attaches the provided StateListAnimator to this View. 13695 * <p> 13696 * Any previously attached StateListAnimator will be detached. 13697 * 13698 * @param stateListAnimator The StateListAnimator to update the view 13699 * @see android.animation.StateListAnimator 13700 */ 13701 public void setStateListAnimator(StateListAnimator stateListAnimator) { 13702 if (mStateListAnimator == stateListAnimator) { 13703 return; 13704 } 13705 if (mStateListAnimator != null) { 13706 mStateListAnimator.setTarget(null); 13707 } 13708 mStateListAnimator = stateListAnimator; 13709 if (stateListAnimator != null) { 13710 stateListAnimator.setTarget(this); 13711 if (isAttachedToWindow()) { 13712 stateListAnimator.setState(getDrawableState()); 13713 } 13714 } 13715 } 13716 13717 /** 13718 * Returns whether the Outline should be used to clip the contents of the View. 13719 * <p> 13720 * Note that this flag will only be respected if the View's Outline returns true from 13721 * {@link Outline#canClip()}. 13722 * 13723 * @see #setOutlineProvider(ViewOutlineProvider) 13724 * @see #setClipToOutline(boolean) 13725 */ 13726 public final boolean getClipToOutline() { 13727 return mRenderNode.getClipToOutline(); 13728 } 13729 13730 /** 13731 * Sets whether the View's Outline should be used to clip the contents of the View. 13732 * <p> 13733 * Only a single non-rectangular clip can be applied on a View at any time. 13734 * Circular clips from a {@link ViewAnimationUtils#createCircularReveal(View, int, int, float, float) 13735 * circular reveal} animation take priority over Outline clipping, and 13736 * child Outline clipping takes priority over Outline clipping done by a 13737 * parent. 13738 * <p> 13739 * Note that this flag will only be respected if the View's Outline returns true from 13740 * {@link Outline#canClip()}. 13741 * 13742 * @see #setOutlineProvider(ViewOutlineProvider) 13743 * @see #getClipToOutline() 13744 */ 13745 public void setClipToOutline(boolean clipToOutline) { 13746 damageInParent(); 13747 if (getClipToOutline() != clipToOutline) { 13748 mRenderNode.setClipToOutline(clipToOutline); 13749 } 13750 } 13751 13752 // correspond to the enum values of View_outlineProvider 13753 private static final int PROVIDER_BACKGROUND = 0; 13754 private static final int PROVIDER_NONE = 1; 13755 private static final int PROVIDER_BOUNDS = 2; 13756 private static final int PROVIDER_PADDED_BOUNDS = 3; 13757 private void setOutlineProviderFromAttribute(int providerInt) { 13758 switch (providerInt) { 13759 case PROVIDER_BACKGROUND: 13760 setOutlineProvider(ViewOutlineProvider.BACKGROUND); 13761 break; 13762 case PROVIDER_NONE: 13763 setOutlineProvider(null); 13764 break; 13765 case PROVIDER_BOUNDS: 13766 setOutlineProvider(ViewOutlineProvider.BOUNDS); 13767 break; 13768 case PROVIDER_PADDED_BOUNDS: 13769 setOutlineProvider(ViewOutlineProvider.PADDED_BOUNDS); 13770 break; 13771 } 13772 } 13773 13774 /** 13775 * Sets the {@link ViewOutlineProvider} of the view, which generates the Outline that defines 13776 * the shape of the shadow it casts, and enables outline clipping. 13777 * <p> 13778 * The default ViewOutlineProvider, {@link ViewOutlineProvider#BACKGROUND}, queries the Outline 13779 * from the View's background drawable, via {@link Drawable#getOutline(Outline)}. Changing the 13780 * outline provider with this method allows this behavior to be overridden. 13781 * <p> 13782 * If the ViewOutlineProvider is null, if querying it for an outline returns false, 13783 * or if the produced Outline is {@link Outline#isEmpty()}, shadows will not be cast. 13784 * <p> 13785 * Only outlines that return true from {@link Outline#canClip()} may be used for clipping. 13786 * 13787 * @see #setClipToOutline(boolean) 13788 * @see #getClipToOutline() 13789 * @see #getOutlineProvider() 13790 */ 13791 public void setOutlineProvider(ViewOutlineProvider provider) { 13792 mOutlineProvider = provider; 13793 invalidateOutline(); 13794 } 13795 13796 /** 13797 * Returns the current {@link ViewOutlineProvider} of the view, which generates the Outline 13798 * that defines the shape of the shadow it casts, and enables outline clipping. 13799 * 13800 * @see #setOutlineProvider(ViewOutlineProvider) 13801 */ 13802 public ViewOutlineProvider getOutlineProvider() { 13803 return mOutlineProvider; 13804 } 13805 13806 /** 13807 * Called to rebuild this View's Outline from its {@link ViewOutlineProvider outline provider} 13808 * 13809 * @see #setOutlineProvider(ViewOutlineProvider) 13810 */ 13811 public void invalidateOutline() { 13812 rebuildOutline(); 13813 13814 notifySubtreeAccessibilityStateChangedIfNeeded(); 13815 invalidateViewProperty(false, false); 13816 } 13817 13818 /** 13819 * Internal version of {@link #invalidateOutline()} which invalidates the 13820 * outline without invalidating the view itself. This is intended to be called from 13821 * within methods in the View class itself which are the result of the view being 13822 * invalidated already. For example, when we are drawing the background of a View, 13823 * we invalidate the outline in case it changed in the meantime, but we do not 13824 * need to invalidate the view because we're already drawing the background as part 13825 * of drawing the view in response to an earlier invalidation of the view. 13826 */ 13827 private void rebuildOutline() { 13828 // Unattached views ignore this signal, and outline is recomputed in onAttachedToWindow() 13829 if (mAttachInfo == null) return; 13830 13831 if (mOutlineProvider == null) { 13832 // no provider, remove outline 13833 mRenderNode.setOutline(null); 13834 } else { 13835 final Outline outline = mAttachInfo.mTmpOutline; 13836 outline.setEmpty(); 13837 outline.setAlpha(1.0f); 13838 13839 mOutlineProvider.getOutline(this, outline); 13840 mRenderNode.setOutline(outline); 13841 } 13842 } 13843 13844 /** 13845 * HierarchyViewer only 13846 * 13847 * @hide 13848 */ 13849 @ViewDebug.ExportedProperty(category = "drawing") 13850 public boolean hasShadow() { 13851 return mRenderNode.hasShadow(); 13852 } 13853 13854 13855 /** @hide */ 13856 public void setRevealClip(boolean shouldClip, float x, float y, float radius) { 13857 mRenderNode.setRevealClip(shouldClip, x, y, radius); 13858 invalidateViewProperty(false, false); 13859 } 13860 13861 /** 13862 * Hit rectangle in parent's coordinates 13863 * 13864 * @param outRect The hit rectangle of the view. 13865 */ 13866 public void getHitRect(Rect outRect) { 13867 if (hasIdentityMatrix() || mAttachInfo == null) { 13868 outRect.set(mLeft, mTop, mRight, mBottom); 13869 } else { 13870 final RectF tmpRect = mAttachInfo.mTmpTransformRect; 13871 tmpRect.set(0, 0, getWidth(), getHeight()); 13872 getMatrix().mapRect(tmpRect); // TODO: mRenderNode.mapRect(tmpRect) 13873 outRect.set((int) tmpRect.left + mLeft, (int) tmpRect.top + mTop, 13874 (int) tmpRect.right + mLeft, (int) tmpRect.bottom + mTop); 13875 } 13876 } 13877 13878 /** 13879 * Determines whether the given point, in local coordinates is inside the view. 13880 */ 13881 /*package*/ final boolean pointInView(float localX, float localY) { 13882 return pointInView(localX, localY, 0); 13883 } 13884 13885 /** 13886 * Utility method to determine whether the given point, in local coordinates, 13887 * is inside the view, where the area of the view is expanded by the slop factor. 13888 * This method is called while processing touch-move events to determine if the event 13889 * is still within the view. 13890 * 13891 * @hide 13892 */ 13893 public boolean pointInView(float localX, float localY, float slop) { 13894 return localX >= -slop && localY >= -slop && localX < ((mRight - mLeft) + slop) && 13895 localY < ((mBottom - mTop) + slop); 13896 } 13897 13898 /** 13899 * When a view has focus and the user navigates away from it, the next view is searched for 13900 * starting from the rectangle filled in by this method. 13901 * 13902 * By default, the rectangle is the {@link #getDrawingRect(android.graphics.Rect)}) 13903 * of the view. However, if your view maintains some idea of internal selection, 13904 * such as a cursor, or a selected row or column, you should override this method and 13905 * fill in a more specific rectangle. 13906 * 13907 * @param r The rectangle to fill in, in this view's coordinates. 13908 */ 13909 public void getFocusedRect(Rect r) { 13910 getDrawingRect(r); 13911 } 13912 13913 /** 13914 * If some part of this view is not clipped by any of its parents, then 13915 * return that area in r in global (root) coordinates. To convert r to local 13916 * coordinates (without taking possible View rotations into account), offset 13917 * it by -globalOffset (e.g. r.offset(-globalOffset.x, -globalOffset.y)). 13918 * If the view is completely clipped or translated out, return false. 13919 * 13920 * @param r If true is returned, r holds the global coordinates of the 13921 * visible portion of this view. 13922 * @param globalOffset If true is returned, globalOffset holds the dx,dy 13923 * between this view and its root. globalOffet may be null. 13924 * @return true if r is non-empty (i.e. part of the view is visible at the 13925 * root level. 13926 */ 13927 public boolean getGlobalVisibleRect(Rect r, Point globalOffset) { 13928 int width = mRight - mLeft; 13929 int height = mBottom - mTop; 13930 if (width > 0 && height > 0) { 13931 r.set(0, 0, width, height); 13932 if (globalOffset != null) { 13933 globalOffset.set(-mScrollX, -mScrollY); 13934 } 13935 return mParent == null || mParent.getChildVisibleRect(this, r, globalOffset); 13936 } 13937 return false; 13938 } 13939 13940 public final boolean getGlobalVisibleRect(Rect r) { 13941 return getGlobalVisibleRect(r, null); 13942 } 13943 13944 public final boolean getLocalVisibleRect(Rect r) { 13945 final Point offset = mAttachInfo != null ? mAttachInfo.mPoint : new Point(); 13946 if (getGlobalVisibleRect(r, offset)) { 13947 r.offset(-offset.x, -offset.y); // make r local 13948 return true; 13949 } 13950 return false; 13951 } 13952 13953 /** 13954 * Offset this view's vertical location by the specified number of pixels. 13955 * 13956 * @param offset the number of pixels to offset the view by 13957 */ 13958 public void offsetTopAndBottom(int offset) { 13959 if (offset != 0) { 13960 final boolean matrixIsIdentity = hasIdentityMatrix(); 13961 if (matrixIsIdentity) { 13962 if (isHardwareAccelerated()) { 13963 invalidateViewProperty(false, false); 13964 } else { 13965 final ViewParent p = mParent; 13966 if (p != null && mAttachInfo != null) { 13967 final Rect r = mAttachInfo.mTmpInvalRect; 13968 int minTop; 13969 int maxBottom; 13970 int yLoc; 13971 if (offset < 0) { 13972 minTop = mTop + offset; 13973 maxBottom = mBottom; 13974 yLoc = offset; 13975 } else { 13976 minTop = mTop; 13977 maxBottom = mBottom + offset; 13978 yLoc = 0; 13979 } 13980 r.set(0, yLoc, mRight - mLeft, maxBottom - minTop); 13981 p.invalidateChild(this, r); 13982 } 13983 } 13984 } else { 13985 invalidateViewProperty(false, false); 13986 } 13987 13988 mTop += offset; 13989 mBottom += offset; 13990 mRenderNode.offsetTopAndBottom(offset); 13991 if (isHardwareAccelerated()) { 13992 invalidateViewProperty(false, false); 13993 invalidateParentIfNeededAndWasQuickRejected(); 13994 } else { 13995 if (!matrixIsIdentity) { 13996 invalidateViewProperty(false, true); 13997 } 13998 invalidateParentIfNeeded(); 13999 } 14000 notifySubtreeAccessibilityStateChangedIfNeeded(); 14001 } 14002 } 14003 14004 /** 14005 * Offset this view's horizontal location by the specified amount of pixels. 14006 * 14007 * @param offset the number of pixels to offset the view by 14008 */ 14009 public void offsetLeftAndRight(int offset) { 14010 if (offset != 0) { 14011 final boolean matrixIsIdentity = hasIdentityMatrix(); 14012 if (matrixIsIdentity) { 14013 if (isHardwareAccelerated()) { 14014 invalidateViewProperty(false, false); 14015 } else { 14016 final ViewParent p = mParent; 14017 if (p != null && mAttachInfo != null) { 14018 final Rect r = mAttachInfo.mTmpInvalRect; 14019 int minLeft; 14020 int maxRight; 14021 if (offset < 0) { 14022 minLeft = mLeft + offset; 14023 maxRight = mRight; 14024 } else { 14025 minLeft = mLeft; 14026 maxRight = mRight + offset; 14027 } 14028 r.set(0, 0, maxRight - minLeft, mBottom - mTop); 14029 p.invalidateChild(this, r); 14030 } 14031 } 14032 } else { 14033 invalidateViewProperty(false, false); 14034 } 14035 14036 mLeft += offset; 14037 mRight += offset; 14038 mRenderNode.offsetLeftAndRight(offset); 14039 if (isHardwareAccelerated()) { 14040 invalidateViewProperty(false, false); 14041 invalidateParentIfNeededAndWasQuickRejected(); 14042 } else { 14043 if (!matrixIsIdentity) { 14044 invalidateViewProperty(false, true); 14045 } 14046 invalidateParentIfNeeded(); 14047 } 14048 notifySubtreeAccessibilityStateChangedIfNeeded(); 14049 } 14050 } 14051 14052 /** 14053 * Get the LayoutParams associated with this view. All views should have 14054 * layout parameters. These supply parameters to the <i>parent</i> of this 14055 * view specifying how it should be arranged. There are many subclasses of 14056 * ViewGroup.LayoutParams, and these correspond to the different subclasses 14057 * of ViewGroup that are responsible for arranging their children. 14058 * 14059 * This method may return null if this View is not attached to a parent 14060 * ViewGroup or {@link #setLayoutParams(android.view.ViewGroup.LayoutParams)} 14061 * was not invoked successfully. When a View is attached to a parent 14062 * ViewGroup, this method must not return null. 14063 * 14064 * @return The LayoutParams associated with this view, or null if no 14065 * parameters have been set yet 14066 */ 14067 @ViewDebug.ExportedProperty(deepExport = true, prefix = "layout_") 14068 public ViewGroup.LayoutParams getLayoutParams() { 14069 return mLayoutParams; 14070 } 14071 14072 /** 14073 * Set the layout parameters associated with this view. These supply 14074 * parameters to the <i>parent</i> of this view specifying how it should be 14075 * arranged. There are many subclasses of ViewGroup.LayoutParams, and these 14076 * correspond to the different subclasses of ViewGroup that are responsible 14077 * for arranging their children. 14078 * 14079 * @param params The layout parameters for this view, cannot be null 14080 */ 14081 public void setLayoutParams(ViewGroup.LayoutParams params) { 14082 if (params == null) { 14083 throw new NullPointerException("Layout parameters cannot be null"); 14084 } 14085 mLayoutParams = params; 14086 resolveLayoutParams(); 14087 if (mParent instanceof ViewGroup) { 14088 ((ViewGroup) mParent).onSetLayoutParams(this, params); 14089 } 14090 requestLayout(); 14091 } 14092 14093 /** 14094 * Resolve the layout parameters depending on the resolved layout direction 14095 * 14096 * @hide 14097 */ 14098 public void resolveLayoutParams() { 14099 if (mLayoutParams != null) { 14100 mLayoutParams.resolveLayoutDirection(getLayoutDirection()); 14101 } 14102 } 14103 14104 /** 14105 * Set the scrolled position of your view. This will cause a call to 14106 * {@link #onScrollChanged(int, int, int, int)} and the view will be 14107 * invalidated. 14108 * @param x the x position to scroll to 14109 * @param y the y position to scroll to 14110 */ 14111 public void scrollTo(int x, int y) { 14112 if (mScrollX != x || mScrollY != y) { 14113 int oldX = mScrollX; 14114 int oldY = mScrollY; 14115 mScrollX = x; 14116 mScrollY = y; 14117 invalidateParentCaches(); 14118 onScrollChanged(mScrollX, mScrollY, oldX, oldY); 14119 if (!awakenScrollBars()) { 14120 postInvalidateOnAnimation(); 14121 } 14122 } 14123 } 14124 14125 /** 14126 * Move the scrolled position of your view. This will cause a call to 14127 * {@link #onScrollChanged(int, int, int, int)} and the view will be 14128 * invalidated. 14129 * @param x the amount of pixels to scroll by horizontally 14130 * @param y the amount of pixels to scroll by vertically 14131 */ 14132 public void scrollBy(int x, int y) { 14133 scrollTo(mScrollX + x, mScrollY + y); 14134 } 14135 14136 /** 14137 * <p>Trigger the scrollbars to draw. When invoked this method starts an 14138 * animation to fade the scrollbars out after a default delay. If a subclass 14139 * provides animated scrolling, the start delay should equal the duration 14140 * of the scrolling animation.</p> 14141 * 14142 * <p>The animation starts only if at least one of the scrollbars is 14143 * enabled, as specified by {@link #isHorizontalScrollBarEnabled()} and 14144 * {@link #isVerticalScrollBarEnabled()}. When the animation is started, 14145 * this method returns true, and false otherwise. If the animation is 14146 * started, this method calls {@link #invalidate()}; in that case the 14147 * caller should not call {@link #invalidate()}.</p> 14148 * 14149 * <p>This method should be invoked every time a subclass directly updates 14150 * the scroll parameters.</p> 14151 * 14152 * <p>This method is automatically invoked by {@link #scrollBy(int, int)} 14153 * and {@link #scrollTo(int, int)}.</p> 14154 * 14155 * @return true if the animation is played, false otherwise 14156 * 14157 * @see #awakenScrollBars(int) 14158 * @see #scrollBy(int, int) 14159 * @see #scrollTo(int, int) 14160 * @see #isHorizontalScrollBarEnabled() 14161 * @see #isVerticalScrollBarEnabled() 14162 * @see #setHorizontalScrollBarEnabled(boolean) 14163 * @see #setVerticalScrollBarEnabled(boolean) 14164 */ 14165 protected boolean awakenScrollBars() { 14166 return mScrollCache != null && 14167 awakenScrollBars(mScrollCache.scrollBarDefaultDelayBeforeFade, true); 14168 } 14169 14170 /** 14171 * Trigger the scrollbars to draw. 14172 * This method differs from awakenScrollBars() only in its default duration. 14173 * initialAwakenScrollBars() will show the scroll bars for longer than 14174 * usual to give the user more of a chance to notice them. 14175 * 14176 * @return true if the animation is played, false otherwise. 14177 */ 14178 private boolean initialAwakenScrollBars() { 14179 return mScrollCache != null && 14180 awakenScrollBars(mScrollCache.scrollBarDefaultDelayBeforeFade * 4, true); 14181 } 14182 14183 /** 14184 * <p> 14185 * Trigger the scrollbars to draw. When invoked this method starts an 14186 * animation to fade the scrollbars out after a fixed delay. If a subclass 14187 * provides animated scrolling, the start delay should equal the duration of 14188 * the scrolling animation. 14189 * </p> 14190 * 14191 * <p> 14192 * The animation starts only if at least one of the scrollbars is enabled, 14193 * as specified by {@link #isHorizontalScrollBarEnabled()} and 14194 * {@link #isVerticalScrollBarEnabled()}. When the animation is started, 14195 * this method returns true, and false otherwise. If the animation is 14196 * started, this method calls {@link #invalidate()}; in that case the caller 14197 * should not call {@link #invalidate()}. 14198 * </p> 14199 * 14200 * <p> 14201 * This method should be invoked every time a subclass directly updates the 14202 * scroll parameters. 14203 * </p> 14204 * 14205 * @param startDelay the delay, in milliseconds, after which the animation 14206 * should start; when the delay is 0, the animation starts 14207 * immediately 14208 * @return true if the animation is played, false otherwise 14209 * 14210 * @see #scrollBy(int, int) 14211 * @see #scrollTo(int, int) 14212 * @see #isHorizontalScrollBarEnabled() 14213 * @see #isVerticalScrollBarEnabled() 14214 * @see #setHorizontalScrollBarEnabled(boolean) 14215 * @see #setVerticalScrollBarEnabled(boolean) 14216 */ 14217 protected boolean awakenScrollBars(int startDelay) { 14218 return awakenScrollBars(startDelay, true); 14219 } 14220 14221 /** 14222 * <p> 14223 * Trigger the scrollbars to draw. When invoked this method starts an 14224 * animation to fade the scrollbars out after a fixed delay. If a subclass 14225 * provides animated scrolling, the start delay should equal the duration of 14226 * the scrolling animation. 14227 * </p> 14228 * 14229 * <p> 14230 * The animation starts only if at least one of the scrollbars is enabled, 14231 * as specified by {@link #isHorizontalScrollBarEnabled()} and 14232 * {@link #isVerticalScrollBarEnabled()}. When the animation is started, 14233 * this method returns true, and false otherwise. If the animation is 14234 * started, this method calls {@link #invalidate()} if the invalidate parameter 14235 * is set to true; in that case the caller 14236 * should not call {@link #invalidate()}. 14237 * </p> 14238 * 14239 * <p> 14240 * This method should be invoked every time a subclass directly updates the 14241 * scroll parameters. 14242 * </p> 14243 * 14244 * @param startDelay the delay, in milliseconds, after which the animation 14245 * should start; when the delay is 0, the animation starts 14246 * immediately 14247 * 14248 * @param invalidate Whether this method should call invalidate 14249 * 14250 * @return true if the animation is played, false otherwise 14251 * 14252 * @see #scrollBy(int, int) 14253 * @see #scrollTo(int, int) 14254 * @see #isHorizontalScrollBarEnabled() 14255 * @see #isVerticalScrollBarEnabled() 14256 * @see #setHorizontalScrollBarEnabled(boolean) 14257 * @see #setVerticalScrollBarEnabled(boolean) 14258 */ 14259 protected boolean awakenScrollBars(int startDelay, boolean invalidate) { 14260 final ScrollabilityCache scrollCache = mScrollCache; 14261 14262 if (scrollCache == null || !scrollCache.fadeScrollBars) { 14263 return false; 14264 } 14265 14266 if (scrollCache.scrollBar == null) { 14267 scrollCache.scrollBar = new ScrollBarDrawable(); 14268 scrollCache.scrollBar.setState(getDrawableState()); 14269 scrollCache.scrollBar.setCallback(this); 14270 } 14271 14272 if (isHorizontalScrollBarEnabled() || isVerticalScrollBarEnabled()) { 14273 14274 if (invalidate) { 14275 // Invalidate to show the scrollbars 14276 postInvalidateOnAnimation(); 14277 } 14278 14279 if (scrollCache.state == ScrollabilityCache.OFF) { 14280 // FIXME: this is copied from WindowManagerService. 14281 // We should get this value from the system when it 14282 // is possible to do so. 14283 final int KEY_REPEAT_FIRST_DELAY = 750; 14284 startDelay = Math.max(KEY_REPEAT_FIRST_DELAY, startDelay); 14285 } 14286 14287 // Tell mScrollCache when we should start fading. This may 14288 // extend the fade start time if one was already scheduled 14289 long fadeStartTime = AnimationUtils.currentAnimationTimeMillis() + startDelay; 14290 scrollCache.fadeStartTime = fadeStartTime; 14291 scrollCache.state = ScrollabilityCache.ON; 14292 14293 // Schedule our fader to run, unscheduling any old ones first 14294 if (mAttachInfo != null) { 14295 mAttachInfo.mHandler.removeCallbacks(scrollCache); 14296 mAttachInfo.mHandler.postAtTime(scrollCache, fadeStartTime); 14297 } 14298 14299 return true; 14300 } 14301 14302 return false; 14303 } 14304 14305 /** 14306 * Do not invalidate views which are not visible and which are not running an animation. They 14307 * will not get drawn and they should not set dirty flags as if they will be drawn 14308 */ 14309 private boolean skipInvalidate() { 14310 return (mViewFlags & VISIBILITY_MASK) != VISIBLE && mCurrentAnimation == null && 14311 (!(mParent instanceof ViewGroup) || 14312 !((ViewGroup) mParent).isViewTransitioning(this)); 14313 } 14314 14315 /** 14316 * Mark the area defined by dirty as needing to be drawn. If the view is 14317 * visible, {@link #onDraw(android.graphics.Canvas)} will be called at some 14318 * point in the future. 14319 * <p> 14320 * This must be called from a UI thread. To call from a non-UI thread, call 14321 * {@link #postInvalidate()}. 14322 * <p> 14323 * <b>WARNING:</b> In API 19 and below, this method may be destructive to 14324 * {@code dirty}. 14325 * 14326 * @param dirty the rectangle representing the bounds of the dirty region 14327 */ 14328 public void invalidate(Rect dirty) { 14329 final int scrollX = mScrollX; 14330 final int scrollY = mScrollY; 14331 invalidateInternal(dirty.left - scrollX, dirty.top - scrollY, 14332 dirty.right - scrollX, dirty.bottom - scrollY, true, false); 14333 } 14334 14335 /** 14336 * Mark the area defined by the rect (l,t,r,b) as needing to be drawn. The 14337 * coordinates of the dirty rect are relative to the view. If the view is 14338 * visible, {@link #onDraw(android.graphics.Canvas)} will be called at some 14339 * point in the future. 14340 * <p> 14341 * This must be called from a UI thread. To call from a non-UI thread, call 14342 * {@link #postInvalidate()}. 14343 * 14344 * @param l the left position of the dirty region 14345 * @param t the top position of the dirty region 14346 * @param r the right position of the dirty region 14347 * @param b the bottom position of the dirty region 14348 */ 14349 public void invalidate(int l, int t, int r, int b) { 14350 final int scrollX = mScrollX; 14351 final int scrollY = mScrollY; 14352 invalidateInternal(l - scrollX, t - scrollY, r - scrollX, b - scrollY, true, false); 14353 } 14354 14355 /** 14356 * Invalidate the whole view. If the view is visible, 14357 * {@link #onDraw(android.graphics.Canvas)} will be called at some point in 14358 * the future. 14359 * <p> 14360 * This must be called from a UI thread. To call from a non-UI thread, call 14361 * {@link #postInvalidate()}. 14362 */ 14363 public void invalidate() { 14364 invalidate(true); 14365 } 14366 14367 /** 14368 * This is where the invalidate() work actually happens. A full invalidate() 14369 * causes the drawing cache to be invalidated, but this function can be 14370 * called with invalidateCache set to false to skip that invalidation step 14371 * for cases that do not need it (for example, a component that remains at 14372 * the same dimensions with the same content). 14373 * 14374 * @param invalidateCache Whether the drawing cache for this view should be 14375 * invalidated as well. This is usually true for a full 14376 * invalidate, but may be set to false if the View's contents or 14377 * dimensions have not changed. 14378 * @hide 14379 */ 14380 public void invalidate(boolean invalidateCache) { 14381 invalidateInternal(0, 0, mRight - mLeft, mBottom - mTop, invalidateCache, true); 14382 } 14383 14384 void invalidateInternal(int l, int t, int r, int b, boolean invalidateCache, 14385 boolean fullInvalidate) { 14386 if (mGhostView != null) { 14387 mGhostView.invalidate(true); 14388 return; 14389 } 14390 14391 if (skipInvalidate()) { 14392 return; 14393 } 14394 14395 if ((mPrivateFlags & (PFLAG_DRAWN | PFLAG_HAS_BOUNDS)) == (PFLAG_DRAWN | PFLAG_HAS_BOUNDS) 14396 || (invalidateCache && (mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == PFLAG_DRAWING_CACHE_VALID) 14397 || (mPrivateFlags & PFLAG_INVALIDATED) != PFLAG_INVALIDATED 14398 || (fullInvalidate && isOpaque() != mLastIsOpaque)) { 14399 if (fullInvalidate) { 14400 mLastIsOpaque = isOpaque(); 14401 mPrivateFlags &= ~PFLAG_DRAWN; 14402 } 14403 14404 mPrivateFlags |= PFLAG_DIRTY; 14405 14406 if (invalidateCache) { 14407 mPrivateFlags |= PFLAG_INVALIDATED; 14408 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; 14409 } 14410 14411 // Propagate the damage rectangle to the parent view. 14412 final AttachInfo ai = mAttachInfo; 14413 final ViewParent p = mParent; 14414 if (p != null && ai != null && l < r && t < b) { 14415 final Rect damage = ai.mTmpInvalRect; 14416 damage.set(l, t, r, b); 14417 p.invalidateChild(this, damage); 14418 } 14419 14420 // Damage the entire projection receiver, if necessary. 14421 if (mBackground != null && mBackground.isProjected()) { 14422 final View receiver = getProjectionReceiver(); 14423 if (receiver != null) { 14424 receiver.damageInParent(); 14425 } 14426 } 14427 } 14428 } 14429 14430 /** 14431 * @return this view's projection receiver, or {@code null} if none exists 14432 */ 14433 private View getProjectionReceiver() { 14434 ViewParent p = getParent(); 14435 while (p != null && p instanceof View) { 14436 final View v = (View) p; 14437 if (v.isProjectionReceiver()) { 14438 return v; 14439 } 14440 p = p.getParent(); 14441 } 14442 14443 return null; 14444 } 14445 14446 /** 14447 * @return whether the view is a projection receiver 14448 */ 14449 private boolean isProjectionReceiver() { 14450 return mBackground != null; 14451 } 14452 14453 /** 14454 * Quick invalidation for View property changes (alpha, translationXY, etc.). We don't want to 14455 * set any flags or handle all of the cases handled by the default invalidation methods. 14456 * Instead, we just want to schedule a traversal in ViewRootImpl with the appropriate 14457 * dirty rect. This method calls into fast invalidation methods in ViewGroup that 14458 * walk up the hierarchy, transforming the dirty rect as necessary. 14459 * 14460 * The method also handles normal invalidation logic if display list properties are not 14461 * being used in this view. The invalidateParent and forceRedraw flags are used by that 14462 * backup approach, to handle these cases used in the various property-setting methods. 14463 * 14464 * @param invalidateParent Force a call to invalidateParentCaches() if display list properties 14465 * are not being used in this view 14466 * @param forceRedraw Mark the view as DRAWN to force the invalidation to propagate, if display 14467 * list properties are not being used in this view 14468 */ 14469 void invalidateViewProperty(boolean invalidateParent, boolean forceRedraw) { 14470 if (!isHardwareAccelerated() 14471 || !mRenderNode.isValid() 14472 || (mPrivateFlags & PFLAG_DRAW_ANIMATION) != 0) { 14473 if (invalidateParent) { 14474 invalidateParentCaches(); 14475 } 14476 if (forceRedraw) { 14477 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 14478 } 14479 invalidate(false); 14480 } else { 14481 damageInParent(); 14482 } 14483 } 14484 14485 /** 14486 * Tells the parent view to damage this view's bounds. 14487 * 14488 * @hide 14489 */ 14490 protected void damageInParent() { 14491 if (mParent != null && mAttachInfo != null) { 14492 mParent.onDescendantInvalidated(this, this); 14493 } 14494 } 14495 14496 /** 14497 * Utility method to transform a given Rect by the current matrix of this view. 14498 */ 14499 void transformRect(final Rect rect) { 14500 if (!getMatrix().isIdentity()) { 14501 RectF boundingRect = mAttachInfo.mTmpTransformRect; 14502 boundingRect.set(rect); 14503 getMatrix().mapRect(boundingRect); 14504 rect.set((int) Math.floor(boundingRect.left), 14505 (int) Math.floor(boundingRect.top), 14506 (int) Math.ceil(boundingRect.right), 14507 (int) Math.ceil(boundingRect.bottom)); 14508 } 14509 } 14510 14511 /** 14512 * Used to indicate that the parent of this view should clear its caches. This functionality 14513 * is used to force the parent to rebuild its display list (when hardware-accelerated), 14514 * which is necessary when various parent-managed properties of the view change, such as 14515 * alpha, translationX/Y, scrollX/Y, scaleX/Y, and rotation/X/Y. This method only 14516 * clears the parent caches and does not causes an invalidate event. 14517 * 14518 * @hide 14519 */ 14520 protected void invalidateParentCaches() { 14521 if (mParent instanceof View) { 14522 ((View) mParent).mPrivateFlags |= PFLAG_INVALIDATED; 14523 } 14524 } 14525 14526 /** 14527 * Used to indicate that the parent of this view should be invalidated. This functionality 14528 * is used to force the parent to rebuild its display list (when hardware-accelerated), 14529 * which is necessary when various parent-managed properties of the view change, such as 14530 * alpha, translationX/Y, scrollX/Y, scaleX/Y, and rotation/X/Y. This method will propagate 14531 * an invalidation event to the parent. 14532 * 14533 * @hide 14534 */ 14535 protected void invalidateParentIfNeeded() { 14536 if (isHardwareAccelerated() && mParent instanceof View) { 14537 ((View) mParent).invalidate(true); 14538 } 14539 } 14540 14541 /** 14542 * @hide 14543 */ 14544 protected void invalidateParentIfNeededAndWasQuickRejected() { 14545 if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) != 0) { 14546 // View was rejected last time it was drawn by its parent; this may have changed 14547 invalidateParentIfNeeded(); 14548 } 14549 } 14550 14551 /** 14552 * Indicates whether this View is opaque. An opaque View guarantees that it will 14553 * draw all the pixels overlapping its bounds using a fully opaque color. 14554 * 14555 * Subclasses of View should override this method whenever possible to indicate 14556 * whether an instance is opaque. Opaque Views are treated in a special way by 14557 * the View hierarchy, possibly allowing it to perform optimizations during 14558 * invalidate/draw passes. 14559 * 14560 * @return True if this View is guaranteed to be fully opaque, false otherwise. 14561 */ 14562 @ViewDebug.ExportedProperty(category = "drawing") 14563 public boolean isOpaque() { 14564 return (mPrivateFlags & PFLAG_OPAQUE_MASK) == PFLAG_OPAQUE_MASK && 14565 getFinalAlpha() >= 1.0f; 14566 } 14567 14568 /** 14569 * @hide 14570 */ 14571 protected void computeOpaqueFlags() { 14572 // Opaque if: 14573 // - Has a background 14574 // - Background is opaque 14575 // - Doesn't have scrollbars or scrollbars overlay 14576 14577 if (mBackground != null && mBackground.getOpacity() == PixelFormat.OPAQUE) { 14578 mPrivateFlags |= PFLAG_OPAQUE_BACKGROUND; 14579 } else { 14580 mPrivateFlags &= ~PFLAG_OPAQUE_BACKGROUND; 14581 } 14582 14583 final int flags = mViewFlags; 14584 if (((flags & SCROLLBARS_VERTICAL) == 0 && (flags & SCROLLBARS_HORIZONTAL) == 0) || 14585 (flags & SCROLLBARS_STYLE_MASK) == SCROLLBARS_INSIDE_OVERLAY || 14586 (flags & SCROLLBARS_STYLE_MASK) == SCROLLBARS_OUTSIDE_OVERLAY) { 14587 mPrivateFlags |= PFLAG_OPAQUE_SCROLLBARS; 14588 } else { 14589 mPrivateFlags &= ~PFLAG_OPAQUE_SCROLLBARS; 14590 } 14591 } 14592 14593 /** 14594 * @hide 14595 */ 14596 protected boolean hasOpaqueScrollbars() { 14597 return (mPrivateFlags & PFLAG_OPAQUE_SCROLLBARS) == PFLAG_OPAQUE_SCROLLBARS; 14598 } 14599 14600 /** 14601 * @return A handler associated with the thread running the View. This 14602 * handler can be used to pump events in the UI events queue. 14603 */ 14604 public Handler getHandler() { 14605 final AttachInfo attachInfo = mAttachInfo; 14606 if (attachInfo != null) { 14607 return attachInfo.mHandler; 14608 } 14609 return null; 14610 } 14611 14612 /** 14613 * Returns the queue of runnable for this view. 14614 * 14615 * @return the queue of runnables for this view 14616 */ 14617 private HandlerActionQueue getRunQueue() { 14618 if (mRunQueue == null) { 14619 mRunQueue = new HandlerActionQueue(); 14620 } 14621 return mRunQueue; 14622 } 14623 14624 /** 14625 * Gets the view root associated with the View. 14626 * @return The view root, or null if none. 14627 * @hide 14628 */ 14629 public ViewRootImpl getViewRootImpl() { 14630 if (mAttachInfo != null) { 14631 return mAttachInfo.mViewRootImpl; 14632 } 14633 return null; 14634 } 14635 14636 /** 14637 * @hide 14638 */ 14639 public ThreadedRenderer getThreadedRenderer() { 14640 return mAttachInfo != null ? mAttachInfo.mThreadedRenderer : null; 14641 } 14642 14643 /** 14644 * <p>Causes the Runnable to be added to the message queue. 14645 * The runnable will be run on the user interface thread.</p> 14646 * 14647 * @param action The Runnable that will be executed. 14648 * 14649 * @return Returns true if the Runnable was successfully placed in to the 14650 * message queue. Returns false on failure, usually because the 14651 * looper processing the message queue is exiting. 14652 * 14653 * @see #postDelayed 14654 * @see #removeCallbacks 14655 */ 14656 public boolean post(Runnable action) { 14657 final AttachInfo attachInfo = mAttachInfo; 14658 if (attachInfo != null) { 14659 return attachInfo.mHandler.post(action); 14660 } 14661 14662 // Postpone the runnable until we know on which thread it needs to run. 14663 // Assume that the runnable will be successfully placed after attach. 14664 getRunQueue().post(action); 14665 return true; 14666 } 14667 14668 /** 14669 * <p>Causes the Runnable to be added to the message queue, to be run 14670 * after the specified amount of time elapses. 14671 * The runnable will be run on the user interface thread.</p> 14672 * 14673 * @param action The Runnable that will be executed. 14674 * @param delayMillis The delay (in milliseconds) until the Runnable 14675 * will be executed. 14676 * 14677 * @return true if the Runnable was successfully placed in to the 14678 * message queue. Returns false on failure, usually because the 14679 * looper processing the message queue is exiting. Note that a 14680 * result of true does not mean the Runnable will be processed -- 14681 * if the looper is quit before the delivery time of the message 14682 * occurs then the message will be dropped. 14683 * 14684 * @see #post 14685 * @see #removeCallbacks 14686 */ 14687 public boolean postDelayed(Runnable action, long delayMillis) { 14688 final AttachInfo attachInfo = mAttachInfo; 14689 if (attachInfo != null) { 14690 return attachInfo.mHandler.postDelayed(action, delayMillis); 14691 } 14692 14693 // Postpone the runnable until we know on which thread it needs to run. 14694 // Assume that the runnable will be successfully placed after attach. 14695 getRunQueue().postDelayed(action, delayMillis); 14696 return true; 14697 } 14698 14699 /** 14700 * <p>Causes the Runnable to execute on the next animation time step. 14701 * The runnable will be run on the user interface thread.</p> 14702 * 14703 * @param action The Runnable that will be executed. 14704 * 14705 * @see #postOnAnimationDelayed 14706 * @see #removeCallbacks 14707 */ 14708 public void postOnAnimation(Runnable action) { 14709 final AttachInfo attachInfo = mAttachInfo; 14710 if (attachInfo != null) { 14711 attachInfo.mViewRootImpl.mChoreographer.postCallback( 14712 Choreographer.CALLBACK_ANIMATION, action, null); 14713 } else { 14714 // Postpone the runnable until we know 14715 // on which thread it needs to run. 14716 getRunQueue().post(action); 14717 } 14718 } 14719 14720 /** 14721 * <p>Causes the Runnable to execute on the next animation time step, 14722 * after the specified amount of time elapses. 14723 * The runnable will be run on the user interface thread.</p> 14724 * 14725 * @param action The Runnable that will be executed. 14726 * @param delayMillis The delay (in milliseconds) until the Runnable 14727 * will be executed. 14728 * 14729 * @see #postOnAnimation 14730 * @see #removeCallbacks 14731 */ 14732 public void postOnAnimationDelayed(Runnable action, long delayMillis) { 14733 final AttachInfo attachInfo = mAttachInfo; 14734 if (attachInfo != null) { 14735 attachInfo.mViewRootImpl.mChoreographer.postCallbackDelayed( 14736 Choreographer.CALLBACK_ANIMATION, action, null, delayMillis); 14737 } else { 14738 // Postpone the runnable until we know 14739 // on which thread it needs to run. 14740 getRunQueue().postDelayed(action, delayMillis); 14741 } 14742 } 14743 14744 /** 14745 * <p>Removes the specified Runnable from the message queue.</p> 14746 * 14747 * @param action The Runnable to remove from the message handling queue 14748 * 14749 * @return true if this view could ask the Handler to remove the Runnable, 14750 * false otherwise. When the returned value is true, the Runnable 14751 * may or may not have been actually removed from the message queue 14752 * (for instance, if the Runnable was not in the queue already.) 14753 * 14754 * @see #post 14755 * @see #postDelayed 14756 * @see #postOnAnimation 14757 * @see #postOnAnimationDelayed 14758 */ 14759 public boolean removeCallbacks(Runnable action) { 14760 if (action != null) { 14761 final AttachInfo attachInfo = mAttachInfo; 14762 if (attachInfo != null) { 14763 attachInfo.mHandler.removeCallbacks(action); 14764 attachInfo.mViewRootImpl.mChoreographer.removeCallbacks( 14765 Choreographer.CALLBACK_ANIMATION, action, null); 14766 } 14767 getRunQueue().removeCallbacks(action); 14768 } 14769 return true; 14770 } 14771 14772 /** 14773 * <p>Cause an invalidate to happen on a subsequent cycle through the event loop. 14774 * Use this to invalidate the View from a non-UI thread.</p> 14775 * 14776 * <p>This method can be invoked from outside of the UI thread 14777 * only when this View is attached to a window.</p> 14778 * 14779 * @see #invalidate() 14780 * @see #postInvalidateDelayed(long) 14781 */ 14782 public void postInvalidate() { 14783 postInvalidateDelayed(0); 14784 } 14785 14786 /** 14787 * <p>Cause an invalidate of the specified area to happen on a subsequent cycle 14788 * through the event loop. Use this to invalidate the View from a non-UI thread.</p> 14789 * 14790 * <p>This method can be invoked from outside of the UI thread 14791 * only when this View is attached to a window.</p> 14792 * 14793 * @param left The left coordinate of the rectangle to invalidate. 14794 * @param top The top coordinate of the rectangle to invalidate. 14795 * @param right The right coordinate of the rectangle to invalidate. 14796 * @param bottom The bottom coordinate of the rectangle to invalidate. 14797 * 14798 * @see #invalidate(int, int, int, int) 14799 * @see #invalidate(Rect) 14800 * @see #postInvalidateDelayed(long, int, int, int, int) 14801 */ 14802 public void postInvalidate(int left, int top, int right, int bottom) { 14803 postInvalidateDelayed(0, left, top, right, bottom); 14804 } 14805 14806 /** 14807 * <p>Cause an invalidate to happen on a subsequent cycle through the event 14808 * loop. Waits for the specified amount of time.</p> 14809 * 14810 * <p>This method can be invoked from outside of the UI thread 14811 * only when this View is attached to a window.</p> 14812 * 14813 * @param delayMilliseconds the duration in milliseconds to delay the 14814 * invalidation by 14815 * 14816 * @see #invalidate() 14817 * @see #postInvalidate() 14818 */ 14819 public void postInvalidateDelayed(long delayMilliseconds) { 14820 // We try only with the AttachInfo because there's no point in invalidating 14821 // if we are not attached to our window 14822 final AttachInfo attachInfo = mAttachInfo; 14823 if (attachInfo != null) { 14824 attachInfo.mViewRootImpl.dispatchInvalidateDelayed(this, delayMilliseconds); 14825 } 14826 } 14827 14828 /** 14829 * <p>Cause an invalidate of the specified area to happen on a subsequent cycle 14830 * through the event loop. Waits for the specified amount of time.</p> 14831 * 14832 * <p>This method can be invoked from outside of the UI thread 14833 * only when this View is attached to a window.</p> 14834 * 14835 * @param delayMilliseconds the duration in milliseconds to delay the 14836 * invalidation by 14837 * @param left The left coordinate of the rectangle to invalidate. 14838 * @param top The top coordinate of the rectangle to invalidate. 14839 * @param right The right coordinate of the rectangle to invalidate. 14840 * @param bottom The bottom coordinate of the rectangle to invalidate. 14841 * 14842 * @see #invalidate(int, int, int, int) 14843 * @see #invalidate(Rect) 14844 * @see #postInvalidate(int, int, int, int) 14845 */ 14846 public void postInvalidateDelayed(long delayMilliseconds, int left, int top, 14847 int right, int bottom) { 14848 14849 // We try only with the AttachInfo because there's no point in invalidating 14850 // if we are not attached to our window 14851 final AttachInfo attachInfo = mAttachInfo; 14852 if (attachInfo != null) { 14853 final AttachInfo.InvalidateInfo info = AttachInfo.InvalidateInfo.obtain(); 14854 info.target = this; 14855 info.left = left; 14856 info.top = top; 14857 info.right = right; 14858 info.bottom = bottom; 14859 14860 attachInfo.mViewRootImpl.dispatchInvalidateRectDelayed(info, delayMilliseconds); 14861 } 14862 } 14863 14864 /** 14865 * <p>Cause an invalidate to happen on the next animation time step, typically the 14866 * next display frame.</p> 14867 * 14868 * <p>This method can be invoked from outside of the UI thread 14869 * only when this View is attached to a window.</p> 14870 * 14871 * @see #invalidate() 14872 */ 14873 public void postInvalidateOnAnimation() { 14874 // We try only with the AttachInfo because there's no point in invalidating 14875 // if we are not attached to our window 14876 final AttachInfo attachInfo = mAttachInfo; 14877 if (attachInfo != null) { 14878 attachInfo.mViewRootImpl.dispatchInvalidateOnAnimation(this); 14879 } 14880 } 14881 14882 /** 14883 * <p>Cause an invalidate of the specified area to happen on the next animation 14884 * time step, typically the next display frame.</p> 14885 * 14886 * <p>This method can be invoked from outside of the UI thread 14887 * only when this View is attached to a window.</p> 14888 * 14889 * @param left The left coordinate of the rectangle to invalidate. 14890 * @param top The top coordinate of the rectangle to invalidate. 14891 * @param right The right coordinate of the rectangle to invalidate. 14892 * @param bottom The bottom coordinate of the rectangle to invalidate. 14893 * 14894 * @see #invalidate(int, int, int, int) 14895 * @see #invalidate(Rect) 14896 */ 14897 public void postInvalidateOnAnimation(int left, int top, int right, int bottom) { 14898 // We try only with the AttachInfo because there's no point in invalidating 14899 // if we are not attached to our window 14900 final AttachInfo attachInfo = mAttachInfo; 14901 if (attachInfo != null) { 14902 final AttachInfo.InvalidateInfo info = AttachInfo.InvalidateInfo.obtain(); 14903 info.target = this; 14904 info.left = left; 14905 info.top = top; 14906 info.right = right; 14907 info.bottom = bottom; 14908 14909 attachInfo.mViewRootImpl.dispatchInvalidateRectOnAnimation(info); 14910 } 14911 } 14912 14913 /** 14914 * Post a callback to send a {@link AccessibilityEvent#TYPE_VIEW_SCROLLED} event. 14915 * This event is sent at most once every 14916 * {@link ViewConfiguration#getSendRecurringAccessibilityEventsInterval()}. 14917 */ 14918 private void postSendViewScrolledAccessibilityEventCallback() { 14919 if (mSendViewScrolledAccessibilityEvent == null) { 14920 mSendViewScrolledAccessibilityEvent = new SendViewScrolledAccessibilityEvent(); 14921 } 14922 if (!mSendViewScrolledAccessibilityEvent.mIsPending) { 14923 mSendViewScrolledAccessibilityEvent.mIsPending = true; 14924 postDelayed(mSendViewScrolledAccessibilityEvent, 14925 ViewConfiguration.getSendRecurringAccessibilityEventsInterval()); 14926 } 14927 } 14928 14929 /** 14930 * Called by a parent to request that a child update its values for mScrollX 14931 * and mScrollY if necessary. This will typically be done if the child is 14932 * animating a scroll using a {@link android.widget.Scroller Scroller} 14933 * object. 14934 */ 14935 public void computeScroll() { 14936 } 14937 14938 /** 14939 * <p>Indicate whether the horizontal edges are faded when the view is 14940 * scrolled horizontally.</p> 14941 * 14942 * @return true if the horizontal edges should are faded on scroll, false 14943 * otherwise 14944 * 14945 * @see #setHorizontalFadingEdgeEnabled(boolean) 14946 * 14947 * @attr ref android.R.styleable#View_requiresFadingEdge 14948 */ 14949 public boolean isHorizontalFadingEdgeEnabled() { 14950 return (mViewFlags & FADING_EDGE_HORIZONTAL) == FADING_EDGE_HORIZONTAL; 14951 } 14952 14953 /** 14954 * <p>Define whether the horizontal edges should be faded when this view 14955 * is scrolled horizontally.</p> 14956 * 14957 * @param horizontalFadingEdgeEnabled true if the horizontal edges should 14958 * be faded when the view is scrolled 14959 * horizontally 14960 * 14961 * @see #isHorizontalFadingEdgeEnabled() 14962 * 14963 * @attr ref android.R.styleable#View_requiresFadingEdge 14964 */ 14965 public void setHorizontalFadingEdgeEnabled(boolean horizontalFadingEdgeEnabled) { 14966 if (isHorizontalFadingEdgeEnabled() != horizontalFadingEdgeEnabled) { 14967 if (horizontalFadingEdgeEnabled) { 14968 initScrollCache(); 14969 } 14970 14971 mViewFlags ^= FADING_EDGE_HORIZONTAL; 14972 } 14973 } 14974 14975 /** 14976 * <p>Indicate whether the vertical edges are faded when the view is 14977 * scrolled horizontally.</p> 14978 * 14979 * @return true if the vertical edges should are faded on scroll, false 14980 * otherwise 14981 * 14982 * @see #setVerticalFadingEdgeEnabled(boolean) 14983 * 14984 * @attr ref android.R.styleable#View_requiresFadingEdge 14985 */ 14986 public boolean isVerticalFadingEdgeEnabled() { 14987 return (mViewFlags & FADING_EDGE_VERTICAL) == FADING_EDGE_VERTICAL; 14988 } 14989 14990 /** 14991 * <p>Define whether the vertical edges should be faded when this view 14992 * is scrolled vertically.</p> 14993 * 14994 * @param verticalFadingEdgeEnabled true if the vertical edges should 14995 * be faded when the view is scrolled 14996 * vertically 14997 * 14998 * @see #isVerticalFadingEdgeEnabled() 14999 * 15000 * @attr ref android.R.styleable#View_requiresFadingEdge 15001 */ 15002 public void setVerticalFadingEdgeEnabled(boolean verticalFadingEdgeEnabled) { 15003 if (isVerticalFadingEdgeEnabled() != verticalFadingEdgeEnabled) { 15004 if (verticalFadingEdgeEnabled) { 15005 initScrollCache(); 15006 } 15007 15008 mViewFlags ^= FADING_EDGE_VERTICAL; 15009 } 15010 } 15011 15012 /** 15013 * Returns the strength, or intensity, of the top faded edge. The strength is 15014 * a value between 0.0 (no fade) and 1.0 (full fade). The default implementation 15015 * returns 0.0 or 1.0 but no value in between. 15016 * 15017 * Subclasses should override this method to provide a smoother fade transition 15018 * when scrolling occurs. 15019 * 15020 * @return the intensity of the top fade as a float between 0.0f and 1.0f 15021 */ 15022 protected float getTopFadingEdgeStrength() { 15023 return computeVerticalScrollOffset() > 0 ? 1.0f : 0.0f; 15024 } 15025 15026 /** 15027 * Returns the strength, or intensity, of the bottom faded edge. The strength is 15028 * a value between 0.0 (no fade) and 1.0 (full fade). The default implementation 15029 * returns 0.0 or 1.0 but no value in between. 15030 * 15031 * Subclasses should override this method to provide a smoother fade transition 15032 * when scrolling occurs. 15033 * 15034 * @return the intensity of the bottom fade as a float between 0.0f and 1.0f 15035 */ 15036 protected float getBottomFadingEdgeStrength() { 15037 return computeVerticalScrollOffset() + computeVerticalScrollExtent() < 15038 computeVerticalScrollRange() ? 1.0f : 0.0f; 15039 } 15040 15041 /** 15042 * Returns the strength, or intensity, of the left faded edge. The strength is 15043 * a value between 0.0 (no fade) and 1.0 (full fade). The default implementation 15044 * returns 0.0 or 1.0 but no value in between. 15045 * 15046 * Subclasses should override this method to provide a smoother fade transition 15047 * when scrolling occurs. 15048 * 15049 * @return the intensity of the left fade as a float between 0.0f and 1.0f 15050 */ 15051 protected float getLeftFadingEdgeStrength() { 15052 return computeHorizontalScrollOffset() > 0 ? 1.0f : 0.0f; 15053 } 15054 15055 /** 15056 * Returns the strength, or intensity, of the right faded edge. The strength is 15057 * a value between 0.0 (no fade) and 1.0 (full fade). The default implementation 15058 * returns 0.0 or 1.0 but no value in between. 15059 * 15060 * Subclasses should override this method to provide a smoother fade transition 15061 * when scrolling occurs. 15062 * 15063 * @return the intensity of the right fade as a float between 0.0f and 1.0f 15064 */ 15065 protected float getRightFadingEdgeStrength() { 15066 return computeHorizontalScrollOffset() + computeHorizontalScrollExtent() < 15067 computeHorizontalScrollRange() ? 1.0f : 0.0f; 15068 } 15069 15070 /** 15071 * <p>Indicate whether the horizontal scrollbar should be drawn or not. The 15072 * scrollbar is not drawn by default.</p> 15073 * 15074 * @return true if the horizontal scrollbar should be painted, false 15075 * otherwise 15076 * 15077 * @see #setHorizontalScrollBarEnabled(boolean) 15078 */ 15079 public boolean isHorizontalScrollBarEnabled() { 15080 return (mViewFlags & SCROLLBARS_HORIZONTAL) == SCROLLBARS_HORIZONTAL; 15081 } 15082 15083 /** 15084 * <p>Define whether the horizontal scrollbar should be drawn or not. The 15085 * scrollbar is not drawn by default.</p> 15086 * 15087 * @param horizontalScrollBarEnabled true if the horizontal scrollbar should 15088 * be painted 15089 * 15090 * @see #isHorizontalScrollBarEnabled() 15091 */ 15092 public void setHorizontalScrollBarEnabled(boolean horizontalScrollBarEnabled) { 15093 if (isHorizontalScrollBarEnabled() != horizontalScrollBarEnabled) { 15094 mViewFlags ^= SCROLLBARS_HORIZONTAL; 15095 computeOpaqueFlags(); 15096 resolvePadding(); 15097 } 15098 } 15099 15100 /** 15101 * <p>Indicate whether the vertical scrollbar should be drawn or not. The 15102 * scrollbar is not drawn by default.</p> 15103 * 15104 * @return true if the vertical scrollbar should be painted, false 15105 * otherwise 15106 * 15107 * @see #setVerticalScrollBarEnabled(boolean) 15108 */ 15109 public boolean isVerticalScrollBarEnabled() { 15110 return (mViewFlags & SCROLLBARS_VERTICAL) == SCROLLBARS_VERTICAL; 15111 } 15112 15113 /** 15114 * <p>Define whether the vertical scrollbar should be drawn or not. The 15115 * scrollbar is not drawn by default.</p> 15116 * 15117 * @param verticalScrollBarEnabled true if the vertical scrollbar should 15118 * be painted 15119 * 15120 * @see #isVerticalScrollBarEnabled() 15121 */ 15122 public void setVerticalScrollBarEnabled(boolean verticalScrollBarEnabled) { 15123 if (isVerticalScrollBarEnabled() != verticalScrollBarEnabled) { 15124 mViewFlags ^= SCROLLBARS_VERTICAL; 15125 computeOpaqueFlags(); 15126 resolvePadding(); 15127 } 15128 } 15129 15130 /** 15131 * @hide 15132 */ 15133 protected void recomputePadding() { 15134 internalSetPadding(mUserPaddingLeft, mPaddingTop, mUserPaddingRight, mUserPaddingBottom); 15135 } 15136 15137 /** 15138 * Define whether scrollbars will fade when the view is not scrolling. 15139 * 15140 * @param fadeScrollbars whether to enable fading 15141 * 15142 * @attr ref android.R.styleable#View_fadeScrollbars 15143 */ 15144 public void setScrollbarFadingEnabled(boolean fadeScrollbars) { 15145 initScrollCache(); 15146 final ScrollabilityCache scrollabilityCache = mScrollCache; 15147 scrollabilityCache.fadeScrollBars = fadeScrollbars; 15148 if (fadeScrollbars) { 15149 scrollabilityCache.state = ScrollabilityCache.OFF; 15150 } else { 15151 scrollabilityCache.state = ScrollabilityCache.ON; 15152 } 15153 } 15154 15155 /** 15156 * 15157 * Returns true if scrollbars will fade when this view is not scrolling 15158 * 15159 * @return true if scrollbar fading is enabled 15160 * 15161 * @attr ref android.R.styleable#View_fadeScrollbars 15162 */ 15163 public boolean isScrollbarFadingEnabled() { 15164 return mScrollCache != null && mScrollCache.fadeScrollBars; 15165 } 15166 15167 /** 15168 * 15169 * Returns the delay before scrollbars fade. 15170 * 15171 * @return the delay before scrollbars fade 15172 * 15173 * @attr ref android.R.styleable#View_scrollbarDefaultDelayBeforeFade 15174 */ 15175 public int getScrollBarDefaultDelayBeforeFade() { 15176 return mScrollCache == null ? ViewConfiguration.getScrollDefaultDelay() : 15177 mScrollCache.scrollBarDefaultDelayBeforeFade; 15178 } 15179 15180 /** 15181 * Define the delay before scrollbars fade. 15182 * 15183 * @param scrollBarDefaultDelayBeforeFade - the delay before scrollbars fade 15184 * 15185 * @attr ref android.R.styleable#View_scrollbarDefaultDelayBeforeFade 15186 */ 15187 public void setScrollBarDefaultDelayBeforeFade(int scrollBarDefaultDelayBeforeFade) { 15188 getScrollCache().scrollBarDefaultDelayBeforeFade = scrollBarDefaultDelayBeforeFade; 15189 } 15190 15191 /** 15192 * 15193 * Returns the scrollbar fade duration. 15194 * 15195 * @return the scrollbar fade duration, in milliseconds 15196 * 15197 * @attr ref android.R.styleable#View_scrollbarFadeDuration 15198 */ 15199 public int getScrollBarFadeDuration() { 15200 return mScrollCache == null ? ViewConfiguration.getScrollBarFadeDuration() : 15201 mScrollCache.scrollBarFadeDuration; 15202 } 15203 15204 /** 15205 * Define the scrollbar fade duration. 15206 * 15207 * @param scrollBarFadeDuration - the scrollbar fade duration, in milliseconds 15208 * 15209 * @attr ref android.R.styleable#View_scrollbarFadeDuration 15210 */ 15211 public void setScrollBarFadeDuration(int scrollBarFadeDuration) { 15212 getScrollCache().scrollBarFadeDuration = scrollBarFadeDuration; 15213 } 15214 15215 /** 15216 * 15217 * Returns the scrollbar size. 15218 * 15219 * @return the scrollbar size 15220 * 15221 * @attr ref android.R.styleable#View_scrollbarSize 15222 */ 15223 public int getScrollBarSize() { 15224 return mScrollCache == null ? ViewConfiguration.get(mContext).getScaledScrollBarSize() : 15225 mScrollCache.scrollBarSize; 15226 } 15227 15228 /** 15229 * Define the scrollbar size. 15230 * 15231 * @param scrollBarSize - the scrollbar size 15232 * 15233 * @attr ref android.R.styleable#View_scrollbarSize 15234 */ 15235 public void setScrollBarSize(int scrollBarSize) { 15236 getScrollCache().scrollBarSize = scrollBarSize; 15237 } 15238 15239 /** 15240 * <p>Specify the style of the scrollbars. The scrollbars can be overlaid or 15241 * inset. When inset, they add to the padding of the view. And the scrollbars 15242 * can be drawn inside the padding area or on the edge of the view. For example, 15243 * if a view has a background drawable and you want to draw the scrollbars 15244 * inside the padding specified by the drawable, you can use 15245 * SCROLLBARS_INSIDE_OVERLAY or SCROLLBARS_INSIDE_INSET. If you want them to 15246 * appear at the edge of the view, ignoring the padding, then you can use 15247 * SCROLLBARS_OUTSIDE_OVERLAY or SCROLLBARS_OUTSIDE_INSET.</p> 15248 * @param style the style of the scrollbars. Should be one of 15249 * SCROLLBARS_INSIDE_OVERLAY, SCROLLBARS_INSIDE_INSET, 15250 * SCROLLBARS_OUTSIDE_OVERLAY or SCROLLBARS_OUTSIDE_INSET. 15251 * @see #SCROLLBARS_INSIDE_OVERLAY 15252 * @see #SCROLLBARS_INSIDE_INSET 15253 * @see #SCROLLBARS_OUTSIDE_OVERLAY 15254 * @see #SCROLLBARS_OUTSIDE_INSET 15255 * 15256 * @attr ref android.R.styleable#View_scrollbarStyle 15257 */ 15258 public void setScrollBarStyle(@ScrollBarStyle int style) { 15259 if (style != (mViewFlags & SCROLLBARS_STYLE_MASK)) { 15260 mViewFlags = (mViewFlags & ~SCROLLBARS_STYLE_MASK) | (style & SCROLLBARS_STYLE_MASK); 15261 computeOpaqueFlags(); 15262 resolvePadding(); 15263 } 15264 } 15265 15266 /** 15267 * <p>Returns the current scrollbar style.</p> 15268 * @return the current scrollbar style 15269 * @see #SCROLLBARS_INSIDE_OVERLAY 15270 * @see #SCROLLBARS_INSIDE_INSET 15271 * @see #SCROLLBARS_OUTSIDE_OVERLAY 15272 * @see #SCROLLBARS_OUTSIDE_INSET 15273 * 15274 * @attr ref android.R.styleable#View_scrollbarStyle 15275 */ 15276 @ViewDebug.ExportedProperty(mapping = { 15277 @ViewDebug.IntToString(from = SCROLLBARS_INSIDE_OVERLAY, to = "INSIDE_OVERLAY"), 15278 @ViewDebug.IntToString(from = SCROLLBARS_INSIDE_INSET, to = "INSIDE_INSET"), 15279 @ViewDebug.IntToString(from = SCROLLBARS_OUTSIDE_OVERLAY, to = "OUTSIDE_OVERLAY"), 15280 @ViewDebug.IntToString(from = SCROLLBARS_OUTSIDE_INSET, to = "OUTSIDE_INSET") 15281 }) 15282 @ScrollBarStyle 15283 public int getScrollBarStyle() { 15284 return mViewFlags & SCROLLBARS_STYLE_MASK; 15285 } 15286 15287 /** 15288 * <p>Compute the horizontal range that the horizontal scrollbar 15289 * represents.</p> 15290 * 15291 * <p>The range is expressed in arbitrary units that must be the same as the 15292 * units used by {@link #computeHorizontalScrollExtent()} and 15293 * {@link #computeHorizontalScrollOffset()}.</p> 15294 * 15295 * <p>The default range is the drawing width of this view.</p> 15296 * 15297 * @return the total horizontal range represented by the horizontal 15298 * scrollbar 15299 * 15300 * @see #computeHorizontalScrollExtent() 15301 * @see #computeHorizontalScrollOffset() 15302 * @see android.widget.ScrollBarDrawable 15303 */ 15304 protected int computeHorizontalScrollRange() { 15305 return getWidth(); 15306 } 15307 15308 /** 15309 * <p>Compute the horizontal offset of the horizontal scrollbar's thumb 15310 * within the horizontal range. This value is used to compute the position 15311 * of the thumb within the scrollbar's track.</p> 15312 * 15313 * <p>The range is expressed in arbitrary units that must be the same as the 15314 * units used by {@link #computeHorizontalScrollRange()} and 15315 * {@link #computeHorizontalScrollExtent()}.</p> 15316 * 15317 * <p>The default offset is the scroll offset of this view.</p> 15318 * 15319 * @return the horizontal offset of the scrollbar's thumb 15320 * 15321 * @see #computeHorizontalScrollRange() 15322 * @see #computeHorizontalScrollExtent() 15323 * @see android.widget.ScrollBarDrawable 15324 */ 15325 protected int computeHorizontalScrollOffset() { 15326 return mScrollX; 15327 } 15328 15329 /** 15330 * <p>Compute the horizontal extent of the horizontal scrollbar's thumb 15331 * within the horizontal range. This value is used to compute the length 15332 * of the thumb within the scrollbar's track.</p> 15333 * 15334 * <p>The range is expressed in arbitrary units that must be the same as the 15335 * units used by {@link #computeHorizontalScrollRange()} and 15336 * {@link #computeHorizontalScrollOffset()}.</p> 15337 * 15338 * <p>The default extent is the drawing width of this view.</p> 15339 * 15340 * @return the horizontal extent of the scrollbar's thumb 15341 * 15342 * @see #computeHorizontalScrollRange() 15343 * @see #computeHorizontalScrollOffset() 15344 * @see android.widget.ScrollBarDrawable 15345 */ 15346 protected int computeHorizontalScrollExtent() { 15347 return getWidth(); 15348 } 15349 15350 /** 15351 * <p>Compute the vertical range that the vertical scrollbar represents.</p> 15352 * 15353 * <p>The range is expressed in arbitrary units that must be the same as the 15354 * units used by {@link #computeVerticalScrollExtent()} and 15355 * {@link #computeVerticalScrollOffset()}.</p> 15356 * 15357 * @return the total vertical range represented by the vertical scrollbar 15358 * 15359 * <p>The default range is the drawing height of this view.</p> 15360 * 15361 * @see #computeVerticalScrollExtent() 15362 * @see #computeVerticalScrollOffset() 15363 * @see android.widget.ScrollBarDrawable 15364 */ 15365 protected int computeVerticalScrollRange() { 15366 return getHeight(); 15367 } 15368 15369 /** 15370 * <p>Compute the vertical offset of the vertical scrollbar's thumb 15371 * within the horizontal range. This value is used to compute the position 15372 * of the thumb within the scrollbar's track.</p> 15373 * 15374 * <p>The range is expressed in arbitrary units that must be the same as the 15375 * units used by {@link #computeVerticalScrollRange()} and 15376 * {@link #computeVerticalScrollExtent()}.</p> 15377 * 15378 * <p>The default offset is the scroll offset of this view.</p> 15379 * 15380 * @return the vertical offset of the scrollbar's thumb 15381 * 15382 * @see #computeVerticalScrollRange() 15383 * @see #computeVerticalScrollExtent() 15384 * @see android.widget.ScrollBarDrawable 15385 */ 15386 protected int computeVerticalScrollOffset() { 15387 return mScrollY; 15388 } 15389 15390 /** 15391 * <p>Compute the vertical extent of the vertical scrollbar's thumb 15392 * within the vertical range. This value is used to compute the length 15393 * of the thumb within the scrollbar's track.</p> 15394 * 15395 * <p>The range is expressed in arbitrary units that must be the same as the 15396 * units used by {@link #computeVerticalScrollRange()} and 15397 * {@link #computeVerticalScrollOffset()}.</p> 15398 * 15399 * <p>The default extent is the drawing height of this view.</p> 15400 * 15401 * @return the vertical extent of the scrollbar's thumb 15402 * 15403 * @see #computeVerticalScrollRange() 15404 * @see #computeVerticalScrollOffset() 15405 * @see android.widget.ScrollBarDrawable 15406 */ 15407 protected int computeVerticalScrollExtent() { 15408 return getHeight(); 15409 } 15410 15411 /** 15412 * Check if this view can be scrolled horizontally in a certain direction. 15413 * 15414 * @param direction Negative to check scrolling left, positive to check scrolling right. 15415 * @return true if this view can be scrolled in the specified direction, false otherwise. 15416 */ 15417 public boolean canScrollHorizontally(int direction) { 15418 final int offset = computeHorizontalScrollOffset(); 15419 final int range = computeHorizontalScrollRange() - computeHorizontalScrollExtent(); 15420 if (range == 0) return false; 15421 if (direction < 0) { 15422 return offset > 0; 15423 } else { 15424 return offset < range - 1; 15425 } 15426 } 15427 15428 /** 15429 * Check if this view can be scrolled vertically in a certain direction. 15430 * 15431 * @param direction Negative to check scrolling up, positive to check scrolling down. 15432 * @return true if this view can be scrolled in the specified direction, false otherwise. 15433 */ 15434 public boolean canScrollVertically(int direction) { 15435 final int offset = computeVerticalScrollOffset(); 15436 final int range = computeVerticalScrollRange() - computeVerticalScrollExtent(); 15437 if (range == 0) return false; 15438 if (direction < 0) { 15439 return offset > 0; 15440 } else { 15441 return offset < range - 1; 15442 } 15443 } 15444 15445 void getScrollIndicatorBounds(@NonNull Rect out) { 15446 out.left = mScrollX; 15447 out.right = mScrollX + mRight - mLeft; 15448 out.top = mScrollY; 15449 out.bottom = mScrollY + mBottom - mTop; 15450 } 15451 15452 private void onDrawScrollIndicators(Canvas c) { 15453 if ((mPrivateFlags3 & SCROLL_INDICATORS_PFLAG3_MASK) == 0) { 15454 // No scroll indicators enabled. 15455 return; 15456 } 15457 15458 final Drawable dr = mScrollIndicatorDrawable; 15459 if (dr == null) { 15460 // Scroll indicators aren't supported here. 15461 return; 15462 } 15463 15464 final int h = dr.getIntrinsicHeight(); 15465 final int w = dr.getIntrinsicWidth(); 15466 final Rect rect = mAttachInfo.mTmpInvalRect; 15467 getScrollIndicatorBounds(rect); 15468 15469 if ((mPrivateFlags3 & PFLAG3_SCROLL_INDICATOR_TOP) != 0) { 15470 final boolean canScrollUp = canScrollVertically(-1); 15471 if (canScrollUp) { 15472 dr.setBounds(rect.left, rect.top, rect.right, rect.top + h); 15473 dr.draw(c); 15474 } 15475 } 15476 15477 if ((mPrivateFlags3 & PFLAG3_SCROLL_INDICATOR_BOTTOM) != 0) { 15478 final boolean canScrollDown = canScrollVertically(1); 15479 if (canScrollDown) { 15480 dr.setBounds(rect.left, rect.bottom - h, rect.right, rect.bottom); 15481 dr.draw(c); 15482 } 15483 } 15484 15485 final int leftRtl; 15486 final int rightRtl; 15487 if (getLayoutDirection() == LAYOUT_DIRECTION_RTL) { 15488 leftRtl = PFLAG3_SCROLL_INDICATOR_END; 15489 rightRtl = PFLAG3_SCROLL_INDICATOR_START; 15490 } else { 15491 leftRtl = PFLAG3_SCROLL_INDICATOR_START; 15492 rightRtl = PFLAG3_SCROLL_INDICATOR_END; 15493 } 15494 15495 final int leftMask = PFLAG3_SCROLL_INDICATOR_LEFT | leftRtl; 15496 if ((mPrivateFlags3 & leftMask) != 0) { 15497 final boolean canScrollLeft = canScrollHorizontally(-1); 15498 if (canScrollLeft) { 15499 dr.setBounds(rect.left, rect.top, rect.left + w, rect.bottom); 15500 dr.draw(c); 15501 } 15502 } 15503 15504 final int rightMask = PFLAG3_SCROLL_INDICATOR_RIGHT | rightRtl; 15505 if ((mPrivateFlags3 & rightMask) != 0) { 15506 final boolean canScrollRight = canScrollHorizontally(1); 15507 if (canScrollRight) { 15508 dr.setBounds(rect.right - w, rect.top, rect.right, rect.bottom); 15509 dr.draw(c); 15510 } 15511 } 15512 } 15513 15514 private void getHorizontalScrollBarBounds(@Nullable Rect drawBounds, 15515 @Nullable Rect touchBounds) { 15516 final Rect bounds = drawBounds != null ? drawBounds : touchBounds; 15517 if (bounds == null) { 15518 return; 15519 } 15520 final int inside = (mViewFlags & SCROLLBARS_OUTSIDE_MASK) == 0 ? ~0 : 0; 15521 final boolean drawVerticalScrollBar = isVerticalScrollBarEnabled() 15522 && !isVerticalScrollBarHidden(); 15523 final int size = getHorizontalScrollbarHeight(); 15524 final int verticalScrollBarGap = drawVerticalScrollBar ? 15525 getVerticalScrollbarWidth() : 0; 15526 final int width = mRight - mLeft; 15527 final int height = mBottom - mTop; 15528 bounds.top = mScrollY + height - size - (mUserPaddingBottom & inside); 15529 bounds.left = mScrollX + (mPaddingLeft & inside); 15530 bounds.right = mScrollX + width - (mUserPaddingRight & inside) - verticalScrollBarGap; 15531 bounds.bottom = bounds.top + size; 15532 15533 if (touchBounds == null) { 15534 return; 15535 } 15536 if (touchBounds != bounds) { 15537 touchBounds.set(bounds); 15538 } 15539 final int minTouchTarget = mScrollCache.scrollBarMinTouchTarget; 15540 if (touchBounds.height() < minTouchTarget) { 15541 final int adjust = (minTouchTarget - touchBounds.height()) / 2; 15542 touchBounds.bottom = Math.min(touchBounds.bottom + adjust, mScrollY + height); 15543 touchBounds.top = touchBounds.bottom - minTouchTarget; 15544 } 15545 if (touchBounds.width() < minTouchTarget) { 15546 final int adjust = (minTouchTarget - touchBounds.width()) / 2; 15547 touchBounds.left -= adjust; 15548 touchBounds.right = touchBounds.left + minTouchTarget; 15549 } 15550 } 15551 15552 private void getVerticalScrollBarBounds(@Nullable Rect bounds, @Nullable Rect touchBounds) { 15553 if (mRoundScrollbarRenderer == null) { 15554 getStraightVerticalScrollBarBounds(bounds, touchBounds); 15555 } else { 15556 getRoundVerticalScrollBarBounds(bounds != null ? bounds : touchBounds); 15557 } 15558 } 15559 15560 private void getRoundVerticalScrollBarBounds(Rect bounds) { 15561 final int width = mRight - mLeft; 15562 final int height = mBottom - mTop; 15563 // Do not take padding into account as we always want the scrollbars 15564 // to hug the screen for round wearable devices. 15565 bounds.left = mScrollX; 15566 bounds.top = mScrollY; 15567 bounds.right = bounds.left + width; 15568 bounds.bottom = mScrollY + height; 15569 } 15570 15571 private void getStraightVerticalScrollBarBounds(@Nullable Rect drawBounds, 15572 @Nullable Rect touchBounds) { 15573 final Rect bounds = drawBounds != null ? drawBounds : touchBounds; 15574 if (bounds == null) { 15575 return; 15576 } 15577 final int inside = (mViewFlags & SCROLLBARS_OUTSIDE_MASK) == 0 ? ~0 : 0; 15578 final int size = getVerticalScrollbarWidth(); 15579 int verticalScrollbarPosition = mVerticalScrollbarPosition; 15580 if (verticalScrollbarPosition == SCROLLBAR_POSITION_DEFAULT) { 15581 verticalScrollbarPosition = isLayoutRtl() ? 15582 SCROLLBAR_POSITION_LEFT : SCROLLBAR_POSITION_RIGHT; 15583 } 15584 final int width = mRight - mLeft; 15585 final int height = mBottom - mTop; 15586 switch (verticalScrollbarPosition) { 15587 default: 15588 case SCROLLBAR_POSITION_RIGHT: 15589 bounds.left = mScrollX + width - size - (mUserPaddingRight & inside); 15590 break; 15591 case SCROLLBAR_POSITION_LEFT: 15592 bounds.left = mScrollX + (mUserPaddingLeft & inside); 15593 break; 15594 } 15595 bounds.top = mScrollY + (mPaddingTop & inside); 15596 bounds.right = bounds.left + size; 15597 bounds.bottom = mScrollY + height - (mUserPaddingBottom & inside); 15598 15599 if (touchBounds == null) { 15600 return; 15601 } 15602 if (touchBounds != bounds) { 15603 touchBounds.set(bounds); 15604 } 15605 final int minTouchTarget = mScrollCache.scrollBarMinTouchTarget; 15606 if (touchBounds.width() < minTouchTarget) { 15607 final int adjust = (minTouchTarget - touchBounds.width()) / 2; 15608 if (verticalScrollbarPosition == SCROLLBAR_POSITION_RIGHT) { 15609 touchBounds.right = Math.min(touchBounds.right + adjust, mScrollX + width); 15610 touchBounds.left = touchBounds.right - minTouchTarget; 15611 } else { 15612 touchBounds.left = Math.max(touchBounds.left + adjust, mScrollX); 15613 touchBounds.right = touchBounds.left + minTouchTarget; 15614 } 15615 } 15616 if (touchBounds.height() < minTouchTarget) { 15617 final int adjust = (minTouchTarget - touchBounds.height()) / 2; 15618 touchBounds.top -= adjust; 15619 touchBounds.bottom = touchBounds.top + minTouchTarget; 15620 } 15621 } 15622 15623 /** 15624 * <p>Request the drawing of the horizontal and the vertical scrollbar. The 15625 * scrollbars are painted only if they have been awakened first.</p> 15626 * 15627 * @param canvas the canvas on which to draw the scrollbars 15628 * 15629 * @see #awakenScrollBars(int) 15630 */ 15631 protected final void onDrawScrollBars(Canvas canvas) { 15632 // scrollbars are drawn only when the animation is running 15633 final ScrollabilityCache cache = mScrollCache; 15634 15635 if (cache != null) { 15636 15637 int state = cache.state; 15638 15639 if (state == ScrollabilityCache.OFF) { 15640 return; 15641 } 15642 15643 boolean invalidate = false; 15644 15645 if (state == ScrollabilityCache.FADING) { 15646 // We're fading -- get our fade interpolation 15647 if (cache.interpolatorValues == null) { 15648 cache.interpolatorValues = new float[1]; 15649 } 15650 15651 float[] values = cache.interpolatorValues; 15652 15653 // Stops the animation if we're done 15654 if (cache.scrollBarInterpolator.timeToValues(values) == 15655 Interpolator.Result.FREEZE_END) { 15656 cache.state = ScrollabilityCache.OFF; 15657 } else { 15658 cache.scrollBar.mutate().setAlpha(Math.round(values[0])); 15659 } 15660 15661 // This will make the scroll bars inval themselves after 15662 // drawing. We only want this when we're fading so that 15663 // we prevent excessive redraws 15664 invalidate = true; 15665 } else { 15666 // We're just on -- but we may have been fading before so 15667 // reset alpha 15668 cache.scrollBar.mutate().setAlpha(255); 15669 } 15670 15671 final boolean drawHorizontalScrollBar = isHorizontalScrollBarEnabled(); 15672 final boolean drawVerticalScrollBar = isVerticalScrollBarEnabled() 15673 && !isVerticalScrollBarHidden(); 15674 15675 // Fork out the scroll bar drawing for round wearable devices. 15676 if (mRoundScrollbarRenderer != null) { 15677 if (drawVerticalScrollBar) { 15678 final Rect bounds = cache.mScrollBarBounds; 15679 getVerticalScrollBarBounds(bounds, null); 15680 mRoundScrollbarRenderer.drawRoundScrollbars( 15681 canvas, (float) cache.scrollBar.getAlpha() / 255f, bounds); 15682 if (invalidate) { 15683 invalidate(); 15684 } 15685 } 15686 // Do not draw horizontal scroll bars for round wearable devices. 15687 } else if (drawVerticalScrollBar || drawHorizontalScrollBar) { 15688 final ScrollBarDrawable scrollBar = cache.scrollBar; 15689 15690 if (drawHorizontalScrollBar) { 15691 scrollBar.setParameters(computeHorizontalScrollRange(), 15692 computeHorizontalScrollOffset(), 15693 computeHorizontalScrollExtent(), false); 15694 final Rect bounds = cache.mScrollBarBounds; 15695 getHorizontalScrollBarBounds(bounds, null); 15696 onDrawHorizontalScrollBar(canvas, scrollBar, bounds.left, bounds.top, 15697 bounds.right, bounds.bottom); 15698 if (invalidate) { 15699 invalidate(bounds); 15700 } 15701 } 15702 15703 if (drawVerticalScrollBar) { 15704 scrollBar.setParameters(computeVerticalScrollRange(), 15705 computeVerticalScrollOffset(), 15706 computeVerticalScrollExtent(), true); 15707 final Rect bounds = cache.mScrollBarBounds; 15708 getVerticalScrollBarBounds(bounds, null); 15709 onDrawVerticalScrollBar(canvas, scrollBar, bounds.left, bounds.top, 15710 bounds.right, bounds.bottom); 15711 if (invalidate) { 15712 invalidate(bounds); 15713 } 15714 } 15715 } 15716 } 15717 } 15718 15719 /** 15720 * Override this if the vertical scrollbar needs to be hidden in a subclass, like when 15721 * FastScroller is visible. 15722 * @return whether to temporarily hide the vertical scrollbar 15723 * @hide 15724 */ 15725 protected boolean isVerticalScrollBarHidden() { 15726 return false; 15727 } 15728 15729 /** 15730 * <p>Draw the horizontal scrollbar if 15731 * {@link #isHorizontalScrollBarEnabled()} returns true.</p> 15732 * 15733 * @param canvas the canvas on which to draw the scrollbar 15734 * @param scrollBar the scrollbar's drawable 15735 * 15736 * @see #isHorizontalScrollBarEnabled() 15737 * @see #computeHorizontalScrollRange() 15738 * @see #computeHorizontalScrollExtent() 15739 * @see #computeHorizontalScrollOffset() 15740 * @see android.widget.ScrollBarDrawable 15741 * @hide 15742 */ 15743 protected void onDrawHorizontalScrollBar(Canvas canvas, Drawable scrollBar, 15744 int l, int t, int r, int b) { 15745 scrollBar.setBounds(l, t, r, b); 15746 scrollBar.draw(canvas); 15747 } 15748 15749 /** 15750 * <p>Draw the vertical scrollbar if {@link #isVerticalScrollBarEnabled()} 15751 * returns true.</p> 15752 * 15753 * @param canvas the canvas on which to draw the scrollbar 15754 * @param scrollBar the scrollbar's drawable 15755 * 15756 * @see #isVerticalScrollBarEnabled() 15757 * @see #computeVerticalScrollRange() 15758 * @see #computeVerticalScrollExtent() 15759 * @see #computeVerticalScrollOffset() 15760 * @see android.widget.ScrollBarDrawable 15761 * @hide 15762 */ 15763 protected void onDrawVerticalScrollBar(Canvas canvas, Drawable scrollBar, 15764 int l, int t, int r, int b) { 15765 scrollBar.setBounds(l, t, r, b); 15766 scrollBar.draw(canvas); 15767 } 15768 15769 /** 15770 * Implement this to do your drawing. 15771 * 15772 * @param canvas the canvas on which the background will be drawn 15773 */ 15774 protected void onDraw(Canvas canvas) { 15775 } 15776 15777 /* 15778 * Caller is responsible for calling requestLayout if necessary. 15779 * (This allows addViewInLayout to not request a new layout.) 15780 */ 15781 void assignParent(ViewParent parent) { 15782 if (mParent == null) { 15783 mParent = parent; 15784 } else if (parent == null) { 15785 mParent = null; 15786 } else { 15787 throw new RuntimeException("view " + this + " being added, but" 15788 + " it already has a parent"); 15789 } 15790 } 15791 15792 /** 15793 * This is called when the view is attached to a window. At this point it 15794 * has a Surface and will start drawing. Note that this function is 15795 * guaranteed to be called before {@link #onDraw(android.graphics.Canvas)}, 15796 * however it may be called any time before the first onDraw -- including 15797 * before or after {@link #onMeasure(int, int)}. 15798 * 15799 * @see #onDetachedFromWindow() 15800 */ 15801 @CallSuper 15802 protected void onAttachedToWindow() { 15803 if ((mPrivateFlags & PFLAG_REQUEST_TRANSPARENT_REGIONS) != 0) { 15804 mParent.requestTransparentRegion(this); 15805 } 15806 15807 mPrivateFlags3 &= ~PFLAG3_IS_LAID_OUT; 15808 15809 jumpDrawablesToCurrentState(); 15810 15811 resetSubtreeAccessibilityStateChanged(); 15812 15813 // rebuild, since Outline not maintained while View is detached 15814 rebuildOutline(); 15815 15816 if (isFocused()) { 15817 InputMethodManager imm = InputMethodManager.peekInstance(); 15818 if (imm != null) { 15819 imm.focusIn(this); 15820 } 15821 } 15822 } 15823 15824 /** 15825 * Resolve all RTL related properties. 15826 * 15827 * @return true if resolution of RTL properties has been done 15828 * 15829 * @hide 15830 */ 15831 public boolean resolveRtlPropertiesIfNeeded() { 15832 if (!needRtlPropertiesResolution()) return false; 15833 15834 // Order is important here: LayoutDirection MUST be resolved first 15835 if (!isLayoutDirectionResolved()) { 15836 resolveLayoutDirection(); 15837 resolveLayoutParams(); 15838 } 15839 // ... then we can resolve the others properties depending on the resolved LayoutDirection. 15840 if (!isTextDirectionResolved()) { 15841 resolveTextDirection(); 15842 } 15843 if (!isTextAlignmentResolved()) { 15844 resolveTextAlignment(); 15845 } 15846 // Should resolve Drawables before Padding because we need the layout direction of the 15847 // Drawable to correctly resolve Padding. 15848 if (!areDrawablesResolved()) { 15849 resolveDrawables(); 15850 } 15851 if (!isPaddingResolved()) { 15852 resolvePadding(); 15853 } 15854 onRtlPropertiesChanged(getLayoutDirection()); 15855 return true; 15856 } 15857 15858 /** 15859 * Reset resolution of all RTL related properties. 15860 * 15861 * @hide 15862 */ 15863 public void resetRtlProperties() { 15864 resetResolvedLayoutDirection(); 15865 resetResolvedTextDirection(); 15866 resetResolvedTextAlignment(); 15867 resetResolvedPadding(); 15868 resetResolvedDrawables(); 15869 } 15870 15871 /** 15872 * @see #onScreenStateChanged(int) 15873 */ 15874 void dispatchScreenStateChanged(int screenState) { 15875 onScreenStateChanged(screenState); 15876 } 15877 15878 /** 15879 * This method is called whenever the state of the screen this view is 15880 * attached to changes. A state change will usually occurs when the screen 15881 * turns on or off (whether it happens automatically or the user does it 15882 * manually.) 15883 * 15884 * @param screenState The new state of the screen. Can be either 15885 * {@link #SCREEN_STATE_ON} or {@link #SCREEN_STATE_OFF} 15886 */ 15887 public void onScreenStateChanged(int screenState) { 15888 } 15889 15890 /** 15891 * @see #onMovedToDisplay(int) 15892 */ 15893 void dispatchMovedToDisplay(Display display) { 15894 mAttachInfo.mDisplay = display; 15895 mAttachInfo.mDisplayState = display.getState(); 15896 onMovedToDisplay(display.getDisplayId()); 15897 } 15898 15899 /** 15900 * Called by the system when the hosting activity is moved from one display to another without 15901 * recreation. This means that the activity is declared to handle all changes to configuration 15902 * that happened when it was switched to another display, so it wasn't destroyed and created 15903 * again. This call will be followed by {@link #onConfigurationChanged(Configuration)} if the 15904 * applied configuration actually changed. 15905 * 15906 * <p>Use this callback to track changes to the displays if some functionality relies on an 15907 * association with some display properties. 15908 * 15909 * @param displayId The id of the display to which the view was moved. 15910 * 15911 * @see #onConfigurationChanged(Configuration) 15912 */ 15913 public void onMovedToDisplay(int displayId) { 15914 } 15915 15916 /** 15917 * Return true if the application tag in the AndroidManifest has set "supportRtl" to true 15918 */ 15919 private boolean hasRtlSupport() { 15920 return mContext.getApplicationInfo().hasRtlSupport(); 15921 } 15922 15923 /** 15924 * Return true if we are in RTL compatibility mode (either before Jelly Bean MR1 or 15925 * RTL not supported) 15926 */ 15927 private boolean isRtlCompatibilityMode() { 15928 final int targetSdkVersion = getContext().getApplicationInfo().targetSdkVersion; 15929 return targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR1 || !hasRtlSupport(); 15930 } 15931 15932 /** 15933 * @return true if RTL properties need resolution. 15934 * 15935 */ 15936 private boolean needRtlPropertiesResolution() { 15937 return (mPrivateFlags2 & ALL_RTL_PROPERTIES_RESOLVED) != ALL_RTL_PROPERTIES_RESOLVED; 15938 } 15939 15940 /** 15941 * Called when any RTL property (layout direction or text direction or text alignment) has 15942 * been changed. 15943 * 15944 * Subclasses need to override this method to take care of cached information that depends on the 15945 * resolved layout direction, or to inform child views that inherit their layout direction. 15946 * 15947 * The default implementation does nothing. 15948 * 15949 * @param layoutDirection the direction of the layout 15950 * 15951 * @see #LAYOUT_DIRECTION_LTR 15952 * @see #LAYOUT_DIRECTION_RTL 15953 */ 15954 public void onRtlPropertiesChanged(@ResolvedLayoutDir int layoutDirection) { 15955 } 15956 15957 /** 15958 * Resolve and cache the layout direction. LTR is set initially. This is implicitly supposing 15959 * that the parent directionality can and will be resolved before its children. 15960 * 15961 * @return true if resolution has been done, false otherwise. 15962 * 15963 * @hide 15964 */ 15965 public boolean resolveLayoutDirection() { 15966 // Clear any previous layout direction resolution 15967 mPrivateFlags2 &= ~PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK; 15968 15969 if (hasRtlSupport()) { 15970 // Set resolved depending on layout direction 15971 switch ((mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_MASK) >> 15972 PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT) { 15973 case LAYOUT_DIRECTION_INHERIT: 15974 // We cannot resolve yet. LTR is by default and let the resolution happen again 15975 // later to get the correct resolved value 15976 if (!canResolveLayoutDirection()) return false; 15977 15978 // Parent has not yet resolved, LTR is still the default 15979 try { 15980 if (!mParent.isLayoutDirectionResolved()) return false; 15981 15982 if (mParent.getLayoutDirection() == LAYOUT_DIRECTION_RTL) { 15983 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL; 15984 } 15985 } catch (AbstractMethodError e) { 15986 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 15987 " does not fully implement ViewParent", e); 15988 } 15989 break; 15990 case LAYOUT_DIRECTION_RTL: 15991 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL; 15992 break; 15993 case LAYOUT_DIRECTION_LOCALE: 15994 if((LAYOUT_DIRECTION_RTL == 15995 TextUtils.getLayoutDirectionFromLocale(Locale.getDefault()))) { 15996 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL; 15997 } 15998 break; 15999 default: 16000 // Nothing to do, LTR by default 16001 } 16002 } 16003 16004 // Set to resolved 16005 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED; 16006 return true; 16007 } 16008 16009 /** 16010 * Check if layout direction resolution can be done. 16011 * 16012 * @return true if layout direction resolution can be done otherwise return false. 16013 */ 16014 public boolean canResolveLayoutDirection() { 16015 switch (getRawLayoutDirection()) { 16016 case LAYOUT_DIRECTION_INHERIT: 16017 if (mParent != null) { 16018 try { 16019 return mParent.canResolveLayoutDirection(); 16020 } catch (AbstractMethodError e) { 16021 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 16022 " does not fully implement ViewParent", e); 16023 } 16024 } 16025 return false; 16026 16027 default: 16028 return true; 16029 } 16030 } 16031 16032 /** 16033 * Reset the resolved layout direction. Layout direction will be resolved during a call to 16034 * {@link #onMeasure(int, int)}. 16035 * 16036 * @hide 16037 */ 16038 public void resetResolvedLayoutDirection() { 16039 // Reset the current resolved bits 16040 mPrivateFlags2 &= ~PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK; 16041 } 16042 16043 /** 16044 * @return true if the layout direction is inherited. 16045 * 16046 * @hide 16047 */ 16048 public boolean isLayoutDirectionInherited() { 16049 return (getRawLayoutDirection() == LAYOUT_DIRECTION_INHERIT); 16050 } 16051 16052 /** 16053 * @return true if layout direction has been resolved. 16054 */ 16055 public boolean isLayoutDirectionResolved() { 16056 return (mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_RESOLVED) == PFLAG2_LAYOUT_DIRECTION_RESOLVED; 16057 } 16058 16059 /** 16060 * Return if padding has been resolved 16061 * 16062 * @hide 16063 */ 16064 boolean isPaddingResolved() { 16065 return (mPrivateFlags2 & PFLAG2_PADDING_RESOLVED) == PFLAG2_PADDING_RESOLVED; 16066 } 16067 16068 /** 16069 * Resolves padding depending on layout direction, if applicable, and 16070 * recomputes internal padding values to adjust for scroll bars. 16071 * 16072 * @hide 16073 */ 16074 public void resolvePadding() { 16075 final int resolvedLayoutDirection = getLayoutDirection(); 16076 16077 if (!isRtlCompatibilityMode()) { 16078 // Post Jelly Bean MR1 case: we need to take the resolved layout direction into account. 16079 // If start / end padding are defined, they will be resolved (hence overriding) to 16080 // left / right or right / left depending on the resolved layout direction. 16081 // If start / end padding are not defined, use the left / right ones. 16082 if (mBackground != null && (!mLeftPaddingDefined || !mRightPaddingDefined)) { 16083 Rect padding = sThreadLocal.get(); 16084 if (padding == null) { 16085 padding = new Rect(); 16086 sThreadLocal.set(padding); 16087 } 16088 mBackground.getPadding(padding); 16089 if (!mLeftPaddingDefined) { 16090 mUserPaddingLeftInitial = padding.left; 16091 } 16092 if (!mRightPaddingDefined) { 16093 mUserPaddingRightInitial = padding.right; 16094 } 16095 } 16096 switch (resolvedLayoutDirection) { 16097 case LAYOUT_DIRECTION_RTL: 16098 if (mUserPaddingStart != UNDEFINED_PADDING) { 16099 mUserPaddingRight = mUserPaddingStart; 16100 } else { 16101 mUserPaddingRight = mUserPaddingRightInitial; 16102 } 16103 if (mUserPaddingEnd != UNDEFINED_PADDING) { 16104 mUserPaddingLeft = mUserPaddingEnd; 16105 } else { 16106 mUserPaddingLeft = mUserPaddingLeftInitial; 16107 } 16108 break; 16109 case LAYOUT_DIRECTION_LTR: 16110 default: 16111 if (mUserPaddingStart != UNDEFINED_PADDING) { 16112 mUserPaddingLeft = mUserPaddingStart; 16113 } else { 16114 mUserPaddingLeft = mUserPaddingLeftInitial; 16115 } 16116 if (mUserPaddingEnd != UNDEFINED_PADDING) { 16117 mUserPaddingRight = mUserPaddingEnd; 16118 } else { 16119 mUserPaddingRight = mUserPaddingRightInitial; 16120 } 16121 } 16122 16123 mUserPaddingBottom = (mUserPaddingBottom >= 0) ? mUserPaddingBottom : mPaddingBottom; 16124 } 16125 16126 internalSetPadding(mUserPaddingLeft, mPaddingTop, mUserPaddingRight, mUserPaddingBottom); 16127 onRtlPropertiesChanged(resolvedLayoutDirection); 16128 16129 mPrivateFlags2 |= PFLAG2_PADDING_RESOLVED; 16130 } 16131 16132 /** 16133 * Reset the resolved layout direction. 16134 * 16135 * @hide 16136 */ 16137 public void resetResolvedPadding() { 16138 resetResolvedPaddingInternal(); 16139 } 16140 16141 /** 16142 * Used when we only want to reset *this* view's padding and not trigger overrides 16143 * in ViewGroup that reset children too. 16144 */ 16145 void resetResolvedPaddingInternal() { 16146 mPrivateFlags2 &= ~PFLAG2_PADDING_RESOLVED; 16147 } 16148 16149 /** 16150 * This is called when the view is detached from a window. At this point it 16151 * no longer has a surface for drawing. 16152 * 16153 * @see #onAttachedToWindow() 16154 */ 16155 @CallSuper 16156 protected void onDetachedFromWindow() { 16157 } 16158 16159 /** 16160 * This is a framework-internal mirror of onDetachedFromWindow() that's called 16161 * after onDetachedFromWindow(). 16162 * 16163 * If you override this you *MUST* call super.onDetachedFromWindowInternal()! 16164 * The super method should be called at the end of the overridden method to ensure 16165 * subclasses are destroyed first 16166 * 16167 * @hide 16168 */ 16169 @CallSuper 16170 protected void onDetachedFromWindowInternal() { 16171 mPrivateFlags &= ~PFLAG_CANCEL_NEXT_UP_EVENT; 16172 mPrivateFlags3 &= ~PFLAG3_IS_LAID_OUT; 16173 mPrivateFlags3 &= ~PFLAG3_TEMPORARY_DETACH; 16174 16175 removeUnsetPressCallback(); 16176 removeLongPressCallback(); 16177 removePerformClickCallback(); 16178 removeSendViewScrolledAccessibilityEventCallback(); 16179 stopNestedScroll(); 16180 16181 // Anything that started animating right before detach should already 16182 // be in its final state when re-attached. 16183 jumpDrawablesToCurrentState(); 16184 16185 destroyDrawingCache(); 16186 16187 cleanupDraw(); 16188 mCurrentAnimation = null; 16189 16190 if ((mViewFlags & TOOLTIP) == TOOLTIP) { 16191 hideTooltip(); 16192 } 16193 } 16194 16195 private void cleanupDraw() { 16196 resetDisplayList(); 16197 if (mAttachInfo != null) { 16198 mAttachInfo.mViewRootImpl.cancelInvalidate(this); 16199 } 16200 } 16201 16202 void invalidateInheritedLayoutMode(int layoutModeOfRoot) { 16203 } 16204 16205 /** 16206 * @return The number of times this view has been attached to a window 16207 */ 16208 protected int getWindowAttachCount() { 16209 return mWindowAttachCount; 16210 } 16211 16212 /** 16213 * Retrieve a unique token identifying the window this view is attached to. 16214 * @return Return the window's token for use in 16215 * {@link WindowManager.LayoutParams#token WindowManager.LayoutParams.token}. 16216 */ 16217 public IBinder getWindowToken() { 16218 return mAttachInfo != null ? mAttachInfo.mWindowToken : null; 16219 } 16220 16221 /** 16222 * Retrieve the {@link WindowId} for the window this view is 16223 * currently attached to. 16224 */ 16225 public WindowId getWindowId() { 16226 if (mAttachInfo == null) { 16227 return null; 16228 } 16229 if (mAttachInfo.mWindowId == null) { 16230 try { 16231 mAttachInfo.mIWindowId = mAttachInfo.mSession.getWindowId( 16232 mAttachInfo.mWindowToken); 16233 mAttachInfo.mWindowId = new WindowId( 16234 mAttachInfo.mIWindowId); 16235 } catch (RemoteException e) { 16236 } 16237 } 16238 return mAttachInfo.mWindowId; 16239 } 16240 16241 /** 16242 * Retrieve a unique token identifying the top-level "real" window of 16243 * the window that this view is attached to. That is, this is like 16244 * {@link #getWindowToken}, except if the window this view in is a panel 16245 * window (attached to another containing window), then the token of 16246 * the containing window is returned instead. 16247 * 16248 * @return Returns the associated window token, either 16249 * {@link #getWindowToken()} or the containing window's token. 16250 */ 16251 public IBinder getApplicationWindowToken() { 16252 AttachInfo ai = mAttachInfo; 16253 if (ai != null) { 16254 IBinder appWindowToken = ai.mPanelParentWindowToken; 16255 if (appWindowToken == null) { 16256 appWindowToken = ai.mWindowToken; 16257 } 16258 return appWindowToken; 16259 } 16260 return null; 16261 } 16262 16263 /** 16264 * Gets the logical display to which the view's window has been attached. 16265 * 16266 * @return The logical display, or null if the view is not currently attached to a window. 16267 */ 16268 public Display getDisplay() { 16269 return mAttachInfo != null ? mAttachInfo.mDisplay : null; 16270 } 16271 16272 /** 16273 * Retrieve private session object this view hierarchy is using to 16274 * communicate with the window manager. 16275 * @return the session object to communicate with the window manager 16276 */ 16277 /*package*/ IWindowSession getWindowSession() { 16278 return mAttachInfo != null ? mAttachInfo.mSession : null; 16279 } 16280 16281 /** 16282 * Return the visibility value of the least visible component passed. 16283 */ 16284 int combineVisibility(int vis1, int vis2) { 16285 // This works because VISIBLE < INVISIBLE < GONE. 16286 return Math.max(vis1, vis2); 16287 } 16288 16289 /** 16290 * @param info the {@link android.view.View.AttachInfo} to associated with 16291 * this view 16292 */ 16293 void dispatchAttachedToWindow(AttachInfo info, int visibility) { 16294 mAttachInfo = info; 16295 if (mOverlay != null) { 16296 mOverlay.getOverlayView().dispatchAttachedToWindow(info, visibility); 16297 } 16298 mWindowAttachCount++; 16299 // We will need to evaluate the drawable state at least once. 16300 mPrivateFlags |= PFLAG_DRAWABLE_STATE_DIRTY; 16301 if (mFloatingTreeObserver != null) { 16302 info.mTreeObserver.merge(mFloatingTreeObserver); 16303 mFloatingTreeObserver = null; 16304 } 16305 16306 registerPendingFrameMetricsObservers(); 16307 16308 if ((mPrivateFlags&PFLAG_SCROLL_CONTAINER) != 0) { 16309 mAttachInfo.mScrollContainers.add(this); 16310 mPrivateFlags |= PFLAG_SCROLL_CONTAINER_ADDED; 16311 } 16312 // Transfer all pending runnables. 16313 if (mRunQueue != null) { 16314 mRunQueue.executeActions(info.mHandler); 16315 mRunQueue = null; 16316 } 16317 performCollectViewAttributes(mAttachInfo, visibility); 16318 onAttachedToWindow(); 16319 16320 ListenerInfo li = mListenerInfo; 16321 final CopyOnWriteArrayList<OnAttachStateChangeListener> listeners = 16322 li != null ? li.mOnAttachStateChangeListeners : null; 16323 if (listeners != null && listeners.size() > 0) { 16324 // NOTE: because of the use of CopyOnWriteArrayList, we *must* use an iterator to 16325 // perform the dispatching. The iterator is a safe guard against listeners that 16326 // could mutate the list by calling the various add/remove methods. This prevents 16327 // the array from being modified while we iterate it. 16328 for (OnAttachStateChangeListener listener : listeners) { 16329 listener.onViewAttachedToWindow(this); 16330 } 16331 } 16332 16333 int vis = info.mWindowVisibility; 16334 if (vis != GONE) { 16335 onWindowVisibilityChanged(vis); 16336 if (isShown()) { 16337 // Calling onVisibilityAggregated directly here since the subtree will also 16338 // receive dispatchAttachedToWindow and this same call 16339 onVisibilityAggregated(vis == VISIBLE); 16340 } 16341 } 16342 16343 // Send onVisibilityChanged directly instead of dispatchVisibilityChanged. 16344 // As all views in the subtree will already receive dispatchAttachedToWindow 16345 // traversing the subtree again here is not desired. 16346 onVisibilityChanged(this, visibility); 16347 16348 if ((mPrivateFlags&PFLAG_DRAWABLE_STATE_DIRTY) != 0) { 16349 // If nobody has evaluated the drawable state yet, then do it now. 16350 refreshDrawableState(); 16351 } 16352 needGlobalAttributesUpdate(false); 16353 } 16354 16355 void dispatchDetachedFromWindow() { 16356 AttachInfo info = mAttachInfo; 16357 if (info != null) { 16358 int vis = info.mWindowVisibility; 16359 if (vis != GONE) { 16360 onWindowVisibilityChanged(GONE); 16361 if (isShown()) { 16362 // Invoking onVisibilityAggregated directly here since the subtree 16363 // will also receive detached from window 16364 onVisibilityAggregated(false); 16365 } 16366 } 16367 } 16368 16369 onDetachedFromWindow(); 16370 onDetachedFromWindowInternal(); 16371 16372 InputMethodManager imm = InputMethodManager.peekInstance(); 16373 if (imm != null) { 16374 imm.onViewDetachedFromWindow(this); 16375 } 16376 16377 ListenerInfo li = mListenerInfo; 16378 final CopyOnWriteArrayList<OnAttachStateChangeListener> listeners = 16379 li != null ? li.mOnAttachStateChangeListeners : null; 16380 if (listeners != null && listeners.size() > 0) { 16381 // NOTE: because of the use of CopyOnWriteArrayList, we *must* use an iterator to 16382 // perform the dispatching. The iterator is a safe guard against listeners that 16383 // could mutate the list by calling the various add/remove methods. This prevents 16384 // the array from being modified while we iterate it. 16385 for (OnAttachStateChangeListener listener : listeners) { 16386 listener.onViewDetachedFromWindow(this); 16387 } 16388 } 16389 16390 if ((mPrivateFlags & PFLAG_SCROLL_CONTAINER_ADDED) != 0) { 16391 mAttachInfo.mScrollContainers.remove(this); 16392 mPrivateFlags &= ~PFLAG_SCROLL_CONTAINER_ADDED; 16393 } 16394 16395 mAttachInfo = null; 16396 if (mOverlay != null) { 16397 mOverlay.getOverlayView().dispatchDetachedFromWindow(); 16398 } 16399 } 16400 16401 /** 16402 * Cancel any deferred high-level input events that were previously posted to the event queue. 16403 * 16404 * <p>Many views post high-level events such as click handlers to the event queue 16405 * to run deferred in order to preserve a desired user experience - clearing visible 16406 * pressed states before executing, etc. This method will abort any events of this nature 16407 * that are currently in flight.</p> 16408 * 16409 * <p>Custom views that generate their own high-level deferred input events should override 16410 * {@link #onCancelPendingInputEvents()} and remove those pending events from the queue.</p> 16411 * 16412 * <p>This will also cancel pending input events for any child views.</p> 16413 * 16414 * <p>Note that this may not be sufficient as a debouncing strategy for clicks in all cases. 16415 * This will not impact newer events posted after this call that may occur as a result of 16416 * lower-level input events still waiting in the queue. If you are trying to prevent 16417 * double-submitted events for the duration of some sort of asynchronous transaction 16418 * you should also take other steps to protect against unexpected double inputs e.g. calling 16419 * {@link #setEnabled(boolean) setEnabled(false)} and re-enabling the view when 16420 * the transaction completes, tracking already submitted transaction IDs, etc.</p> 16421 */ 16422 public final void cancelPendingInputEvents() { 16423 dispatchCancelPendingInputEvents(); 16424 } 16425 16426 /** 16427 * Called by {@link #cancelPendingInputEvents()} to cancel input events in flight. 16428 * Overridden by ViewGroup to dispatch. Package scoped to prevent app-side meddling. 16429 */ 16430 void dispatchCancelPendingInputEvents() { 16431 mPrivateFlags3 &= ~PFLAG3_CALLED_SUPER; 16432 onCancelPendingInputEvents(); 16433 if ((mPrivateFlags3 & PFLAG3_CALLED_SUPER) != PFLAG3_CALLED_SUPER) { 16434 throw new SuperNotCalledException("View " + getClass().getSimpleName() + 16435 " did not call through to super.onCancelPendingInputEvents()"); 16436 } 16437 } 16438 16439 /** 16440 * Called as the result of a call to {@link #cancelPendingInputEvents()} on this view or 16441 * a parent view. 16442 * 16443 * <p>This method is responsible for removing any pending high-level input events that were 16444 * posted to the event queue to run later. Custom view classes that post their own deferred 16445 * high-level events via {@link #post(Runnable)}, {@link #postDelayed(Runnable, long)} or 16446 * {@link android.os.Handler} should override this method, call 16447 * <code>super.onCancelPendingInputEvents()</code> and remove those callbacks as appropriate. 16448 * </p> 16449 */ 16450 public void onCancelPendingInputEvents() { 16451 removePerformClickCallback(); 16452 cancelLongPress(); 16453 mPrivateFlags3 |= PFLAG3_CALLED_SUPER; 16454 } 16455 16456 /** 16457 * Store this view hierarchy's frozen state into the given container. 16458 * 16459 * @param container The SparseArray in which to save the view's state. 16460 * 16461 * @see #restoreHierarchyState(android.util.SparseArray) 16462 * @see #dispatchSaveInstanceState(android.util.SparseArray) 16463 * @see #onSaveInstanceState() 16464 */ 16465 public void saveHierarchyState(SparseArray<Parcelable> container) { 16466 dispatchSaveInstanceState(container); 16467 } 16468 16469 /** 16470 * Called by {@link #saveHierarchyState(android.util.SparseArray)} to store the state for 16471 * this view and its children. May be overridden to modify how freezing happens to a 16472 * view's children; for example, some views may want to not store state for their children. 16473 * 16474 * @param container The SparseArray in which to save the view's state. 16475 * 16476 * @see #dispatchRestoreInstanceState(android.util.SparseArray) 16477 * @see #saveHierarchyState(android.util.SparseArray) 16478 * @see #onSaveInstanceState() 16479 */ 16480 protected void dispatchSaveInstanceState(SparseArray<Parcelable> container) { 16481 if (mID != NO_ID && (mViewFlags & SAVE_DISABLED_MASK) == 0) { 16482 mPrivateFlags &= ~PFLAG_SAVE_STATE_CALLED; 16483 Parcelable state = onSaveInstanceState(); 16484 if ((mPrivateFlags & PFLAG_SAVE_STATE_CALLED) == 0) { 16485 throw new IllegalStateException( 16486 "Derived class did not call super.onSaveInstanceState()"); 16487 } 16488 if (state != null) { 16489 // Log.i("View", "Freezing #" + Integer.toHexString(mID) 16490 // + ": " + state); 16491 container.put(mID, state); 16492 } 16493 } 16494 } 16495 16496 /** 16497 * Hook allowing a view to generate a representation of its internal state 16498 * that can later be used to create a new instance with that same state. 16499 * This state should only contain information that is not persistent or can 16500 * not be reconstructed later. For example, you will never store your 16501 * current position on screen because that will be computed again when a 16502 * new instance of the view is placed in its view hierarchy. 16503 * <p> 16504 * Some examples of things you may store here: the current cursor position 16505 * in a text view (but usually not the text itself since that is stored in a 16506 * content provider or other persistent storage), the currently selected 16507 * item in a list view. 16508 * 16509 * @return Returns a Parcelable object containing the view's current dynamic 16510 * state, or null if there is nothing interesting to save. The 16511 * default implementation returns null. 16512 * @see #onRestoreInstanceState(android.os.Parcelable) 16513 * @see #saveHierarchyState(android.util.SparseArray) 16514 * @see #dispatchSaveInstanceState(android.util.SparseArray) 16515 * @see #setSaveEnabled(boolean) 16516 */ 16517 @CallSuper 16518 protected Parcelable onSaveInstanceState() { 16519 mPrivateFlags |= PFLAG_SAVE_STATE_CALLED; 16520 if (mStartActivityRequestWho != null) { 16521 BaseSavedState state = new BaseSavedState(AbsSavedState.EMPTY_STATE); 16522 state.mStartActivityRequestWhoSaved = mStartActivityRequestWho; 16523 return state; 16524 } 16525 return BaseSavedState.EMPTY_STATE; 16526 } 16527 16528 /** 16529 * Restore this view hierarchy's frozen state from the given container. 16530 * 16531 * @param container The SparseArray which holds previously frozen states. 16532 * 16533 * @see #saveHierarchyState(android.util.SparseArray) 16534 * @see #dispatchRestoreInstanceState(android.util.SparseArray) 16535 * @see #onRestoreInstanceState(android.os.Parcelable) 16536 */ 16537 public void restoreHierarchyState(SparseArray<Parcelable> container) { 16538 dispatchRestoreInstanceState(container); 16539 } 16540 16541 /** 16542 * Called by {@link #restoreHierarchyState(android.util.SparseArray)} to retrieve the 16543 * state for this view and its children. May be overridden to modify how restoring 16544 * happens to a view's children; for example, some views may want to not store state 16545 * for their children. 16546 * 16547 * @param container The SparseArray which holds previously saved state. 16548 * 16549 * @see #dispatchSaveInstanceState(android.util.SparseArray) 16550 * @see #restoreHierarchyState(android.util.SparseArray) 16551 * @see #onRestoreInstanceState(android.os.Parcelable) 16552 */ 16553 protected void dispatchRestoreInstanceState(SparseArray<Parcelable> container) { 16554 if (mID != NO_ID) { 16555 Parcelable state = container.get(mID); 16556 if (state != null) { 16557 // Log.i("View", "Restoreing #" + Integer.toHexString(mID) 16558 // + ": " + state); 16559 mPrivateFlags &= ~PFLAG_SAVE_STATE_CALLED; 16560 onRestoreInstanceState(state); 16561 if ((mPrivateFlags & PFLAG_SAVE_STATE_CALLED) == 0) { 16562 throw new IllegalStateException( 16563 "Derived class did not call super.onRestoreInstanceState()"); 16564 } 16565 } 16566 } 16567 } 16568 16569 /** 16570 * Hook allowing a view to re-apply a representation of its internal state that had previously 16571 * been generated by {@link #onSaveInstanceState}. This function will never be called with a 16572 * null state. 16573 * 16574 * @param state The frozen state that had previously been returned by 16575 * {@link #onSaveInstanceState}. 16576 * 16577 * @see #onSaveInstanceState() 16578 * @see #restoreHierarchyState(android.util.SparseArray) 16579 * @see #dispatchRestoreInstanceState(android.util.SparseArray) 16580 */ 16581 @CallSuper 16582 protected void onRestoreInstanceState(Parcelable state) { 16583 mPrivateFlags |= PFLAG_SAVE_STATE_CALLED; 16584 if (state != null && !(state instanceof AbsSavedState)) { 16585 throw new IllegalArgumentException("Wrong state class, expecting View State but " 16586 + "received " + state.getClass().toString() + " instead. This usually happens " 16587 + "when two views of different type have the same id in the same hierarchy. " 16588 + "This view's id is " + ViewDebug.resolveId(mContext, getId()) + ". Make sure " 16589 + "other views do not use the same id."); 16590 } 16591 if (state != null && state instanceof BaseSavedState) { 16592 mStartActivityRequestWho = ((BaseSavedState) state).mStartActivityRequestWhoSaved; 16593 } 16594 } 16595 16596 /** 16597 * <p>Return the time at which the drawing of the view hierarchy started.</p> 16598 * 16599 * @return the drawing start time in milliseconds 16600 */ 16601 public long getDrawingTime() { 16602 return mAttachInfo != null ? mAttachInfo.mDrawingTime : 0; 16603 } 16604 16605 /** 16606 * <p>Enables or disables the duplication of the parent's state into this view. When 16607 * duplication is enabled, this view gets its drawable state from its parent rather 16608 * than from its own internal properties.</p> 16609 * 16610 * <p>Note: in the current implementation, setting this property to true after the 16611 * view was added to a ViewGroup might have no effect at all. This property should 16612 * always be used from XML or set to true before adding this view to a ViewGroup.</p> 16613 * 16614 * <p>Note: if this view's parent addStateFromChildren property is enabled and this 16615 * property is enabled, an exception will be thrown.</p> 16616 * 16617 * <p>Note: if the child view uses and updates additional states which are unknown to the 16618 * parent, these states should not be affected by this method.</p> 16619 * 16620 * @param enabled True to enable duplication of the parent's drawable state, false 16621 * to disable it. 16622 * 16623 * @see #getDrawableState() 16624 * @see #isDuplicateParentStateEnabled() 16625 */ 16626 public void setDuplicateParentStateEnabled(boolean enabled) { 16627 setFlags(enabled ? DUPLICATE_PARENT_STATE : 0, DUPLICATE_PARENT_STATE); 16628 } 16629 16630 /** 16631 * <p>Indicates whether this duplicates its drawable state from its parent.</p> 16632 * 16633 * @return True if this view's drawable state is duplicated from the parent, 16634 * false otherwise 16635 * 16636 * @see #getDrawableState() 16637 * @see #setDuplicateParentStateEnabled(boolean) 16638 */ 16639 public boolean isDuplicateParentStateEnabled() { 16640 return (mViewFlags & DUPLICATE_PARENT_STATE) == DUPLICATE_PARENT_STATE; 16641 } 16642 16643 /** 16644 * <p>Specifies the type of layer backing this view. The layer can be 16645 * {@link #LAYER_TYPE_NONE}, {@link #LAYER_TYPE_SOFTWARE} or 16646 * {@link #LAYER_TYPE_HARDWARE}.</p> 16647 * 16648 * <p>A layer is associated with an optional {@link android.graphics.Paint} 16649 * instance that controls how the layer is composed on screen. The following 16650 * properties of the paint are taken into account when composing the layer:</p> 16651 * <ul> 16652 * <li>{@link android.graphics.Paint#getAlpha() Translucency (alpha)}</li> 16653 * <li>{@link android.graphics.Paint#getXfermode() Blending mode}</li> 16654 * <li>{@link android.graphics.Paint#getColorFilter() Color filter}</li> 16655 * </ul> 16656 * 16657 * <p>If this view has an alpha value set to < 1.0 by calling 16658 * {@link #setAlpha(float)}, the alpha value of the layer's paint is superseded 16659 * by this view's alpha value.</p> 16660 * 16661 * <p>Refer to the documentation of {@link #LAYER_TYPE_NONE}, 16662 * {@link #LAYER_TYPE_SOFTWARE} and {@link #LAYER_TYPE_HARDWARE} 16663 * for more information on when and how to use layers.</p> 16664 * 16665 * @param layerType The type of layer to use with this view, must be one of 16666 * {@link #LAYER_TYPE_NONE}, {@link #LAYER_TYPE_SOFTWARE} or 16667 * {@link #LAYER_TYPE_HARDWARE} 16668 * @param paint The paint used to compose the layer. This argument is optional 16669 * and can be null. It is ignored when the layer type is 16670 * {@link #LAYER_TYPE_NONE} 16671 * 16672 * @see #getLayerType() 16673 * @see #LAYER_TYPE_NONE 16674 * @see #LAYER_TYPE_SOFTWARE 16675 * @see #LAYER_TYPE_HARDWARE 16676 * @see #setAlpha(float) 16677 * 16678 * @attr ref android.R.styleable#View_layerType 16679 */ 16680 public void setLayerType(int layerType, @Nullable Paint paint) { 16681 if (layerType < LAYER_TYPE_NONE || layerType > LAYER_TYPE_HARDWARE) { 16682 throw new IllegalArgumentException("Layer type can only be one of: LAYER_TYPE_NONE, " 16683 + "LAYER_TYPE_SOFTWARE or LAYER_TYPE_HARDWARE"); 16684 } 16685 16686 boolean typeChanged = mRenderNode.setLayerType(layerType); 16687 16688 if (!typeChanged) { 16689 setLayerPaint(paint); 16690 return; 16691 } 16692 16693 if (layerType != LAYER_TYPE_SOFTWARE) { 16694 // Destroy any previous software drawing cache if present 16695 // NOTE: even if previous layer type is HW, we do this to ensure we've cleaned up 16696 // drawing cache created in View#draw when drawing to a SW canvas. 16697 destroyDrawingCache(); 16698 } 16699 16700 mLayerType = layerType; 16701 mLayerPaint = mLayerType == LAYER_TYPE_NONE ? null : paint; 16702 mRenderNode.setLayerPaint(mLayerPaint); 16703 16704 // draw() behaves differently if we are on a layer, so we need to 16705 // invalidate() here 16706 invalidateParentCaches(); 16707 invalidate(true); 16708 } 16709 16710 /** 16711 * Updates the {@link Paint} object used with the current layer (used only if the current 16712 * layer type is not set to {@link #LAYER_TYPE_NONE}). Changed properties of the Paint 16713 * provided to {@link #setLayerType(int, android.graphics.Paint)} will be used the next time 16714 * the View is redrawn, but {@link #setLayerPaint(android.graphics.Paint)} must be called to 16715 * ensure that the view gets redrawn immediately. 16716 * 16717 * <p>A layer is associated with an optional {@link android.graphics.Paint} 16718 * instance that controls how the layer is composed on screen. The following 16719 * properties of the paint are taken into account when composing the layer:</p> 16720 * <ul> 16721 * <li>{@link android.graphics.Paint#getAlpha() Translucency (alpha)}</li> 16722 * <li>{@link android.graphics.Paint#getXfermode() Blending mode}</li> 16723 * <li>{@link android.graphics.Paint#getColorFilter() Color filter}</li> 16724 * </ul> 16725 * 16726 * <p>If this view has an alpha value set to < 1.0 by calling {@link #setAlpha(float)}, the 16727 * alpha value of the layer's paint is superseded by this view's alpha value.</p> 16728 * 16729 * @param paint The paint used to compose the layer. This argument is optional 16730 * and can be null. It is ignored when the layer type is 16731 * {@link #LAYER_TYPE_NONE} 16732 * 16733 * @see #setLayerType(int, android.graphics.Paint) 16734 */ 16735 public void setLayerPaint(@Nullable Paint paint) { 16736 int layerType = getLayerType(); 16737 if (layerType != LAYER_TYPE_NONE) { 16738 mLayerPaint = paint; 16739 if (layerType == LAYER_TYPE_HARDWARE) { 16740 if (mRenderNode.setLayerPaint(paint)) { 16741 invalidateViewProperty(false, false); 16742 } 16743 } else { 16744 invalidate(); 16745 } 16746 } 16747 } 16748 16749 /** 16750 * Indicates what type of layer is currently associated with this view. By default 16751 * a view does not have a layer, and the layer type is {@link #LAYER_TYPE_NONE}. 16752 * Refer to the documentation of {@link #setLayerType(int, android.graphics.Paint)} 16753 * for more information on the different types of layers. 16754 * 16755 * @return {@link #LAYER_TYPE_NONE}, {@link #LAYER_TYPE_SOFTWARE} or 16756 * {@link #LAYER_TYPE_HARDWARE} 16757 * 16758 * @see #setLayerType(int, android.graphics.Paint) 16759 * @see #buildLayer() 16760 * @see #LAYER_TYPE_NONE 16761 * @see #LAYER_TYPE_SOFTWARE 16762 * @see #LAYER_TYPE_HARDWARE 16763 */ 16764 public int getLayerType() { 16765 return mLayerType; 16766 } 16767 16768 /** 16769 * Forces this view's layer to be created and this view to be rendered 16770 * into its layer. If this view's layer type is set to {@link #LAYER_TYPE_NONE}, 16771 * invoking this method will have no effect. 16772 * 16773 * This method can for instance be used to render a view into its layer before 16774 * starting an animation. If this view is complex, rendering into the layer 16775 * before starting the animation will avoid skipping frames. 16776 * 16777 * @throws IllegalStateException If this view is not attached to a window 16778 * 16779 * @see #setLayerType(int, android.graphics.Paint) 16780 */ 16781 public void buildLayer() { 16782 if (mLayerType == LAYER_TYPE_NONE) return; 16783 16784 final AttachInfo attachInfo = mAttachInfo; 16785 if (attachInfo == null) { 16786 throw new IllegalStateException("This view must be attached to a window first"); 16787 } 16788 16789 if (getWidth() == 0 || getHeight() == 0) { 16790 return; 16791 } 16792 16793 switch (mLayerType) { 16794 case LAYER_TYPE_HARDWARE: 16795 updateDisplayListIfDirty(); 16796 if (attachInfo.mThreadedRenderer != null && mRenderNode.isValid()) { 16797 attachInfo.mThreadedRenderer.buildLayer(mRenderNode); 16798 } 16799 break; 16800 case LAYER_TYPE_SOFTWARE: 16801 buildDrawingCache(true); 16802 break; 16803 } 16804 } 16805 16806 /** 16807 * Destroys all hardware rendering resources. This method is invoked 16808 * when the system needs to reclaim resources. Upon execution of this 16809 * method, you should free any OpenGL resources created by the view. 16810 * 16811 * Note: you <strong>must</strong> call 16812 * <code>super.destroyHardwareResources()</code> when overriding 16813 * this method. 16814 * 16815 * @hide 16816 */ 16817 @CallSuper 16818 protected void destroyHardwareResources() { 16819 if (mOverlay != null) { 16820 mOverlay.getOverlayView().destroyHardwareResources(); 16821 } 16822 if (mGhostView != null) { 16823 mGhostView.destroyHardwareResources(); 16824 } 16825 } 16826 16827 /** 16828 * <p>Enables or disables the drawing cache. When the drawing cache is enabled, the next call 16829 * to {@link #getDrawingCache()} or {@link #buildDrawingCache()} will draw the view in a 16830 * bitmap. Calling {@link #draw(android.graphics.Canvas)} will not draw from the cache when 16831 * the cache is enabled. To benefit from the cache, you must request the drawing cache by 16832 * calling {@link #getDrawingCache()} and draw it on screen if the returned bitmap is not 16833 * null.</p> 16834 * 16835 * <p>Enabling the drawing cache is similar to 16836 * {@link #setLayerType(int, android.graphics.Paint) setting a layer} when hardware 16837 * acceleration is turned off. When hardware acceleration is turned on, enabling the 16838 * drawing cache has no effect on rendering because the system uses a different mechanism 16839 * for acceleration which ignores the flag. If you want to use a Bitmap for the view, even 16840 * when hardware acceleration is enabled, see {@link #setLayerType(int, android.graphics.Paint)} 16841 * for information on how to enable software and hardware layers.</p> 16842 * 16843 * <p>This API can be used to manually generate 16844 * a bitmap copy of this view, by setting the flag to <code>true</code> and calling 16845 * {@link #getDrawingCache()}.</p> 16846 * 16847 * @param enabled true to enable the drawing cache, false otherwise 16848 * 16849 * @see #isDrawingCacheEnabled() 16850 * @see #getDrawingCache() 16851 * @see #buildDrawingCache() 16852 * @see #setLayerType(int, android.graphics.Paint) 16853 */ 16854 public void setDrawingCacheEnabled(boolean enabled) { 16855 mCachingFailed = false; 16856 setFlags(enabled ? DRAWING_CACHE_ENABLED : 0, DRAWING_CACHE_ENABLED); 16857 } 16858 16859 /** 16860 * <p>Indicates whether the drawing cache is enabled for this view.</p> 16861 * 16862 * @return true if the drawing cache is enabled 16863 * 16864 * @see #setDrawingCacheEnabled(boolean) 16865 * @see #getDrawingCache() 16866 */ 16867 @ViewDebug.ExportedProperty(category = "drawing") 16868 public boolean isDrawingCacheEnabled() { 16869 return (mViewFlags & DRAWING_CACHE_ENABLED) == DRAWING_CACHE_ENABLED; 16870 } 16871 16872 /** 16873 * Debugging utility which recursively outputs the dirty state of a view and its 16874 * descendants. 16875 * 16876 * @hide 16877 */ 16878 @SuppressWarnings({"UnusedDeclaration"}) 16879 public void outputDirtyFlags(String indent, boolean clear, int clearMask) { 16880 Log.d("View", indent + this + " DIRTY(" + (mPrivateFlags & View.PFLAG_DIRTY_MASK) + 16881 ") DRAWN(" + (mPrivateFlags & PFLAG_DRAWN) + ")" + " CACHE_VALID(" + 16882 (mPrivateFlags & View.PFLAG_DRAWING_CACHE_VALID) + 16883 ") INVALIDATED(" + (mPrivateFlags & PFLAG_INVALIDATED) + ")"); 16884 if (clear) { 16885 mPrivateFlags &= clearMask; 16886 } 16887 if (this instanceof ViewGroup) { 16888 ViewGroup parent = (ViewGroup) this; 16889 final int count = parent.getChildCount(); 16890 for (int i = 0; i < count; i++) { 16891 final View child = parent.getChildAt(i); 16892 child.outputDirtyFlags(indent + " ", clear, clearMask); 16893 } 16894 } 16895 } 16896 16897 /** 16898 * This method is used by ViewGroup to cause its children to restore or recreate their 16899 * display lists. It is called by getDisplayList() when the parent ViewGroup does not need 16900 * to recreate its own display list, which would happen if it went through the normal 16901 * draw/dispatchDraw mechanisms. 16902 * 16903 * @hide 16904 */ 16905 protected void dispatchGetDisplayList() {} 16906 16907 /** 16908 * A view that is not attached or hardware accelerated cannot create a display list. 16909 * This method checks these conditions and returns the appropriate result. 16910 * 16911 * @return true if view has the ability to create a display list, false otherwise. 16912 * 16913 * @hide 16914 */ 16915 public boolean canHaveDisplayList() { 16916 return !(mAttachInfo == null || mAttachInfo.mThreadedRenderer == null); 16917 } 16918 16919 /** 16920 * Gets the RenderNode for the view, and updates its DisplayList (if needed and supported) 16921 * @hide 16922 */ 16923 @NonNull 16924 public RenderNode updateDisplayListIfDirty() { 16925 final RenderNode renderNode = mRenderNode; 16926 if (!canHaveDisplayList()) { 16927 // can't populate RenderNode, don't try 16928 return renderNode; 16929 } 16930 16931 if ((mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == 0 16932 || !renderNode.isValid() 16933 || (mRecreateDisplayList)) { 16934 // Don't need to recreate the display list, just need to tell our 16935 // children to restore/recreate theirs 16936 if (renderNode.isValid() 16937 && !mRecreateDisplayList) { 16938 mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID; 16939 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 16940 dispatchGetDisplayList(); 16941 16942 return renderNode; // no work needed 16943 } 16944 16945 // If we got here, we're recreating it. Mark it as such to ensure that 16946 // we copy in child display lists into ours in drawChild() 16947 mRecreateDisplayList = true; 16948 16949 int width = mRight - mLeft; 16950 int height = mBottom - mTop; 16951 int layerType = getLayerType(); 16952 16953 final DisplayListCanvas canvas = renderNode.start(width, height); 16954 canvas.setHighContrastText(mAttachInfo.mHighContrastText); 16955 16956 try { 16957 if (layerType == LAYER_TYPE_SOFTWARE) { 16958 buildDrawingCache(true); 16959 Bitmap cache = getDrawingCache(true); 16960 if (cache != null) { 16961 canvas.drawBitmap(cache, 0, 0, mLayerPaint); 16962 } 16963 } else { 16964 computeScroll(); 16965 16966 canvas.translate(-mScrollX, -mScrollY); 16967 mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID; 16968 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 16969 16970 // Fast path for layouts with no backgrounds 16971 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { 16972 dispatchDraw(canvas); 16973 if (mOverlay != null && !mOverlay.isEmpty()) { 16974 mOverlay.getOverlayView().draw(canvas); 16975 } 16976 if (debugDraw()) { 16977 debugDrawFocus(canvas); 16978 } 16979 } else { 16980 draw(canvas); 16981 } 16982 } 16983 } finally { 16984 renderNode.end(canvas); 16985 setDisplayListProperties(renderNode); 16986 } 16987 } else { 16988 mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID; 16989 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 16990 } 16991 return renderNode; 16992 } 16993 16994 private void resetDisplayList() { 16995 mRenderNode.discardDisplayList(); 16996 if (mBackgroundRenderNode != null) { 16997 mBackgroundRenderNode.discardDisplayList(); 16998 } 16999 } 17000 17001 /** 17002 * <p>Calling this method is equivalent to calling <code>getDrawingCache(false)</code>.</p> 17003 * 17004 * @return A non-scaled bitmap representing this view or null if cache is disabled. 17005 * 17006 * @see #getDrawingCache(boolean) 17007 */ 17008 public Bitmap getDrawingCache() { 17009 return getDrawingCache(false); 17010 } 17011 17012 /** 17013 * <p>Returns the bitmap in which this view drawing is cached. The returned bitmap 17014 * is null when caching is disabled. If caching is enabled and the cache is not ready, 17015 * this method will create it. Calling {@link #draw(android.graphics.Canvas)} will not 17016 * draw from the cache when the cache is enabled. To benefit from the cache, you must 17017 * request the drawing cache by calling this method and draw it on screen if the 17018 * returned bitmap is not null.</p> 17019 * 17020 * <p>Note about auto scaling in compatibility mode: When auto scaling is not enabled, 17021 * this method will create a bitmap of the same size as this view. Because this bitmap 17022 * will be drawn scaled by the parent ViewGroup, the result on screen might show 17023 * scaling artifacts. To avoid such artifacts, you should call this method by setting 17024 * the auto scaling to true. Doing so, however, will generate a bitmap of a different 17025 * size than the view. This implies that your application must be able to handle this 17026 * size.</p> 17027 * 17028 * @param autoScale Indicates whether the generated bitmap should be scaled based on 17029 * the current density of the screen when the application is in compatibility 17030 * mode. 17031 * 17032 * @return A bitmap representing this view or null if cache is disabled. 17033 * 17034 * @see #setDrawingCacheEnabled(boolean) 17035 * @see #isDrawingCacheEnabled() 17036 * @see #buildDrawingCache(boolean) 17037 * @see #destroyDrawingCache() 17038 */ 17039 public Bitmap getDrawingCache(boolean autoScale) { 17040 if ((mViewFlags & WILL_NOT_CACHE_DRAWING) == WILL_NOT_CACHE_DRAWING) { 17041 return null; 17042 } 17043 if ((mViewFlags & DRAWING_CACHE_ENABLED) == DRAWING_CACHE_ENABLED) { 17044 buildDrawingCache(autoScale); 17045 } 17046 return autoScale ? mDrawingCache : mUnscaledDrawingCache; 17047 } 17048 17049 /** 17050 * <p>Frees the resources used by the drawing cache. If you call 17051 * {@link #buildDrawingCache()} manually without calling 17052 * {@link #setDrawingCacheEnabled(boolean) setDrawingCacheEnabled(true)}, you 17053 * should cleanup the cache with this method afterwards.</p> 17054 * 17055 * @see #setDrawingCacheEnabled(boolean) 17056 * @see #buildDrawingCache() 17057 * @see #getDrawingCache() 17058 */ 17059 public void destroyDrawingCache() { 17060 if (mDrawingCache != null) { 17061 mDrawingCache.recycle(); 17062 mDrawingCache = null; 17063 } 17064 if (mUnscaledDrawingCache != null) { 17065 mUnscaledDrawingCache.recycle(); 17066 mUnscaledDrawingCache = null; 17067 } 17068 } 17069 17070 /** 17071 * Setting a solid background color for the drawing cache's bitmaps will improve 17072 * performance and memory usage. Note, though that this should only be used if this 17073 * view will always be drawn on top of a solid color. 17074 * 17075 * @param color The background color to use for the drawing cache's bitmap 17076 * 17077 * @see #setDrawingCacheEnabled(boolean) 17078 * @see #buildDrawingCache() 17079 * @see #getDrawingCache() 17080 */ 17081 public void setDrawingCacheBackgroundColor(@ColorInt int color) { 17082 if (color != mDrawingCacheBackgroundColor) { 17083 mDrawingCacheBackgroundColor = color; 17084 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; 17085 } 17086 } 17087 17088 /** 17089 * @see #setDrawingCacheBackgroundColor(int) 17090 * 17091 * @return The background color to used for the drawing cache's bitmap 17092 */ 17093 @ColorInt 17094 public int getDrawingCacheBackgroundColor() { 17095 return mDrawingCacheBackgroundColor; 17096 } 17097 17098 /** 17099 * <p>Calling this method is equivalent to calling <code>buildDrawingCache(false)</code>.</p> 17100 * 17101 * @see #buildDrawingCache(boolean) 17102 */ 17103 public void buildDrawingCache() { 17104 buildDrawingCache(false); 17105 } 17106 17107 /** 17108 * <p>Forces the drawing cache to be built if the drawing cache is invalid.</p> 17109 * 17110 * <p>If you call {@link #buildDrawingCache()} manually without calling 17111 * {@link #setDrawingCacheEnabled(boolean) setDrawingCacheEnabled(true)}, you 17112 * should cleanup the cache by calling {@link #destroyDrawingCache()} afterwards.</p> 17113 * 17114 * <p>Note about auto scaling in compatibility mode: When auto scaling is not enabled, 17115 * this method will create a bitmap of the same size as this view. Because this bitmap 17116 * will be drawn scaled by the parent ViewGroup, the result on screen might show 17117 * scaling artifacts. To avoid such artifacts, you should call this method by setting 17118 * the auto scaling to true. Doing so, however, will generate a bitmap of a different 17119 * size than the view. This implies that your application must be able to handle this 17120 * size.</p> 17121 * 17122 * <p>You should avoid calling this method when hardware acceleration is enabled. If 17123 * you do not need the drawing cache bitmap, calling this method will increase memory 17124 * usage and cause the view to be rendered in software once, thus negatively impacting 17125 * performance.</p> 17126 * 17127 * @see #getDrawingCache() 17128 * @see #destroyDrawingCache() 17129 */ 17130 public void buildDrawingCache(boolean autoScale) { 17131 if ((mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == 0 || (autoScale ? 17132 mDrawingCache == null : mUnscaledDrawingCache == null)) { 17133 if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) { 17134 Trace.traceBegin(Trace.TRACE_TAG_VIEW, 17135 "buildDrawingCache/SW Layer for " + getClass().getSimpleName()); 17136 } 17137 try { 17138 buildDrawingCacheImpl(autoScale); 17139 } finally { 17140 Trace.traceEnd(Trace.TRACE_TAG_VIEW); 17141 } 17142 } 17143 } 17144 17145 /** 17146 * private, internal implementation of buildDrawingCache, used to enable tracing 17147 */ 17148 private void buildDrawingCacheImpl(boolean autoScale) { 17149 mCachingFailed = false; 17150 17151 int width = mRight - mLeft; 17152 int height = mBottom - mTop; 17153 17154 final AttachInfo attachInfo = mAttachInfo; 17155 final boolean scalingRequired = attachInfo != null && attachInfo.mScalingRequired; 17156 17157 if (autoScale && scalingRequired) { 17158 width = (int) ((width * attachInfo.mApplicationScale) + 0.5f); 17159 height = (int) ((height * attachInfo.mApplicationScale) + 0.5f); 17160 } 17161 17162 final int drawingCacheBackgroundColor = mDrawingCacheBackgroundColor; 17163 final boolean opaque = drawingCacheBackgroundColor != 0 || isOpaque(); 17164 final boolean use32BitCache = attachInfo != null && attachInfo.mUse32BitDrawingCache; 17165 17166 final long projectedBitmapSize = width * height * (opaque && !use32BitCache ? 2 : 4); 17167 final long drawingCacheSize = 17168 ViewConfiguration.get(mContext).getScaledMaximumDrawingCacheSize(); 17169 if (width <= 0 || height <= 0 || projectedBitmapSize > drawingCacheSize) { 17170 if (width > 0 && height > 0) { 17171 Log.w(VIEW_LOG_TAG, getClass().getSimpleName() + " not displayed because it is" 17172 + " too large to fit into a software layer (or drawing cache), needs " 17173 + projectedBitmapSize + " bytes, only " 17174 + drawingCacheSize + " available"); 17175 } 17176 destroyDrawingCache(); 17177 mCachingFailed = true; 17178 return; 17179 } 17180 17181 boolean clear = true; 17182 Bitmap bitmap = autoScale ? mDrawingCache : mUnscaledDrawingCache; 17183 17184 if (bitmap == null || bitmap.getWidth() != width || bitmap.getHeight() != height) { 17185 Bitmap.Config quality; 17186 if (!opaque) { 17187 // Never pick ARGB_4444 because it looks awful 17188 // Keep the DRAWING_CACHE_QUALITY_LOW flag just in case 17189 switch (mViewFlags & DRAWING_CACHE_QUALITY_MASK) { 17190 case DRAWING_CACHE_QUALITY_AUTO: 17191 case DRAWING_CACHE_QUALITY_LOW: 17192 case DRAWING_CACHE_QUALITY_HIGH: 17193 default: 17194 quality = Bitmap.Config.ARGB_8888; 17195 break; 17196 } 17197 } else { 17198 // Optimization for translucent windows 17199 // If the window is translucent, use a 32 bits bitmap to benefit from memcpy() 17200 quality = use32BitCache ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565; 17201 } 17202 17203 // Try to cleanup memory 17204 if (bitmap != null) bitmap.recycle(); 17205 17206 try { 17207 bitmap = Bitmap.createBitmap(mResources.getDisplayMetrics(), 17208 width, height, quality); 17209 bitmap.setDensity(getResources().getDisplayMetrics().densityDpi); 17210 if (autoScale) { 17211 mDrawingCache = bitmap; 17212 } else { 17213 mUnscaledDrawingCache = bitmap; 17214 } 17215 if (opaque && use32BitCache) bitmap.setHasAlpha(false); 17216 } catch (OutOfMemoryError e) { 17217 // If there is not enough memory to create the bitmap cache, just 17218 // ignore the issue as bitmap caches are not required to draw the 17219 // view hierarchy 17220 if (autoScale) { 17221 mDrawingCache = null; 17222 } else { 17223 mUnscaledDrawingCache = null; 17224 } 17225 mCachingFailed = true; 17226 return; 17227 } 17228 17229 clear = drawingCacheBackgroundColor != 0; 17230 } 17231 17232 Canvas canvas; 17233 if (attachInfo != null) { 17234 canvas = attachInfo.mCanvas; 17235 if (canvas == null) { 17236 canvas = new Canvas(); 17237 } 17238 canvas.setBitmap(bitmap); 17239 // Temporarily clobber the cached Canvas in case one of our children 17240 // is also using a drawing cache. Without this, the children would 17241 // steal the canvas by attaching their own bitmap to it and bad, bad 17242 // thing would happen (invisible views, corrupted drawings, etc.) 17243 attachInfo.mCanvas = null; 17244 } else { 17245 // This case should hopefully never or seldom happen 17246 canvas = new Canvas(bitmap); 17247 } 17248 17249 if (clear) { 17250 bitmap.eraseColor(drawingCacheBackgroundColor); 17251 } 17252 17253 computeScroll(); 17254 final int restoreCount = canvas.save(); 17255 17256 if (autoScale && scalingRequired) { 17257 final float scale = attachInfo.mApplicationScale; 17258 canvas.scale(scale, scale); 17259 } 17260 17261 canvas.translate(-mScrollX, -mScrollY); 17262 17263 mPrivateFlags |= PFLAG_DRAWN; 17264 if (mAttachInfo == null || !mAttachInfo.mHardwareAccelerated || 17265 mLayerType != LAYER_TYPE_NONE) { 17266 mPrivateFlags |= PFLAG_DRAWING_CACHE_VALID; 17267 } 17268 17269 // Fast path for layouts with no backgrounds 17270 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { 17271 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 17272 dispatchDraw(canvas); 17273 if (mOverlay != null && !mOverlay.isEmpty()) { 17274 mOverlay.getOverlayView().draw(canvas); 17275 } 17276 } else { 17277 draw(canvas); 17278 } 17279 17280 canvas.restoreToCount(restoreCount); 17281 canvas.setBitmap(null); 17282 17283 if (attachInfo != null) { 17284 // Restore the cached Canvas for our siblings 17285 attachInfo.mCanvas = canvas; 17286 } 17287 } 17288 17289 /** 17290 * Create a snapshot of the view into a bitmap. We should probably make 17291 * some form of this public, but should think about the API. 17292 * 17293 * @hide 17294 */ 17295 public Bitmap createSnapshot(Bitmap.Config quality, int backgroundColor, boolean skipChildren) { 17296 int width = mRight - mLeft; 17297 int height = mBottom - mTop; 17298 17299 final AttachInfo attachInfo = mAttachInfo; 17300 final float scale = attachInfo != null ? attachInfo.mApplicationScale : 1.0f; 17301 width = (int) ((width * scale) + 0.5f); 17302 height = (int) ((height * scale) + 0.5f); 17303 17304 Bitmap bitmap = Bitmap.createBitmap(mResources.getDisplayMetrics(), 17305 width > 0 ? width : 1, height > 0 ? height : 1, quality); 17306 if (bitmap == null) { 17307 throw new OutOfMemoryError(); 17308 } 17309 17310 Resources resources = getResources(); 17311 if (resources != null) { 17312 bitmap.setDensity(resources.getDisplayMetrics().densityDpi); 17313 } 17314 17315 Canvas canvas; 17316 if (attachInfo != null) { 17317 canvas = attachInfo.mCanvas; 17318 if (canvas == null) { 17319 canvas = new Canvas(); 17320 } 17321 canvas.setBitmap(bitmap); 17322 // Temporarily clobber the cached Canvas in case one of our children 17323 // is also using a drawing cache. Without this, the children would 17324 // steal the canvas by attaching their own bitmap to it and bad, bad 17325 // things would happen (invisible views, corrupted drawings, etc.) 17326 attachInfo.mCanvas = null; 17327 } else { 17328 // This case should hopefully never or seldom happen 17329 canvas = new Canvas(bitmap); 17330 } 17331 17332 if ((backgroundColor & 0xff000000) != 0) { 17333 bitmap.eraseColor(backgroundColor); 17334 } 17335 17336 computeScroll(); 17337 final int restoreCount = canvas.save(); 17338 canvas.scale(scale, scale); 17339 canvas.translate(-mScrollX, -mScrollY); 17340 17341 // Temporarily remove the dirty mask 17342 int flags = mPrivateFlags; 17343 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 17344 17345 // Fast path for layouts with no backgrounds 17346 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { 17347 dispatchDraw(canvas); 17348 if (mOverlay != null && !mOverlay.isEmpty()) { 17349 mOverlay.getOverlayView().draw(canvas); 17350 } 17351 } else { 17352 draw(canvas); 17353 } 17354 17355 mPrivateFlags = flags; 17356 17357 canvas.restoreToCount(restoreCount); 17358 canvas.setBitmap(null); 17359 17360 if (attachInfo != null) { 17361 // Restore the cached Canvas for our siblings 17362 attachInfo.mCanvas = canvas; 17363 } 17364 17365 return bitmap; 17366 } 17367 17368 /** 17369 * Indicates whether this View is currently in edit mode. A View is usually 17370 * in edit mode when displayed within a developer tool. For instance, if 17371 * this View is being drawn by a visual user interface builder, this method 17372 * should return true. 17373 * 17374 * Subclasses should check the return value of this method to provide 17375 * different behaviors if their normal behavior might interfere with the 17376 * host environment. For instance: the class spawns a thread in its 17377 * constructor, the drawing code relies on device-specific features, etc. 17378 * 17379 * This method is usually checked in the drawing code of custom widgets. 17380 * 17381 * @return True if this View is in edit mode, false otherwise. 17382 */ 17383 public boolean isInEditMode() { 17384 return false; 17385 } 17386 17387 /** 17388 * If the View draws content inside its padding and enables fading edges, 17389 * it needs to support padding offsets. Padding offsets are added to the 17390 * fading edges to extend the length of the fade so that it covers pixels 17391 * drawn inside the padding. 17392 * 17393 * Subclasses of this class should override this method if they need 17394 * to draw content inside the padding. 17395 * 17396 * @return True if padding offset must be applied, false otherwise. 17397 * 17398 * @see #getLeftPaddingOffset() 17399 * @see #getRightPaddingOffset() 17400 * @see #getTopPaddingOffset() 17401 * @see #getBottomPaddingOffset() 17402 * 17403 * @since CURRENT 17404 */ 17405 protected boolean isPaddingOffsetRequired() { 17406 return false; 17407 } 17408 17409 /** 17410 * Amount by which to extend the left fading region. Called only when 17411 * {@link #isPaddingOffsetRequired()} returns true. 17412 * 17413 * @return The left padding offset in pixels. 17414 * 17415 * @see #isPaddingOffsetRequired() 17416 * 17417 * @since CURRENT 17418 */ 17419 protected int getLeftPaddingOffset() { 17420 return 0; 17421 } 17422 17423 /** 17424 * Amount by which to extend the right fading region. Called only when 17425 * {@link #isPaddingOffsetRequired()} returns true. 17426 * 17427 * @return The right padding offset in pixels. 17428 * 17429 * @see #isPaddingOffsetRequired() 17430 * 17431 * @since CURRENT 17432 */ 17433 protected int getRightPaddingOffset() { 17434 return 0; 17435 } 17436 17437 /** 17438 * Amount by which to extend the top fading region. Called only when 17439 * {@link #isPaddingOffsetRequired()} returns true. 17440 * 17441 * @return The top padding offset in pixels. 17442 * 17443 * @see #isPaddingOffsetRequired() 17444 * 17445 * @since CURRENT 17446 */ 17447 protected int getTopPaddingOffset() { 17448 return 0; 17449 } 17450 17451 /** 17452 * Amount by which to extend the bottom fading region. Called only when 17453 * {@link #isPaddingOffsetRequired()} returns true. 17454 * 17455 * @return The bottom padding offset in pixels. 17456 * 17457 * @see #isPaddingOffsetRequired() 17458 * 17459 * @since CURRENT 17460 */ 17461 protected int getBottomPaddingOffset() { 17462 return 0; 17463 } 17464 17465 /** 17466 * @hide 17467 * @param offsetRequired 17468 */ 17469 protected int getFadeTop(boolean offsetRequired) { 17470 int top = mPaddingTop; 17471 if (offsetRequired) top += getTopPaddingOffset(); 17472 return top; 17473 } 17474 17475 /** 17476 * @hide 17477 * @param offsetRequired 17478 */ 17479 protected int getFadeHeight(boolean offsetRequired) { 17480 int padding = mPaddingTop; 17481 if (offsetRequired) padding += getTopPaddingOffset(); 17482 return mBottom - mTop - mPaddingBottom - padding; 17483 } 17484 17485 /** 17486 * <p>Indicates whether this view is attached to a hardware accelerated 17487 * window or not.</p> 17488 * 17489 * <p>Even if this method returns true, it does not mean that every call 17490 * to {@link #draw(android.graphics.Canvas)} will be made with an hardware 17491 * accelerated {@link android.graphics.Canvas}. For instance, if this view 17492 * is drawn onto an offscreen {@link android.graphics.Bitmap} and its 17493 * window is hardware accelerated, 17494 * {@link android.graphics.Canvas#isHardwareAccelerated()} will likely 17495 * return false, and this method will return true.</p> 17496 * 17497 * @return True if the view is attached to a window and the window is 17498 * hardware accelerated; false in any other case. 17499 */ 17500 @ViewDebug.ExportedProperty(category = "drawing") 17501 public boolean isHardwareAccelerated() { 17502 return mAttachInfo != null && mAttachInfo.mHardwareAccelerated; 17503 } 17504 17505 /** 17506 * Sets a rectangular area on this view to which the view will be clipped 17507 * when it is drawn. Setting the value to null will remove the clip bounds 17508 * and the view will draw normally, using its full bounds. 17509 * 17510 * @param clipBounds The rectangular area, in the local coordinates of 17511 * this view, to which future drawing operations will be clipped. 17512 */ 17513 public void setClipBounds(Rect clipBounds) { 17514 if (clipBounds == mClipBounds 17515 || (clipBounds != null && clipBounds.equals(mClipBounds))) { 17516 return; 17517 } 17518 if (clipBounds != null) { 17519 if (mClipBounds == null) { 17520 mClipBounds = new Rect(clipBounds); 17521 } else { 17522 mClipBounds.set(clipBounds); 17523 } 17524 } else { 17525 mClipBounds = null; 17526 } 17527 mRenderNode.setClipBounds(mClipBounds); 17528 invalidateViewProperty(false, false); 17529 } 17530 17531 /** 17532 * Returns a copy of the current {@link #setClipBounds(Rect) clipBounds}. 17533 * 17534 * @return A copy of the current clip bounds if clip bounds are set, 17535 * otherwise null. 17536 */ 17537 public Rect getClipBounds() { 17538 return (mClipBounds != null) ? new Rect(mClipBounds) : null; 17539 } 17540 17541 17542 /** 17543 * Populates an output rectangle with the clip bounds of the view, 17544 * returning {@code true} if successful or {@code false} if the view's 17545 * clip bounds are {@code null}. 17546 * 17547 * @param outRect rectangle in which to place the clip bounds of the view 17548 * @return {@code true} if successful or {@code false} if the view's 17549 * clip bounds are {@code null} 17550 */ 17551 public boolean getClipBounds(Rect outRect) { 17552 if (mClipBounds != null) { 17553 outRect.set(mClipBounds); 17554 return true; 17555 } 17556 return false; 17557 } 17558 17559 /** 17560 * Utility function, called by draw(canvas, parent, drawingTime) to handle the less common 17561 * case of an active Animation being run on the view. 17562 */ 17563 private boolean applyLegacyAnimation(ViewGroup parent, long drawingTime, 17564 Animation a, boolean scalingRequired) { 17565 Transformation invalidationTransform; 17566 final int flags = parent.mGroupFlags; 17567 final boolean initialized = a.isInitialized(); 17568 if (!initialized) { 17569 a.initialize(mRight - mLeft, mBottom - mTop, parent.getWidth(), parent.getHeight()); 17570 a.initializeInvalidateRegion(0, 0, mRight - mLeft, mBottom - mTop); 17571 if (mAttachInfo != null) a.setListenerHandler(mAttachInfo.mHandler); 17572 onAnimationStart(); 17573 } 17574 17575 final Transformation t = parent.getChildTransformation(); 17576 boolean more = a.getTransformation(drawingTime, t, 1f); 17577 if (scalingRequired && mAttachInfo.mApplicationScale != 1f) { 17578 if (parent.mInvalidationTransformation == null) { 17579 parent.mInvalidationTransformation = new Transformation(); 17580 } 17581 invalidationTransform = parent.mInvalidationTransformation; 17582 a.getTransformation(drawingTime, invalidationTransform, 1f); 17583 } else { 17584 invalidationTransform = t; 17585 } 17586 17587 if (more) { 17588 if (!a.willChangeBounds()) { 17589 if ((flags & (ViewGroup.FLAG_OPTIMIZE_INVALIDATE | ViewGroup.FLAG_ANIMATION_DONE)) == 17590 ViewGroup.FLAG_OPTIMIZE_INVALIDATE) { 17591 parent.mGroupFlags |= ViewGroup.FLAG_INVALIDATE_REQUIRED; 17592 } else if ((flags & ViewGroup.FLAG_INVALIDATE_REQUIRED) == 0) { 17593 // The child need to draw an animation, potentially offscreen, so 17594 // make sure we do not cancel invalidate requests 17595 parent.mPrivateFlags |= PFLAG_DRAW_ANIMATION; 17596 parent.invalidate(mLeft, mTop, mRight, mBottom); 17597 } 17598 } else { 17599 if (parent.mInvalidateRegion == null) { 17600 parent.mInvalidateRegion = new RectF(); 17601 } 17602 final RectF region = parent.mInvalidateRegion; 17603 a.getInvalidateRegion(0, 0, mRight - mLeft, mBottom - mTop, region, 17604 invalidationTransform); 17605 17606 // The child need to draw an animation, potentially offscreen, so 17607 // make sure we do not cancel invalidate requests 17608 parent.mPrivateFlags |= PFLAG_DRAW_ANIMATION; 17609 17610 final int left = mLeft + (int) region.left; 17611 final int top = mTop + (int) region.top; 17612 parent.invalidate(left, top, left + (int) (region.width() + .5f), 17613 top + (int) (region.height() + .5f)); 17614 } 17615 } 17616 return more; 17617 } 17618 17619 /** 17620 * This method is called by getDisplayList() when a display list is recorded for a View. 17621 * It pushes any properties to the RenderNode that aren't managed by the RenderNode. 17622 */ 17623 void setDisplayListProperties(RenderNode renderNode) { 17624 if (renderNode != null) { 17625 renderNode.setHasOverlappingRendering(getHasOverlappingRendering()); 17626 renderNode.setClipToBounds(mParent instanceof ViewGroup 17627 && ((ViewGroup) mParent).getClipChildren()); 17628 17629 float alpha = 1; 17630 if (mParent instanceof ViewGroup && (((ViewGroup) mParent).mGroupFlags & 17631 ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) != 0) { 17632 ViewGroup parentVG = (ViewGroup) mParent; 17633 final Transformation t = parentVG.getChildTransformation(); 17634 if (parentVG.getChildStaticTransformation(this, t)) { 17635 final int transformType = t.getTransformationType(); 17636 if (transformType != Transformation.TYPE_IDENTITY) { 17637 if ((transformType & Transformation.TYPE_ALPHA) != 0) { 17638 alpha = t.getAlpha(); 17639 } 17640 if ((transformType & Transformation.TYPE_MATRIX) != 0) { 17641 renderNode.setStaticMatrix(t.getMatrix()); 17642 } 17643 } 17644 } 17645 } 17646 if (mTransformationInfo != null) { 17647 alpha *= getFinalAlpha(); 17648 if (alpha < 1) { 17649 final int multipliedAlpha = (int) (255 * alpha); 17650 if (onSetAlpha(multipliedAlpha)) { 17651 alpha = 1; 17652 } 17653 } 17654 renderNode.setAlpha(alpha); 17655 } else if (alpha < 1) { 17656 renderNode.setAlpha(alpha); 17657 } 17658 } 17659 } 17660 17661 /** 17662 * This method is called by ViewGroup.drawChild() to have each child view draw itself. 17663 * 17664 * This is where the View specializes rendering behavior based on layer type, 17665 * and hardware acceleration. 17666 */ 17667 boolean draw(Canvas canvas, ViewGroup parent, long drawingTime) { 17668 final boolean hardwareAcceleratedCanvas = canvas.isHardwareAccelerated(); 17669 /* If an attached view draws to a HW canvas, it may use its RenderNode + DisplayList. 17670 * 17671 * If a view is dettached, its DisplayList shouldn't exist. If the canvas isn't 17672 * HW accelerated, it can't handle drawing RenderNodes. 17673 */ 17674 boolean drawingWithRenderNode = mAttachInfo != null 17675 && mAttachInfo.mHardwareAccelerated 17676 && hardwareAcceleratedCanvas; 17677 17678 boolean more = false; 17679 final boolean childHasIdentityMatrix = hasIdentityMatrix(); 17680 final int parentFlags = parent.mGroupFlags; 17681 17682 if ((parentFlags & ViewGroup.FLAG_CLEAR_TRANSFORMATION) != 0) { 17683 parent.getChildTransformation().clear(); 17684 parent.mGroupFlags &= ~ViewGroup.FLAG_CLEAR_TRANSFORMATION; 17685 } 17686 17687 Transformation transformToApply = null; 17688 boolean concatMatrix = false; 17689 final boolean scalingRequired = mAttachInfo != null && mAttachInfo.mScalingRequired; 17690 final Animation a = getAnimation(); 17691 if (a != null) { 17692 more = applyLegacyAnimation(parent, drawingTime, a, scalingRequired); 17693 concatMatrix = a.willChangeTransformationMatrix(); 17694 if (concatMatrix) { 17695 mPrivateFlags3 |= PFLAG3_VIEW_IS_ANIMATING_TRANSFORM; 17696 } 17697 transformToApply = parent.getChildTransformation(); 17698 } else { 17699 if ((mPrivateFlags3 & PFLAG3_VIEW_IS_ANIMATING_TRANSFORM) != 0) { 17700 // No longer animating: clear out old animation matrix 17701 mRenderNode.setAnimationMatrix(null); 17702 mPrivateFlags3 &= ~PFLAG3_VIEW_IS_ANIMATING_TRANSFORM; 17703 } 17704 if (!drawingWithRenderNode 17705 && (parentFlags & ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) != 0) { 17706 final Transformation t = parent.getChildTransformation(); 17707 final boolean hasTransform = parent.getChildStaticTransformation(this, t); 17708 if (hasTransform) { 17709 final int transformType = t.getTransformationType(); 17710 transformToApply = transformType != Transformation.TYPE_IDENTITY ? t : null; 17711 concatMatrix = (transformType & Transformation.TYPE_MATRIX) != 0; 17712 } 17713 } 17714 } 17715 17716 concatMatrix |= !childHasIdentityMatrix; 17717 17718 // Sets the flag as early as possible to allow draw() implementations 17719 // to call invalidate() successfully when doing animations 17720 mPrivateFlags |= PFLAG_DRAWN; 17721 17722 if (!concatMatrix && 17723 (parentFlags & (ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS | 17724 ViewGroup.FLAG_CLIP_CHILDREN)) == ViewGroup.FLAG_CLIP_CHILDREN && 17725 canvas.quickReject(mLeft, mTop, mRight, mBottom, Canvas.EdgeType.BW) && 17726 (mPrivateFlags & PFLAG_DRAW_ANIMATION) == 0) { 17727 mPrivateFlags2 |= PFLAG2_VIEW_QUICK_REJECTED; 17728 return more; 17729 } 17730 mPrivateFlags2 &= ~PFLAG2_VIEW_QUICK_REJECTED; 17731 17732 if (hardwareAcceleratedCanvas) { 17733 // Clear INVALIDATED flag to allow invalidation to occur during rendering, but 17734 // retain the flag's value temporarily in the mRecreateDisplayList flag 17735 mRecreateDisplayList = (mPrivateFlags & PFLAG_INVALIDATED) != 0; 17736 mPrivateFlags &= ~PFLAG_INVALIDATED; 17737 } 17738 17739 RenderNode renderNode = null; 17740 Bitmap cache = null; 17741 int layerType = getLayerType(); // TODO: signify cache state with just 'cache' local 17742 if (layerType == LAYER_TYPE_SOFTWARE || !drawingWithRenderNode) { 17743 if (layerType != LAYER_TYPE_NONE) { 17744 // If not drawing with RenderNode, treat HW layers as SW 17745 layerType = LAYER_TYPE_SOFTWARE; 17746 buildDrawingCache(true); 17747 } 17748 cache = getDrawingCache(true); 17749 } 17750 17751 if (drawingWithRenderNode) { 17752 // Delay getting the display list until animation-driven alpha values are 17753 // set up and possibly passed on to the view 17754 renderNode = updateDisplayListIfDirty(); 17755 if (!renderNode.isValid()) { 17756 // Uncommon, but possible. If a view is removed from the hierarchy during the call 17757 // to getDisplayList(), the display list will be marked invalid and we should not 17758 // try to use it again. 17759 renderNode = null; 17760 drawingWithRenderNode = false; 17761 } 17762 } 17763 17764 int sx = 0; 17765 int sy = 0; 17766 if (!drawingWithRenderNode) { 17767 computeScroll(); 17768 sx = mScrollX; 17769 sy = mScrollY; 17770 } 17771 17772 final boolean drawingWithDrawingCache = cache != null && !drawingWithRenderNode; 17773 final boolean offsetForScroll = cache == null && !drawingWithRenderNode; 17774 17775 int restoreTo = -1; 17776 if (!drawingWithRenderNode || transformToApply != null) { 17777 restoreTo = canvas.save(); 17778 } 17779 if (offsetForScroll) { 17780 canvas.translate(mLeft - sx, mTop - sy); 17781 } else { 17782 if (!drawingWithRenderNode) { 17783 canvas.translate(mLeft, mTop); 17784 } 17785 if (scalingRequired) { 17786 if (drawingWithRenderNode) { 17787 // TODO: Might not need this if we put everything inside the DL 17788 restoreTo = canvas.save(); 17789 } 17790 // mAttachInfo cannot be null, otherwise scalingRequired == false 17791 final float scale = 1.0f / mAttachInfo.mApplicationScale; 17792 canvas.scale(scale, scale); 17793 } 17794 } 17795 17796 float alpha = drawingWithRenderNode ? 1 : (getAlpha() * getTransitionAlpha()); 17797 if (transformToApply != null 17798 || alpha < 1 17799 || !hasIdentityMatrix() 17800 || (mPrivateFlags3 & PFLAG3_VIEW_IS_ANIMATING_ALPHA) != 0) { 17801 if (transformToApply != null || !childHasIdentityMatrix) { 17802 int transX = 0; 17803 int transY = 0; 17804 17805 if (offsetForScroll) { 17806 transX = -sx; 17807 transY = -sy; 17808 } 17809 17810 if (transformToApply != null) { 17811 if (concatMatrix) { 17812 if (drawingWithRenderNode) { 17813 renderNode.setAnimationMatrix(transformToApply.getMatrix()); 17814 } else { 17815 // Undo the scroll translation, apply the transformation matrix, 17816 // then redo the scroll translate to get the correct result. 17817 canvas.translate(-transX, -transY); 17818 canvas.concat(transformToApply.getMatrix()); 17819 canvas.translate(transX, transY); 17820 } 17821 parent.mGroupFlags |= ViewGroup.FLAG_CLEAR_TRANSFORMATION; 17822 } 17823 17824 float transformAlpha = transformToApply.getAlpha(); 17825 if (transformAlpha < 1) { 17826 alpha *= transformAlpha; 17827 parent.mGroupFlags |= ViewGroup.FLAG_CLEAR_TRANSFORMATION; 17828 } 17829 } 17830 17831 if (!childHasIdentityMatrix && !drawingWithRenderNode) { 17832 canvas.translate(-transX, -transY); 17833 canvas.concat(getMatrix()); 17834 canvas.translate(transX, transY); 17835 } 17836 } 17837 17838 // Deal with alpha if it is or used to be <1 17839 if (alpha < 1 || (mPrivateFlags3 & PFLAG3_VIEW_IS_ANIMATING_ALPHA) != 0) { 17840 if (alpha < 1) { 17841 mPrivateFlags3 |= PFLAG3_VIEW_IS_ANIMATING_ALPHA; 17842 } else { 17843 mPrivateFlags3 &= ~PFLAG3_VIEW_IS_ANIMATING_ALPHA; 17844 } 17845 parent.mGroupFlags |= ViewGroup.FLAG_CLEAR_TRANSFORMATION; 17846 if (!drawingWithDrawingCache) { 17847 final int multipliedAlpha = (int) (255 * alpha); 17848 if (!onSetAlpha(multipliedAlpha)) { 17849 if (drawingWithRenderNode) { 17850 renderNode.setAlpha(alpha * getAlpha() * getTransitionAlpha()); 17851 } else if (layerType == LAYER_TYPE_NONE) { 17852 canvas.saveLayerAlpha(sx, sy, sx + getWidth(), sy + getHeight(), 17853 multipliedAlpha); 17854 } 17855 } else { 17856 // Alpha is handled by the child directly, clobber the layer's alpha 17857 mPrivateFlags |= PFLAG_ALPHA_SET; 17858 } 17859 } 17860 } 17861 } else if ((mPrivateFlags & PFLAG_ALPHA_SET) == PFLAG_ALPHA_SET) { 17862 onSetAlpha(255); 17863 mPrivateFlags &= ~PFLAG_ALPHA_SET; 17864 } 17865 17866 if (!drawingWithRenderNode) { 17867 // apply clips directly, since RenderNode won't do it for this draw 17868 if ((parentFlags & ViewGroup.FLAG_CLIP_CHILDREN) != 0 && cache == null) { 17869 if (offsetForScroll) { 17870 canvas.clipRect(sx, sy, sx + getWidth(), sy + getHeight()); 17871 } else { 17872 if (!scalingRequired || cache == null) { 17873 canvas.clipRect(0, 0, getWidth(), getHeight()); 17874 } else { 17875 canvas.clipRect(0, 0, cache.getWidth(), cache.getHeight()); 17876 } 17877 } 17878 } 17879 17880 if (mClipBounds != null) { 17881 // clip bounds ignore scroll 17882 canvas.clipRect(mClipBounds); 17883 } 17884 } 17885 17886 if (!drawingWithDrawingCache) { 17887 if (drawingWithRenderNode) { 17888 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 17889 ((DisplayListCanvas) canvas).drawRenderNode(renderNode); 17890 } else { 17891 // Fast path for layouts with no backgrounds 17892 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { 17893 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 17894 dispatchDraw(canvas); 17895 } else { 17896 draw(canvas); 17897 } 17898 } 17899 } else if (cache != null) { 17900 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 17901 if (layerType == LAYER_TYPE_NONE || mLayerPaint == null) { 17902 // no layer paint, use temporary paint to draw bitmap 17903 Paint cachePaint = parent.mCachePaint; 17904 if (cachePaint == null) { 17905 cachePaint = new Paint(); 17906 cachePaint.setDither(false); 17907 parent.mCachePaint = cachePaint; 17908 } 17909 cachePaint.setAlpha((int) (alpha * 255)); 17910 canvas.drawBitmap(cache, 0.0f, 0.0f, cachePaint); 17911 } else { 17912 // use layer paint to draw the bitmap, merging the two alphas, but also restore 17913 int layerPaintAlpha = mLayerPaint.getAlpha(); 17914 if (alpha < 1) { 17915 mLayerPaint.setAlpha((int) (alpha * layerPaintAlpha)); 17916 } 17917 canvas.drawBitmap(cache, 0.0f, 0.0f, mLayerPaint); 17918 if (alpha < 1) { 17919 mLayerPaint.setAlpha(layerPaintAlpha); 17920 } 17921 } 17922 } 17923 17924 if (restoreTo >= 0) { 17925 canvas.restoreToCount(restoreTo); 17926 } 17927 17928 if (a != null && !more) { 17929 if (!hardwareAcceleratedCanvas && !a.getFillAfter()) { 17930 onSetAlpha(255); 17931 } 17932 parent.finishAnimatingView(this, a); 17933 } 17934 17935 if (more && hardwareAcceleratedCanvas) { 17936 if (a.hasAlpha() && (mPrivateFlags & PFLAG_ALPHA_SET) == PFLAG_ALPHA_SET) { 17937 // alpha animations should cause the child to recreate its display list 17938 invalidate(true); 17939 } 17940 } 17941 17942 mRecreateDisplayList = false; 17943 17944 return more; 17945 } 17946 17947 static Paint getDebugPaint() { 17948 if (sDebugPaint == null) { 17949 sDebugPaint = new Paint(); 17950 sDebugPaint.setAntiAlias(false); 17951 } 17952 return sDebugPaint; 17953 } 17954 17955 final int dipsToPixels(int dips) { 17956 float scale = getContext().getResources().getDisplayMetrics().density; 17957 return (int) (dips * scale + 0.5f); 17958 } 17959 17960 final private void debugDrawFocus(Canvas canvas) { 17961 if (isFocused()) { 17962 final int cornerSquareSize = dipsToPixels(DEBUG_CORNERS_SIZE_DIP); 17963 final int l = mScrollX; 17964 final int r = l + mRight - mLeft; 17965 final int t = mScrollY; 17966 final int b = t + mBottom - mTop; 17967 17968 final Paint paint = getDebugPaint(); 17969 paint.setColor(DEBUG_CORNERS_COLOR); 17970 17971 // Draw squares in corners. 17972 paint.setStyle(Paint.Style.FILL); 17973 canvas.drawRect(l, t, l + cornerSquareSize, t + cornerSquareSize, paint); 17974 canvas.drawRect(r - cornerSquareSize, t, r, t + cornerSquareSize, paint); 17975 canvas.drawRect(l, b - cornerSquareSize, l + cornerSquareSize, b, paint); 17976 canvas.drawRect(r - cornerSquareSize, b - cornerSquareSize, r, b, paint); 17977 17978 // Draw big X across the view. 17979 paint.setStyle(Paint.Style.STROKE); 17980 canvas.drawLine(l, t, r, b, paint); 17981 canvas.drawLine(l, b, r, t, paint); 17982 } 17983 } 17984 17985 /** 17986 * Manually render this view (and all of its children) to the given Canvas. 17987 * The view must have already done a full layout before this function is 17988 * called. When implementing a view, implement 17989 * {@link #onDraw(android.graphics.Canvas)} instead of overriding this method. 17990 * If you do need to override this method, call the superclass version. 17991 * 17992 * @param canvas The Canvas to which the View is rendered. 17993 */ 17994 @CallSuper 17995 public void draw(Canvas canvas) { 17996 final int privateFlags = mPrivateFlags; 17997 final boolean dirtyOpaque = (privateFlags & PFLAG_DIRTY_MASK) == PFLAG_DIRTY_OPAQUE && 17998 (mAttachInfo == null || !mAttachInfo.mIgnoreDirtyState); 17999 mPrivateFlags = (privateFlags & ~PFLAG_DIRTY_MASK) | PFLAG_DRAWN; 18000 18001 /* 18002 * Draw traversal performs several drawing steps which must be executed 18003 * in the appropriate order: 18004 * 18005 * 1. Draw the background 18006 * 2. If necessary, save the canvas' layers to prepare for fading 18007 * 3. Draw view's content 18008 * 4. Draw children 18009 * 5. If necessary, draw the fading edges and restore layers 18010 * 6. Draw decorations (scrollbars for instance) 18011 */ 18012 18013 // Step 1, draw the background, if needed 18014 int saveCount; 18015 18016 if (!dirtyOpaque) { 18017 drawBackground(canvas); 18018 } 18019 18020 // skip step 2 & 5 if possible (common case) 18021 final int viewFlags = mViewFlags; 18022 boolean horizontalEdges = (viewFlags & FADING_EDGE_HORIZONTAL) != 0; 18023 boolean verticalEdges = (viewFlags & FADING_EDGE_VERTICAL) != 0; 18024 if (!verticalEdges && !horizontalEdges) { 18025 // Step 3, draw the content 18026 if (!dirtyOpaque) onDraw(canvas); 18027 18028 // Step 4, draw the children 18029 dispatchDraw(canvas); 18030 18031 // Overlay is part of the content and draws beneath Foreground 18032 if (mOverlay != null && !mOverlay.isEmpty()) { 18033 mOverlay.getOverlayView().dispatchDraw(canvas); 18034 } 18035 18036 // Step 6, draw decorations (foreground, scrollbars) 18037 onDrawForeground(canvas); 18038 18039 if (debugDraw()) { 18040 debugDrawFocus(canvas); 18041 } 18042 18043 // we're done... 18044 return; 18045 } 18046 18047 /* 18048 * Here we do the full fledged routine... 18049 * (this is an uncommon case where speed matters less, 18050 * this is why we repeat some of the tests that have been 18051 * done above) 18052 */ 18053 18054 boolean drawTop = false; 18055 boolean drawBottom = false; 18056 boolean drawLeft = false; 18057 boolean drawRight = false; 18058 18059 float topFadeStrength = 0.0f; 18060 float bottomFadeStrength = 0.0f; 18061 float leftFadeStrength = 0.0f; 18062 float rightFadeStrength = 0.0f; 18063 18064 // Step 2, save the canvas' layers 18065 int paddingLeft = mPaddingLeft; 18066 18067 final boolean offsetRequired = isPaddingOffsetRequired(); 18068 if (offsetRequired) { 18069 paddingLeft += getLeftPaddingOffset(); 18070 } 18071 18072 int left = mScrollX + paddingLeft; 18073 int right = left + mRight - mLeft - mPaddingRight - paddingLeft; 18074 int top = mScrollY + getFadeTop(offsetRequired); 18075 int bottom = top + getFadeHeight(offsetRequired); 18076 18077 if (offsetRequired) { 18078 right += getRightPaddingOffset(); 18079 bottom += getBottomPaddingOffset(); 18080 } 18081 18082 final ScrollabilityCache scrollabilityCache = mScrollCache; 18083 final float fadeHeight = scrollabilityCache.fadingEdgeLength; 18084 int length = (int) fadeHeight; 18085 18086 // clip the fade length if top and bottom fades overlap 18087 // overlapping fades produce odd-looking artifacts 18088 if (verticalEdges && (top + length > bottom - length)) { 18089 length = (bottom - top) / 2; 18090 } 18091 18092 // also clip horizontal fades if necessary 18093 if (horizontalEdges && (left + length > right - length)) { 18094 length = (right - left) / 2; 18095 } 18096 18097 if (verticalEdges) { 18098 topFadeStrength = Math.max(0.0f, Math.min(1.0f, getTopFadingEdgeStrength())); 18099 drawTop = topFadeStrength * fadeHeight > 1.0f; 18100 bottomFadeStrength = Math.max(0.0f, Math.min(1.0f, getBottomFadingEdgeStrength())); 18101 drawBottom = bottomFadeStrength * fadeHeight > 1.0f; 18102 } 18103 18104 if (horizontalEdges) { 18105 leftFadeStrength = Math.max(0.0f, Math.min(1.0f, getLeftFadingEdgeStrength())); 18106 drawLeft = leftFadeStrength * fadeHeight > 1.0f; 18107 rightFadeStrength = Math.max(0.0f, Math.min(1.0f, getRightFadingEdgeStrength())); 18108 drawRight = rightFadeStrength * fadeHeight > 1.0f; 18109 } 18110 18111 saveCount = canvas.getSaveCount(); 18112 18113 int solidColor = getSolidColor(); 18114 if (solidColor == 0) { 18115 final int flags = Canvas.HAS_ALPHA_LAYER_SAVE_FLAG; 18116 18117 if (drawTop) { 18118 canvas.saveLayer(left, top, right, top + length, null, flags); 18119 } 18120 18121 if (drawBottom) { 18122 canvas.saveLayer(left, bottom - length, right, bottom, null, flags); 18123 } 18124 18125 if (drawLeft) { 18126 canvas.saveLayer(left, top, left + length, bottom, null, flags); 18127 } 18128 18129 if (drawRight) { 18130 canvas.saveLayer(right - length, top, right, bottom, null, flags); 18131 } 18132 } else { 18133 scrollabilityCache.setFadeColor(solidColor); 18134 } 18135 18136 // Step 3, draw the content 18137 if (!dirtyOpaque) onDraw(canvas); 18138 18139 // Step 4, draw the children 18140 dispatchDraw(canvas); 18141 18142 // Step 5, draw the fade effect and restore layers 18143 final Paint p = scrollabilityCache.paint; 18144 final Matrix matrix = scrollabilityCache.matrix; 18145 final Shader fade = scrollabilityCache.shader; 18146 18147 if (drawTop) { 18148 matrix.setScale(1, fadeHeight * topFadeStrength); 18149 matrix.postTranslate(left, top); 18150 fade.setLocalMatrix(matrix); 18151 p.setShader(fade); 18152 canvas.drawRect(left, top, right, top + length, p); 18153 } 18154 18155 if (drawBottom) { 18156 matrix.setScale(1, fadeHeight * bottomFadeStrength); 18157 matrix.postRotate(180); 18158 matrix.postTranslate(left, bottom); 18159 fade.setLocalMatrix(matrix); 18160 p.setShader(fade); 18161 canvas.drawRect(left, bottom - length, right, bottom, p); 18162 } 18163 18164 if (drawLeft) { 18165 matrix.setScale(1, fadeHeight * leftFadeStrength); 18166 matrix.postRotate(-90); 18167 matrix.postTranslate(left, top); 18168 fade.setLocalMatrix(matrix); 18169 p.setShader(fade); 18170 canvas.drawRect(left, top, left + length, bottom, p); 18171 } 18172 18173 if (drawRight) { 18174 matrix.setScale(1, fadeHeight * rightFadeStrength); 18175 matrix.postRotate(90); 18176 matrix.postTranslate(right, top); 18177 fade.setLocalMatrix(matrix); 18178 p.setShader(fade); 18179 canvas.drawRect(right - length, top, right, bottom, p); 18180 } 18181 18182 canvas.restoreToCount(saveCount); 18183 18184 // Overlay is part of the content and draws beneath Foreground 18185 if (mOverlay != null && !mOverlay.isEmpty()) { 18186 mOverlay.getOverlayView().dispatchDraw(canvas); 18187 } 18188 18189 // Step 6, draw decorations (foreground, scrollbars) 18190 onDrawForeground(canvas); 18191 18192 if (debugDraw()) { 18193 debugDrawFocus(canvas); 18194 } 18195 } 18196 18197 /** 18198 * Draws the background onto the specified canvas. 18199 * 18200 * @param canvas Canvas on which to draw the background 18201 */ 18202 private void drawBackground(Canvas canvas) { 18203 final Drawable background = mBackground; 18204 if (background == null) { 18205 return; 18206 } 18207 18208 setBackgroundBounds(); 18209 18210 // Attempt to use a display list if requested. 18211 if (canvas.isHardwareAccelerated() && mAttachInfo != null 18212 && mAttachInfo.mThreadedRenderer != null) { 18213 mBackgroundRenderNode = getDrawableRenderNode(background, mBackgroundRenderNode); 18214 18215 final RenderNode renderNode = mBackgroundRenderNode; 18216 if (renderNode != null && renderNode.isValid()) { 18217 setBackgroundRenderNodeProperties(renderNode); 18218 ((DisplayListCanvas) canvas).drawRenderNode(renderNode); 18219 return; 18220 } 18221 } 18222 18223 final int scrollX = mScrollX; 18224 final int scrollY = mScrollY; 18225 if ((scrollX | scrollY) == 0) { 18226 background.draw(canvas); 18227 } else { 18228 canvas.translate(scrollX, scrollY); 18229 background.draw(canvas); 18230 canvas.translate(-scrollX, -scrollY); 18231 } 18232 } 18233 18234 /** 18235 * Sets the correct background bounds and rebuilds the outline, if needed. 18236 * <p/> 18237 * This is called by LayoutLib. 18238 */ 18239 void setBackgroundBounds() { 18240 if (mBackgroundSizeChanged && mBackground != null) { 18241 mBackground.setBounds(0, 0, mRight - mLeft, mBottom - mTop); 18242 mBackgroundSizeChanged = false; 18243 rebuildOutline(); 18244 } 18245 } 18246 18247 private void setBackgroundRenderNodeProperties(RenderNode renderNode) { 18248 renderNode.setTranslationX(mScrollX); 18249 renderNode.setTranslationY(mScrollY); 18250 } 18251 18252 /** 18253 * Creates a new display list or updates the existing display list for the 18254 * specified Drawable. 18255 * 18256 * @param drawable Drawable for which to create a display list 18257 * @param renderNode Existing RenderNode, or {@code null} 18258 * @return A valid display list for the specified drawable 18259 */ 18260 private RenderNode getDrawableRenderNode(Drawable drawable, RenderNode renderNode) { 18261 if (renderNode == null) { 18262 renderNode = RenderNode.create(drawable.getClass().getName(), this); 18263 } 18264 18265 final Rect bounds = drawable.getBounds(); 18266 final int width = bounds.width(); 18267 final int height = bounds.height(); 18268 final DisplayListCanvas canvas = renderNode.start(width, height); 18269 18270 // Reverse left/top translation done by drawable canvas, which will 18271 // instead be applied by rendernode's LTRB bounds below. This way, the 18272 // drawable's bounds match with its rendernode bounds and its content 18273 // will lie within those bounds in the rendernode tree. 18274 canvas.translate(-bounds.left, -bounds.top); 18275 18276 try { 18277 drawable.draw(canvas); 18278 } finally { 18279 renderNode.end(canvas); 18280 } 18281 18282 // Set up drawable properties that are view-independent. 18283 renderNode.setLeftTopRightBottom(bounds.left, bounds.top, bounds.right, bounds.bottom); 18284 renderNode.setProjectBackwards(drawable.isProjected()); 18285 renderNode.setProjectionReceiver(true); 18286 renderNode.setClipToBounds(false); 18287 return renderNode; 18288 } 18289 18290 /** 18291 * Returns the overlay for this view, creating it if it does not yet exist. 18292 * Adding drawables to the overlay will cause them to be displayed whenever 18293 * the view itself is redrawn. Objects in the overlay should be actively 18294 * managed: remove them when they should not be displayed anymore. The 18295 * overlay will always have the same size as its host view. 18296 * 18297 * <p>Note: Overlays do not currently work correctly with {@link 18298 * SurfaceView} or {@link TextureView}; contents in overlays for these 18299 * types of views may not display correctly.</p> 18300 * 18301 * @return The ViewOverlay object for this view. 18302 * @see ViewOverlay 18303 */ 18304 public ViewOverlay getOverlay() { 18305 if (mOverlay == null) { 18306 mOverlay = new ViewOverlay(mContext, this); 18307 } 18308 return mOverlay; 18309 } 18310 18311 /** 18312 * Override this if your view is known to always be drawn on top of a solid color background, 18313 * and needs to draw fading edges. Returning a non-zero color enables the view system to 18314 * optimize the drawing of the fading edges. If you do return a non-zero color, the alpha 18315 * should be set to 0xFF. 18316 * 18317 * @see #setVerticalFadingEdgeEnabled(boolean) 18318 * @see #setHorizontalFadingEdgeEnabled(boolean) 18319 * 18320 * @return The known solid color background for this view, or 0 if the color may vary 18321 */ 18322 @ViewDebug.ExportedProperty(category = "drawing") 18323 @ColorInt 18324 public int getSolidColor() { 18325 return 0; 18326 } 18327 18328 /** 18329 * Build a human readable string representation of the specified view flags. 18330 * 18331 * @param flags the view flags to convert to a string 18332 * @return a String representing the supplied flags 18333 */ 18334 private static String printFlags(int flags) { 18335 String output = ""; 18336 int numFlags = 0; 18337 if ((flags & FOCUSABLE) == FOCUSABLE) { 18338 output += "TAKES_FOCUS"; 18339 numFlags++; 18340 } 18341 18342 switch (flags & VISIBILITY_MASK) { 18343 case INVISIBLE: 18344 if (numFlags > 0) { 18345 output += " "; 18346 } 18347 output += "INVISIBLE"; 18348 // USELESS HERE numFlags++; 18349 break; 18350 case GONE: 18351 if (numFlags > 0) { 18352 output += " "; 18353 } 18354 output += "GONE"; 18355 // USELESS HERE numFlags++; 18356 break; 18357 default: 18358 break; 18359 } 18360 return output; 18361 } 18362 18363 /** 18364 * Build a human readable string representation of the specified private 18365 * view flags. 18366 * 18367 * @param privateFlags the private view flags to convert to a string 18368 * @return a String representing the supplied flags 18369 */ 18370 private static String printPrivateFlags(int privateFlags) { 18371 String output = ""; 18372 int numFlags = 0; 18373 18374 if ((privateFlags & PFLAG_WANTS_FOCUS) == PFLAG_WANTS_FOCUS) { 18375 output += "WANTS_FOCUS"; 18376 numFlags++; 18377 } 18378 18379 if ((privateFlags & PFLAG_FOCUSED) == PFLAG_FOCUSED) { 18380 if (numFlags > 0) { 18381 output += " "; 18382 } 18383 output += "FOCUSED"; 18384 numFlags++; 18385 } 18386 18387 if ((privateFlags & PFLAG_SELECTED) == PFLAG_SELECTED) { 18388 if (numFlags > 0) { 18389 output += " "; 18390 } 18391 output += "SELECTED"; 18392 numFlags++; 18393 } 18394 18395 if ((privateFlags & PFLAG_IS_ROOT_NAMESPACE) == PFLAG_IS_ROOT_NAMESPACE) { 18396 if (numFlags > 0) { 18397 output += " "; 18398 } 18399 output += "IS_ROOT_NAMESPACE"; 18400 numFlags++; 18401 } 18402 18403 if ((privateFlags & PFLAG_HAS_BOUNDS) == PFLAG_HAS_BOUNDS) { 18404 if (numFlags > 0) { 18405 output += " "; 18406 } 18407 output += "HAS_BOUNDS"; 18408 numFlags++; 18409 } 18410 18411 if ((privateFlags & PFLAG_DRAWN) == PFLAG_DRAWN) { 18412 if (numFlags > 0) { 18413 output += " "; 18414 } 18415 output += "DRAWN"; 18416 // USELESS HERE numFlags++; 18417 } 18418 return output; 18419 } 18420 18421 /** 18422 * <p>Indicates whether or not this view's layout will be requested during 18423 * the next hierarchy layout pass.</p> 18424 * 18425 * @return true if the layout will be forced during next layout pass 18426 */ 18427 public boolean isLayoutRequested() { 18428 return (mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT; 18429 } 18430 18431 /** 18432 * Return true if o is a ViewGroup that is laying out using optical bounds. 18433 * @hide 18434 */ 18435 public static boolean isLayoutModeOptical(Object o) { 18436 return o instanceof ViewGroup && ((ViewGroup) o).isLayoutModeOptical(); 18437 } 18438 18439 private boolean setOpticalFrame(int left, int top, int right, int bottom) { 18440 Insets parentInsets = mParent instanceof View ? 18441 ((View) mParent).getOpticalInsets() : Insets.NONE; 18442 Insets childInsets = getOpticalInsets(); 18443 return setFrame( 18444 left + parentInsets.left - childInsets.left, 18445 top + parentInsets.top - childInsets.top, 18446 right + parentInsets.left + childInsets.right, 18447 bottom + parentInsets.top + childInsets.bottom); 18448 } 18449 18450 /** 18451 * Assign a size and position to a view and all of its 18452 * descendants 18453 * 18454 * <p>This is the second phase of the layout mechanism. 18455 * (The first is measuring). In this phase, each parent calls 18456 * layout on all of its children to position them. 18457 * This is typically done using the child measurements 18458 * that were stored in the measure pass().</p> 18459 * 18460 * <p>Derived classes should not override this method. 18461 * Derived classes with children should override 18462 * onLayout. In that method, they should 18463 * call layout on each of their children.</p> 18464 * 18465 * @param l Left position, relative to parent 18466 * @param t Top position, relative to parent 18467 * @param r Right position, relative to parent 18468 * @param b Bottom position, relative to parent 18469 */ 18470 @SuppressWarnings({"unchecked"}) 18471 public void layout(int l, int t, int r, int b) { 18472 if ((mPrivateFlags3 & PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT) != 0) { 18473 onMeasure(mOldWidthMeasureSpec, mOldHeightMeasureSpec); 18474 mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT; 18475 } 18476 18477 int oldL = mLeft; 18478 int oldT = mTop; 18479 int oldB = mBottom; 18480 int oldR = mRight; 18481 18482 boolean changed = isLayoutModeOptical(mParent) ? 18483 setOpticalFrame(l, t, r, b) : setFrame(l, t, r, b); 18484 18485 if (changed || (mPrivateFlags & PFLAG_LAYOUT_REQUIRED) == PFLAG_LAYOUT_REQUIRED) { 18486 onLayout(changed, l, t, r, b); 18487 18488 if (shouldDrawRoundScrollbar()) { 18489 if(mRoundScrollbarRenderer == null) { 18490 mRoundScrollbarRenderer = new RoundScrollbarRenderer(this); 18491 } 18492 } else { 18493 mRoundScrollbarRenderer = null; 18494 } 18495 18496 mPrivateFlags &= ~PFLAG_LAYOUT_REQUIRED; 18497 18498 ListenerInfo li = mListenerInfo; 18499 if (li != null && li.mOnLayoutChangeListeners != null) { 18500 ArrayList<OnLayoutChangeListener> listenersCopy = 18501 (ArrayList<OnLayoutChangeListener>)li.mOnLayoutChangeListeners.clone(); 18502 int numListeners = listenersCopy.size(); 18503 for (int i = 0; i < numListeners; ++i) { 18504 listenersCopy.get(i).onLayoutChange(this, l, t, r, b, oldL, oldT, oldR, oldB); 18505 } 18506 } 18507 } 18508 18509 mPrivateFlags &= ~PFLAG_FORCE_LAYOUT; 18510 mPrivateFlags3 |= PFLAG3_IS_LAID_OUT; 18511 } 18512 18513 /** 18514 * Called from layout when this view should 18515 * assign a size and position to each of its children. 18516 * 18517 * Derived classes with children should override 18518 * this method and call layout on each of 18519 * their children. 18520 * @param changed This is a new size or position for this view 18521 * @param left Left position, relative to parent 18522 * @param top Top position, relative to parent 18523 * @param right Right position, relative to parent 18524 * @param bottom Bottom position, relative to parent 18525 */ 18526 protected void onLayout(boolean changed, int left, int top, int right, int bottom) { 18527 } 18528 18529 /** 18530 * Assign a size and position to this view. 18531 * 18532 * This is called from layout. 18533 * 18534 * @param left Left position, relative to parent 18535 * @param top Top position, relative to parent 18536 * @param right Right position, relative to parent 18537 * @param bottom Bottom position, relative to parent 18538 * @return true if the new size and position are different than the 18539 * previous ones 18540 * {@hide} 18541 */ 18542 protected boolean setFrame(int left, int top, int right, int bottom) { 18543 boolean changed = false; 18544 18545 if (DBG) { 18546 Log.d("View", this + " View.setFrame(" + left + "," + top + "," 18547 + right + "," + bottom + ")"); 18548 } 18549 18550 if (mLeft != left || mRight != right || mTop != top || mBottom != bottom) { 18551 changed = true; 18552 18553 // Remember our drawn bit 18554 int drawn = mPrivateFlags & PFLAG_DRAWN; 18555 18556 int oldWidth = mRight - mLeft; 18557 int oldHeight = mBottom - mTop; 18558 int newWidth = right - left; 18559 int newHeight = bottom - top; 18560 boolean sizeChanged = (newWidth != oldWidth) || (newHeight != oldHeight); 18561 18562 // Invalidate our old position 18563 invalidate(sizeChanged); 18564 18565 mLeft = left; 18566 mTop = top; 18567 mRight = right; 18568 mBottom = bottom; 18569 mRenderNode.setLeftTopRightBottom(mLeft, mTop, mRight, mBottom); 18570 18571 mPrivateFlags |= PFLAG_HAS_BOUNDS; 18572 18573 18574 if (sizeChanged) { 18575 sizeChange(newWidth, newHeight, oldWidth, oldHeight); 18576 } 18577 18578 if ((mViewFlags & VISIBILITY_MASK) == VISIBLE || mGhostView != null) { 18579 // If we are visible, force the DRAWN bit to on so that 18580 // this invalidate will go through (at least to our parent). 18581 // This is because someone may have invalidated this view 18582 // before this call to setFrame came in, thereby clearing 18583 // the DRAWN bit. 18584 mPrivateFlags |= PFLAG_DRAWN; 18585 invalidate(sizeChanged); 18586 // parent display list may need to be recreated based on a change in the bounds 18587 // of any child 18588 invalidateParentCaches(); 18589 } 18590 18591 // Reset drawn bit to original value (invalidate turns it off) 18592 mPrivateFlags |= drawn; 18593 18594 mBackgroundSizeChanged = true; 18595 if (mForegroundInfo != null) { 18596 mForegroundInfo.mBoundsChanged = true; 18597 } 18598 18599 notifySubtreeAccessibilityStateChangedIfNeeded(); 18600 } 18601 return changed; 18602 } 18603 18604 /** 18605 * Same as setFrame, but public and hidden. For use in {@link android.transition.ChangeBounds}. 18606 * @hide 18607 */ 18608 public void setLeftTopRightBottom(int left, int top, int right, int bottom) { 18609 setFrame(left, top, right, bottom); 18610 } 18611 18612 private void sizeChange(int newWidth, int newHeight, int oldWidth, int oldHeight) { 18613 onSizeChanged(newWidth, newHeight, oldWidth, oldHeight); 18614 if (mOverlay != null) { 18615 mOverlay.getOverlayView().setRight(newWidth); 18616 mOverlay.getOverlayView().setBottom(newHeight); 18617 } 18618 rebuildOutline(); 18619 } 18620 18621 /** 18622 * Finalize inflating a view from XML. This is called as the last phase 18623 * of inflation, after all child views have been added. 18624 * 18625 * <p>Even if the subclass overrides onFinishInflate, they should always be 18626 * sure to call the super method, so that we get called. 18627 */ 18628 @CallSuper 18629 protected void onFinishInflate() { 18630 } 18631 18632 /** 18633 * Returns the resources associated with this view. 18634 * 18635 * @return Resources object. 18636 */ 18637 public Resources getResources() { 18638 return mResources; 18639 } 18640 18641 /** 18642 * Invalidates the specified Drawable. 18643 * 18644 * @param drawable the drawable to invalidate 18645 */ 18646 @Override 18647 public void invalidateDrawable(@NonNull Drawable drawable) { 18648 if (verifyDrawable(drawable)) { 18649 final Rect dirty = drawable.getDirtyBounds(); 18650 final int scrollX = mScrollX; 18651 final int scrollY = mScrollY; 18652 18653 invalidate(dirty.left + scrollX, dirty.top + scrollY, 18654 dirty.right + scrollX, dirty.bottom + scrollY); 18655 rebuildOutline(); 18656 } 18657 } 18658 18659 /** 18660 * Schedules an action on a drawable to occur at a specified time. 18661 * 18662 * @param who the recipient of the action 18663 * @param what the action to run on the drawable 18664 * @param when the time at which the action must occur. Uses the 18665 * {@link SystemClock#uptimeMillis} timebase. 18666 */ 18667 @Override 18668 public void scheduleDrawable(@NonNull Drawable who, @NonNull Runnable what, long when) { 18669 if (verifyDrawable(who) && what != null) { 18670 final long delay = when - SystemClock.uptimeMillis(); 18671 if (mAttachInfo != null) { 18672 mAttachInfo.mViewRootImpl.mChoreographer.postCallbackDelayed( 18673 Choreographer.CALLBACK_ANIMATION, what, who, 18674 Choreographer.subtractFrameDelay(delay)); 18675 } else { 18676 // Postpone the runnable until we know 18677 // on which thread it needs to run. 18678 getRunQueue().postDelayed(what, delay); 18679 } 18680 } 18681 } 18682 18683 /** 18684 * Cancels a scheduled action on a drawable. 18685 * 18686 * @param who the recipient of the action 18687 * @param what the action to cancel 18688 */ 18689 @Override 18690 public void unscheduleDrawable(@NonNull Drawable who, @NonNull Runnable what) { 18691 if (verifyDrawable(who) && what != null) { 18692 if (mAttachInfo != null) { 18693 mAttachInfo.mViewRootImpl.mChoreographer.removeCallbacks( 18694 Choreographer.CALLBACK_ANIMATION, what, who); 18695 } 18696 getRunQueue().removeCallbacks(what); 18697 } 18698 } 18699 18700 /** 18701 * Unschedule any events associated with the given Drawable. This can be 18702 * used when selecting a new Drawable into a view, so that the previous 18703 * one is completely unscheduled. 18704 * 18705 * @param who The Drawable to unschedule. 18706 * 18707 * @see #drawableStateChanged 18708 */ 18709 public void unscheduleDrawable(Drawable who) { 18710 if (mAttachInfo != null && who != null) { 18711 mAttachInfo.mViewRootImpl.mChoreographer.removeCallbacks( 18712 Choreographer.CALLBACK_ANIMATION, null, who); 18713 } 18714 } 18715 18716 /** 18717 * Resolve the Drawables depending on the layout direction. This is implicitly supposing 18718 * that the View directionality can and will be resolved before its Drawables. 18719 * 18720 * Will call {@link View#onResolveDrawables} when resolution is done. 18721 * 18722 * @hide 18723 */ 18724 protected void resolveDrawables() { 18725 // Drawables resolution may need to happen before resolving the layout direction (which is 18726 // done only during the measure() call). 18727 // If the layout direction is not resolved yet, we cannot resolve the Drawables except in 18728 // one case: when the raw layout direction has not been defined as LAYOUT_DIRECTION_INHERIT. 18729 // So, if the raw layout direction is LAYOUT_DIRECTION_LTR or LAYOUT_DIRECTION_RTL or 18730 // LAYOUT_DIRECTION_LOCALE, we can "cheat" and we don't need to wait for the layout 18731 // direction to be resolved as its resolved value will be the same as its raw value. 18732 if (!isLayoutDirectionResolved() && 18733 getRawLayoutDirection() == View.LAYOUT_DIRECTION_INHERIT) { 18734 return; 18735 } 18736 18737 final int layoutDirection = isLayoutDirectionResolved() ? 18738 getLayoutDirection() : getRawLayoutDirection(); 18739 18740 if (mBackground != null) { 18741 mBackground.setLayoutDirection(layoutDirection); 18742 } 18743 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null) { 18744 mForegroundInfo.mDrawable.setLayoutDirection(layoutDirection); 18745 } 18746 mPrivateFlags2 |= PFLAG2_DRAWABLE_RESOLVED; 18747 onResolveDrawables(layoutDirection); 18748 } 18749 18750 boolean areDrawablesResolved() { 18751 return (mPrivateFlags2 & PFLAG2_DRAWABLE_RESOLVED) == PFLAG2_DRAWABLE_RESOLVED; 18752 } 18753 18754 /** 18755 * Called when layout direction has been resolved. 18756 * 18757 * The default implementation does nothing. 18758 * 18759 * @param layoutDirection The resolved layout direction. 18760 * 18761 * @see #LAYOUT_DIRECTION_LTR 18762 * @see #LAYOUT_DIRECTION_RTL 18763 * 18764 * @hide 18765 */ 18766 public void onResolveDrawables(@ResolvedLayoutDir int layoutDirection) { 18767 } 18768 18769 /** 18770 * @hide 18771 */ 18772 protected void resetResolvedDrawables() { 18773 resetResolvedDrawablesInternal(); 18774 } 18775 18776 void resetResolvedDrawablesInternal() { 18777 mPrivateFlags2 &= ~PFLAG2_DRAWABLE_RESOLVED; 18778 } 18779 18780 /** 18781 * If your view subclass is displaying its own Drawable objects, it should 18782 * override this function and return true for any Drawable it is 18783 * displaying. This allows animations for those drawables to be 18784 * scheduled. 18785 * 18786 * <p>Be sure to call through to the super class when overriding this 18787 * function. 18788 * 18789 * @param who The Drawable to verify. Return true if it is one you are 18790 * displaying, else return the result of calling through to the 18791 * super class. 18792 * 18793 * @return boolean If true than the Drawable is being displayed in the 18794 * view; else false and it is not allowed to animate. 18795 * 18796 * @see #unscheduleDrawable(android.graphics.drawable.Drawable) 18797 * @see #drawableStateChanged() 18798 */ 18799 @CallSuper 18800 protected boolean verifyDrawable(@NonNull Drawable who) { 18801 // Avoid verifying the scroll bar drawable so that we don't end up in 18802 // an invalidation loop. This effectively prevents the scroll bar 18803 // drawable from triggering invalidations and scheduling runnables. 18804 return who == mBackground || (mForegroundInfo != null && mForegroundInfo.mDrawable == who); 18805 } 18806 18807 /** 18808 * This function is called whenever the state of the view changes in such 18809 * a way that it impacts the state of drawables being shown. 18810 * <p> 18811 * If the View has a StateListAnimator, it will also be called to run necessary state 18812 * change animations. 18813 * <p> 18814 * Be sure to call through to the superclass when overriding this function. 18815 * 18816 * @see Drawable#setState(int[]) 18817 */ 18818 @CallSuper 18819 protected void drawableStateChanged() { 18820 final int[] state = getDrawableState(); 18821 boolean changed = false; 18822 18823 final Drawable bg = mBackground; 18824 if (bg != null && bg.isStateful()) { 18825 changed |= bg.setState(state); 18826 } 18827 18828 final Drawable fg = mForegroundInfo != null ? mForegroundInfo.mDrawable : null; 18829 if (fg != null && fg.isStateful()) { 18830 changed |= fg.setState(state); 18831 } 18832 18833 if (mScrollCache != null) { 18834 final Drawable scrollBar = mScrollCache.scrollBar; 18835 if (scrollBar != null && scrollBar.isStateful()) { 18836 changed |= scrollBar.setState(state) 18837 && mScrollCache.state != ScrollabilityCache.OFF; 18838 } 18839 } 18840 18841 if (mStateListAnimator != null) { 18842 mStateListAnimator.setState(state); 18843 } 18844 18845 if (changed) { 18846 invalidate(); 18847 } 18848 } 18849 18850 /** 18851 * This function is called whenever the view hotspot changes and needs to 18852 * be propagated to drawables or child views managed by the view. 18853 * <p> 18854 * Dispatching to child views is handled by 18855 * {@link #dispatchDrawableHotspotChanged(float, float)}. 18856 * <p> 18857 * Be sure to call through to the superclass when overriding this function. 18858 * 18859 * @param x hotspot x coordinate 18860 * @param y hotspot y coordinate 18861 */ 18862 @CallSuper 18863 public void drawableHotspotChanged(float x, float y) { 18864 if (mBackground != null) { 18865 mBackground.setHotspot(x, y); 18866 } 18867 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null) { 18868 mForegroundInfo.mDrawable.setHotspot(x, y); 18869 } 18870 18871 dispatchDrawableHotspotChanged(x, y); 18872 } 18873 18874 /** 18875 * Dispatches drawableHotspotChanged to all of this View's children. 18876 * 18877 * @param x hotspot x coordinate 18878 * @param y hotspot y coordinate 18879 * @see #drawableHotspotChanged(float, float) 18880 */ 18881 public void dispatchDrawableHotspotChanged(float x, float y) { 18882 } 18883 18884 /** 18885 * Call this to force a view to update its drawable state. This will cause 18886 * drawableStateChanged to be called on this view. Views that are interested 18887 * in the new state should call getDrawableState. 18888 * 18889 * @see #drawableStateChanged 18890 * @see #getDrawableState 18891 */ 18892 public void refreshDrawableState() { 18893 mPrivateFlags |= PFLAG_DRAWABLE_STATE_DIRTY; 18894 drawableStateChanged(); 18895 18896 ViewParent parent = mParent; 18897 if (parent != null) { 18898 parent.childDrawableStateChanged(this); 18899 } 18900 } 18901 18902 /** 18903 * Return an array of resource IDs of the drawable states representing the 18904 * current state of the view. 18905 * 18906 * @return The current drawable state 18907 * 18908 * @see Drawable#setState(int[]) 18909 * @see #drawableStateChanged() 18910 * @see #onCreateDrawableState(int) 18911 */ 18912 public final int[] getDrawableState() { 18913 if ((mDrawableState != null) && ((mPrivateFlags & PFLAG_DRAWABLE_STATE_DIRTY) == 0)) { 18914 return mDrawableState; 18915 } else { 18916 mDrawableState = onCreateDrawableState(0); 18917 mPrivateFlags &= ~PFLAG_DRAWABLE_STATE_DIRTY; 18918 return mDrawableState; 18919 } 18920 } 18921 18922 /** 18923 * Generate the new {@link android.graphics.drawable.Drawable} state for 18924 * this view. This is called by the view 18925 * system when the cached Drawable state is determined to be invalid. To 18926 * retrieve the current state, you should use {@link #getDrawableState}. 18927 * 18928 * @param extraSpace if non-zero, this is the number of extra entries you 18929 * would like in the returned array in which you can place your own 18930 * states. 18931 * 18932 * @return Returns an array holding the current {@link Drawable} state of 18933 * the view. 18934 * 18935 * @see #mergeDrawableStates(int[], int[]) 18936 */ 18937 protected int[] onCreateDrawableState(int extraSpace) { 18938 if ((mViewFlags & DUPLICATE_PARENT_STATE) == DUPLICATE_PARENT_STATE && 18939 mParent instanceof View) { 18940 return ((View) mParent).onCreateDrawableState(extraSpace); 18941 } 18942 18943 int[] drawableState; 18944 18945 int privateFlags = mPrivateFlags; 18946 18947 int viewStateIndex = 0; 18948 if ((privateFlags & PFLAG_PRESSED) != 0) viewStateIndex |= StateSet.VIEW_STATE_PRESSED; 18949 if ((mViewFlags & ENABLED_MASK) == ENABLED) viewStateIndex |= StateSet.VIEW_STATE_ENABLED; 18950 if (isFocused()) viewStateIndex |= StateSet.VIEW_STATE_FOCUSED; 18951 if ((privateFlags & PFLAG_SELECTED) != 0) viewStateIndex |= StateSet.VIEW_STATE_SELECTED; 18952 if (hasWindowFocus()) viewStateIndex |= StateSet.VIEW_STATE_WINDOW_FOCUSED; 18953 if ((privateFlags & PFLAG_ACTIVATED) != 0) viewStateIndex |= StateSet.VIEW_STATE_ACTIVATED; 18954 if (mAttachInfo != null && mAttachInfo.mHardwareAccelerationRequested && 18955 ThreadedRenderer.isAvailable()) { 18956 // This is set if HW acceleration is requested, even if the current 18957 // process doesn't allow it. This is just to allow app preview 18958 // windows to better match their app. 18959 viewStateIndex |= StateSet.VIEW_STATE_ACCELERATED; 18960 } 18961 if ((privateFlags & PFLAG_HOVERED) != 0) viewStateIndex |= StateSet.VIEW_STATE_HOVERED; 18962 18963 final int privateFlags2 = mPrivateFlags2; 18964 if ((privateFlags2 & PFLAG2_DRAG_CAN_ACCEPT) != 0) { 18965 viewStateIndex |= StateSet.VIEW_STATE_DRAG_CAN_ACCEPT; 18966 } 18967 if ((privateFlags2 & PFLAG2_DRAG_HOVERED) != 0) { 18968 viewStateIndex |= StateSet.VIEW_STATE_DRAG_HOVERED; 18969 } 18970 18971 drawableState = StateSet.get(viewStateIndex); 18972 18973 //noinspection ConstantIfStatement 18974 if (false) { 18975 Log.i("View", "drawableStateIndex=" + viewStateIndex); 18976 Log.i("View", toString() 18977 + " pressed=" + ((privateFlags & PFLAG_PRESSED) != 0) 18978 + " en=" + ((mViewFlags & ENABLED_MASK) == ENABLED) 18979 + " fo=" + hasFocus() 18980 + " sl=" + ((privateFlags & PFLAG_SELECTED) != 0) 18981 + " wf=" + hasWindowFocus() 18982 + ": " + Arrays.toString(drawableState)); 18983 } 18984 18985 if (extraSpace == 0) { 18986 return drawableState; 18987 } 18988 18989 final int[] fullState; 18990 if (drawableState != null) { 18991 fullState = new int[drawableState.length + extraSpace]; 18992 System.arraycopy(drawableState, 0, fullState, 0, drawableState.length); 18993 } else { 18994 fullState = new int[extraSpace]; 18995 } 18996 18997 return fullState; 18998 } 18999 19000 /** 19001 * Merge your own state values in <var>additionalState</var> into the base 19002 * state values <var>baseState</var> that were returned by 19003 * {@link #onCreateDrawableState(int)}. 19004 * 19005 * @param baseState The base state values returned by 19006 * {@link #onCreateDrawableState(int)}, which will be modified to also hold your 19007 * own additional state values. 19008 * 19009 * @param additionalState The additional state values you would like 19010 * added to <var>baseState</var>; this array is not modified. 19011 * 19012 * @return As a convenience, the <var>baseState</var> array you originally 19013 * passed into the function is returned. 19014 * 19015 * @see #onCreateDrawableState(int) 19016 */ 19017 protected static int[] mergeDrawableStates(int[] baseState, int[] additionalState) { 19018 final int N = baseState.length; 19019 int i = N - 1; 19020 while (i >= 0 && baseState[i] == 0) { 19021 i--; 19022 } 19023 System.arraycopy(additionalState, 0, baseState, i + 1, additionalState.length); 19024 return baseState; 19025 } 19026 19027 /** 19028 * Call {@link Drawable#jumpToCurrentState() Drawable.jumpToCurrentState()} 19029 * on all Drawable objects associated with this view. 19030 * <p> 19031 * Also calls {@link StateListAnimator#jumpToCurrentState()} if there is a StateListAnimator 19032 * attached to this view. 19033 */ 19034 @CallSuper 19035 public void jumpDrawablesToCurrentState() { 19036 if (mBackground != null) { 19037 mBackground.jumpToCurrentState(); 19038 } 19039 if (mStateListAnimator != null) { 19040 mStateListAnimator.jumpToCurrentState(); 19041 } 19042 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null) { 19043 mForegroundInfo.mDrawable.jumpToCurrentState(); 19044 } 19045 } 19046 19047 /** 19048 * Sets the background color for this view. 19049 * @param color the color of the background 19050 */ 19051 @RemotableViewMethod 19052 public void setBackgroundColor(@ColorInt int color) { 19053 if (mBackground instanceof ColorDrawable) { 19054 ((ColorDrawable) mBackground.mutate()).setColor(color); 19055 computeOpaqueFlags(); 19056 mBackgroundResource = 0; 19057 } else { 19058 setBackground(new ColorDrawable(color)); 19059 } 19060 } 19061 19062 /** 19063 * Set the background to a given resource. The resource should refer to 19064 * a Drawable object or 0 to remove the background. 19065 * @param resid The identifier of the resource. 19066 * 19067 * @attr ref android.R.styleable#View_background 19068 */ 19069 @RemotableViewMethod 19070 public void setBackgroundResource(@DrawableRes int resid) { 19071 if (resid != 0 && resid == mBackgroundResource) { 19072 return; 19073 } 19074 19075 Drawable d = null; 19076 if (resid != 0) { 19077 d = mContext.getDrawable(resid); 19078 } 19079 setBackground(d); 19080 19081 mBackgroundResource = resid; 19082 } 19083 19084 /** 19085 * Set the background to a given Drawable, or remove the background. If the 19086 * background has padding, this View's padding is set to the background's 19087 * padding. However, when a background is removed, this View's padding isn't 19088 * touched. If setting the padding is desired, please use 19089 * {@link #setPadding(int, int, int, int)}. 19090 * 19091 * @param background The Drawable to use as the background, or null to remove the 19092 * background 19093 */ 19094 public void setBackground(Drawable background) { 19095 //noinspection deprecation 19096 setBackgroundDrawable(background); 19097 } 19098 19099 /** 19100 * @deprecated use {@link #setBackground(Drawable)} instead 19101 */ 19102 @Deprecated 19103 public void setBackgroundDrawable(Drawable background) { 19104 computeOpaqueFlags(); 19105 19106 if (background == mBackground) { 19107 return; 19108 } 19109 19110 boolean requestLayout = false; 19111 19112 mBackgroundResource = 0; 19113 19114 /* 19115 * Regardless of whether we're setting a new background or not, we want 19116 * to clear the previous drawable. setVisible first while we still have the callback set. 19117 */ 19118 if (mBackground != null) { 19119 if (isAttachedToWindow()) { 19120 mBackground.setVisible(false, false); 19121 } 19122 mBackground.setCallback(null); 19123 unscheduleDrawable(mBackground); 19124 } 19125 19126 if (background != null) { 19127 Rect padding = sThreadLocal.get(); 19128 if (padding == null) { 19129 padding = new Rect(); 19130 sThreadLocal.set(padding); 19131 } 19132 resetResolvedDrawablesInternal(); 19133 background.setLayoutDirection(getLayoutDirection()); 19134 if (background.getPadding(padding)) { 19135 resetResolvedPaddingInternal(); 19136 switch (background.getLayoutDirection()) { 19137 case LAYOUT_DIRECTION_RTL: 19138 mUserPaddingLeftInitial = padding.right; 19139 mUserPaddingRightInitial = padding.left; 19140 internalSetPadding(padding.right, padding.top, padding.left, padding.bottom); 19141 break; 19142 case LAYOUT_DIRECTION_LTR: 19143 default: 19144 mUserPaddingLeftInitial = padding.left; 19145 mUserPaddingRightInitial = padding.right; 19146 internalSetPadding(padding.left, padding.top, padding.right, padding.bottom); 19147 } 19148 mLeftPaddingDefined = false; 19149 mRightPaddingDefined = false; 19150 } 19151 19152 // Compare the minimum sizes of the old Drawable and the new. If there isn't an old or 19153 // if it has a different minimum size, we should layout again 19154 if (mBackground == null 19155 || mBackground.getMinimumHeight() != background.getMinimumHeight() 19156 || mBackground.getMinimumWidth() != background.getMinimumWidth()) { 19157 requestLayout = true; 19158 } 19159 19160 // Set mBackground before we set this as the callback and start making other 19161 // background drawable state change calls. In particular, the setVisible call below 19162 // can result in drawables attempting to start animations or otherwise invalidate, 19163 // which requires the view set as the callback (us) to recognize the drawable as 19164 // belonging to it as per verifyDrawable. 19165 mBackground = background; 19166 if (background.isStateful()) { 19167 background.setState(getDrawableState()); 19168 } 19169 if (isAttachedToWindow()) { 19170 background.setVisible(getWindowVisibility() == VISIBLE && isShown(), false); 19171 } 19172 19173 applyBackgroundTint(); 19174 19175 // Set callback last, since the view may still be initializing. 19176 background.setCallback(this); 19177 19178 if ((mPrivateFlags & PFLAG_SKIP_DRAW) != 0) { 19179 mPrivateFlags &= ~PFLAG_SKIP_DRAW; 19180 requestLayout = true; 19181 } 19182 } else { 19183 /* Remove the background */ 19184 mBackground = null; 19185 if ((mViewFlags & WILL_NOT_DRAW) != 0 19186 && (mForegroundInfo == null || mForegroundInfo.mDrawable == null)) { 19187 mPrivateFlags |= PFLAG_SKIP_DRAW; 19188 } 19189 19190 /* 19191 * When the background is set, we try to apply its padding to this 19192 * View. When the background is removed, we don't touch this View's 19193 * padding. This is noted in the Javadocs. Hence, we don't need to 19194 * requestLayout(), the invalidate() below is sufficient. 19195 */ 19196 19197 // The old background's minimum size could have affected this 19198 // View's layout, so let's requestLayout 19199 requestLayout = true; 19200 } 19201 19202 computeOpaqueFlags(); 19203 19204 if (requestLayout) { 19205 requestLayout(); 19206 } 19207 19208 mBackgroundSizeChanged = true; 19209 invalidate(true); 19210 invalidateOutline(); 19211 } 19212 19213 /** 19214 * Gets the background drawable 19215 * 19216 * @return The drawable used as the background for this view, if any. 19217 * 19218 * @see #setBackground(Drawable) 19219 * 19220 * @attr ref android.R.styleable#View_background 19221 */ 19222 public Drawable getBackground() { 19223 return mBackground; 19224 } 19225 19226 /** 19227 * Applies a tint to the background drawable. Does not modify the current tint 19228 * mode, which is {@link PorterDuff.Mode#SRC_IN} by default. 19229 * <p> 19230 * Subsequent calls to {@link #setBackground(Drawable)} will automatically 19231 * mutate the drawable and apply the specified tint and tint mode using 19232 * {@link Drawable#setTintList(ColorStateList)}. 19233 * 19234 * @param tint the tint to apply, may be {@code null} to clear tint 19235 * 19236 * @attr ref android.R.styleable#View_backgroundTint 19237 * @see #getBackgroundTintList() 19238 * @see Drawable#setTintList(ColorStateList) 19239 */ 19240 public void setBackgroundTintList(@Nullable ColorStateList tint) { 19241 if (mBackgroundTint == null) { 19242 mBackgroundTint = new TintInfo(); 19243 } 19244 mBackgroundTint.mTintList = tint; 19245 mBackgroundTint.mHasTintList = true; 19246 19247 applyBackgroundTint(); 19248 } 19249 19250 /** 19251 * Return the tint applied to the background drawable, if specified. 19252 * 19253 * @return the tint applied to the background drawable 19254 * @attr ref android.R.styleable#View_backgroundTint 19255 * @see #setBackgroundTintList(ColorStateList) 19256 */ 19257 @Nullable 19258 public ColorStateList getBackgroundTintList() { 19259 return mBackgroundTint != null ? mBackgroundTint.mTintList : null; 19260 } 19261 19262 /** 19263 * Specifies the blending mode used to apply the tint specified by 19264 * {@link #setBackgroundTintList(ColorStateList)}} to the background 19265 * drawable. The default mode is {@link PorterDuff.Mode#SRC_IN}. 19266 * 19267 * @param tintMode the blending mode used to apply the tint, may be 19268 * {@code null} to clear tint 19269 * @attr ref android.R.styleable#View_backgroundTintMode 19270 * @see #getBackgroundTintMode() 19271 * @see Drawable#setTintMode(PorterDuff.Mode) 19272 */ 19273 public void setBackgroundTintMode(@Nullable PorterDuff.Mode tintMode) { 19274 if (mBackgroundTint == null) { 19275 mBackgroundTint = new TintInfo(); 19276 } 19277 mBackgroundTint.mTintMode = tintMode; 19278 mBackgroundTint.mHasTintMode = true; 19279 19280 applyBackgroundTint(); 19281 } 19282 19283 /** 19284 * Return the blending mode used to apply the tint to the background 19285 * drawable, if specified. 19286 * 19287 * @return the blending mode used to apply the tint to the background 19288 * drawable 19289 * @attr ref android.R.styleable#View_backgroundTintMode 19290 * @see #setBackgroundTintMode(PorterDuff.Mode) 19291 */ 19292 @Nullable 19293 public PorterDuff.Mode getBackgroundTintMode() { 19294 return mBackgroundTint != null ? mBackgroundTint.mTintMode : null; 19295 } 19296 19297 private void applyBackgroundTint() { 19298 if (mBackground != null && mBackgroundTint != null) { 19299 final TintInfo tintInfo = mBackgroundTint; 19300 if (tintInfo.mHasTintList || tintInfo.mHasTintMode) { 19301 mBackground = mBackground.mutate(); 19302 19303 if (tintInfo.mHasTintList) { 19304 mBackground.setTintList(tintInfo.mTintList); 19305 } 19306 19307 if (tintInfo.mHasTintMode) { 19308 mBackground.setTintMode(tintInfo.mTintMode); 19309 } 19310 19311 // The drawable (or one of its children) may not have been 19312 // stateful before applying the tint, so let's try again. 19313 if (mBackground.isStateful()) { 19314 mBackground.setState(getDrawableState()); 19315 } 19316 } 19317 } 19318 } 19319 19320 /** 19321 * Returns the drawable used as the foreground of this View. The 19322 * foreground drawable, if non-null, is always drawn on top of the view's content. 19323 * 19324 * @return a Drawable or null if no foreground was set 19325 * 19326 * @see #onDrawForeground(Canvas) 19327 */ 19328 public Drawable getForeground() { 19329 return mForegroundInfo != null ? mForegroundInfo.mDrawable : null; 19330 } 19331 19332 /** 19333 * Supply a Drawable that is to be rendered on top of all of the content in the view. 19334 * 19335 * @param foreground the Drawable to be drawn on top of the children 19336 * 19337 * @attr ref android.R.styleable#View_foreground 19338 */ 19339 public void setForeground(Drawable foreground) { 19340 if (mForegroundInfo == null) { 19341 if (foreground == null) { 19342 // Nothing to do. 19343 return; 19344 } 19345 mForegroundInfo = new ForegroundInfo(); 19346 } 19347 19348 if (foreground == mForegroundInfo.mDrawable) { 19349 // Nothing to do 19350 return; 19351 } 19352 19353 if (mForegroundInfo.mDrawable != null) { 19354 if (isAttachedToWindow()) { 19355 mForegroundInfo.mDrawable.setVisible(false, false); 19356 } 19357 mForegroundInfo.mDrawable.setCallback(null); 19358 unscheduleDrawable(mForegroundInfo.mDrawable); 19359 } 19360 19361 mForegroundInfo.mDrawable = foreground; 19362 mForegroundInfo.mBoundsChanged = true; 19363 if (foreground != null) { 19364 if ((mPrivateFlags & PFLAG_SKIP_DRAW) != 0) { 19365 mPrivateFlags &= ~PFLAG_SKIP_DRAW; 19366 } 19367 foreground.setLayoutDirection(getLayoutDirection()); 19368 if (foreground.isStateful()) { 19369 foreground.setState(getDrawableState()); 19370 } 19371 applyForegroundTint(); 19372 if (isAttachedToWindow()) { 19373 foreground.setVisible(getWindowVisibility() == VISIBLE && isShown(), false); 19374 } 19375 // Set callback last, since the view may still be initializing. 19376 foreground.setCallback(this); 19377 } else if ((mViewFlags & WILL_NOT_DRAW) != 0 && mBackground == null) { 19378 mPrivateFlags |= PFLAG_SKIP_DRAW; 19379 } 19380 requestLayout(); 19381 invalidate(); 19382 } 19383 19384 /** 19385 * Magic bit used to support features of framework-internal window decor implementation details. 19386 * This used to live exclusively in FrameLayout. 19387 * 19388 * @return true if the foreground should draw inside the padding region or false 19389 * if it should draw inset by the view's padding 19390 * @hide internal use only; only used by FrameLayout and internal screen layouts. 19391 */ 19392 public boolean isForegroundInsidePadding() { 19393 return mForegroundInfo != null ? mForegroundInfo.mInsidePadding : true; 19394 } 19395 19396 /** 19397 * Describes how the foreground is positioned. 19398 * 19399 * @return foreground gravity. 19400 * 19401 * @see #setForegroundGravity(int) 19402 * 19403 * @attr ref android.R.styleable#View_foregroundGravity 19404 */ 19405 public int getForegroundGravity() { 19406 return mForegroundInfo != null ? mForegroundInfo.mGravity 19407 : Gravity.START | Gravity.TOP; 19408 } 19409 19410 /** 19411 * Describes how the foreground is positioned. Defaults to START and TOP. 19412 * 19413 * @param gravity see {@link android.view.Gravity} 19414 * 19415 * @see #getForegroundGravity() 19416 * 19417 * @attr ref android.R.styleable#View_foregroundGravity 19418 */ 19419 public void setForegroundGravity(int gravity) { 19420 if (mForegroundInfo == null) { 19421 mForegroundInfo = new ForegroundInfo(); 19422 } 19423 19424 if (mForegroundInfo.mGravity != gravity) { 19425 if ((gravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK) == 0) { 19426 gravity |= Gravity.START; 19427 } 19428 19429 if ((gravity & Gravity.VERTICAL_GRAVITY_MASK) == 0) { 19430 gravity |= Gravity.TOP; 19431 } 19432 19433 mForegroundInfo.mGravity = gravity; 19434 requestLayout(); 19435 } 19436 } 19437 19438 /** 19439 * Applies a tint to the foreground drawable. Does not modify the current tint 19440 * mode, which is {@link PorterDuff.Mode#SRC_IN} by default. 19441 * <p> 19442 * Subsequent calls to {@link #setForeground(Drawable)} will automatically 19443 * mutate the drawable and apply the specified tint and tint mode using 19444 * {@link Drawable#setTintList(ColorStateList)}. 19445 * 19446 * @param tint the tint to apply, may be {@code null} to clear tint 19447 * 19448 * @attr ref android.R.styleable#View_foregroundTint 19449 * @see #getForegroundTintList() 19450 * @see Drawable#setTintList(ColorStateList) 19451 */ 19452 public void setForegroundTintList(@Nullable ColorStateList tint) { 19453 if (mForegroundInfo == null) { 19454 mForegroundInfo = new ForegroundInfo(); 19455 } 19456 if (mForegroundInfo.mTintInfo == null) { 19457 mForegroundInfo.mTintInfo = new TintInfo(); 19458 } 19459 mForegroundInfo.mTintInfo.mTintList = tint; 19460 mForegroundInfo.mTintInfo.mHasTintList = true; 19461 19462 applyForegroundTint(); 19463 } 19464 19465 /** 19466 * Return the tint applied to the foreground drawable, if specified. 19467 * 19468 * @return the tint applied to the foreground drawable 19469 * @attr ref android.R.styleable#View_foregroundTint 19470 * @see #setForegroundTintList(ColorStateList) 19471 */ 19472 @Nullable 19473 public ColorStateList getForegroundTintList() { 19474 return mForegroundInfo != null && mForegroundInfo.mTintInfo != null 19475 ? mForegroundInfo.mTintInfo.mTintList : null; 19476 } 19477 19478 /** 19479 * Specifies the blending mode used to apply the tint specified by 19480 * {@link #setForegroundTintList(ColorStateList)}} to the background 19481 * drawable. The default mode is {@link PorterDuff.Mode#SRC_IN}. 19482 * 19483 * @param tintMode the blending mode used to apply the tint, may be 19484 * {@code null} to clear tint 19485 * @attr ref android.R.styleable#View_foregroundTintMode 19486 * @see #getForegroundTintMode() 19487 * @see Drawable#setTintMode(PorterDuff.Mode) 19488 */ 19489 public void setForegroundTintMode(@Nullable PorterDuff.Mode tintMode) { 19490 if (mForegroundInfo == null) { 19491 mForegroundInfo = new ForegroundInfo(); 19492 } 19493 if (mForegroundInfo.mTintInfo == null) { 19494 mForegroundInfo.mTintInfo = new TintInfo(); 19495 } 19496 mForegroundInfo.mTintInfo.mTintMode = tintMode; 19497 mForegroundInfo.mTintInfo.mHasTintMode = true; 19498 19499 applyForegroundTint(); 19500 } 19501 19502 /** 19503 * Return the blending mode used to apply the tint to the foreground 19504 * drawable, if specified. 19505 * 19506 * @return the blending mode used to apply the tint to the foreground 19507 * drawable 19508 * @attr ref android.R.styleable#View_foregroundTintMode 19509 * @see #setForegroundTintMode(PorterDuff.Mode) 19510 */ 19511 @Nullable 19512 public PorterDuff.Mode getForegroundTintMode() { 19513 return mForegroundInfo != null && mForegroundInfo.mTintInfo != null 19514 ? mForegroundInfo.mTintInfo.mTintMode : null; 19515 } 19516 19517 private void applyForegroundTint() { 19518 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null 19519 && mForegroundInfo.mTintInfo != null) { 19520 final TintInfo tintInfo = mForegroundInfo.mTintInfo; 19521 if (tintInfo.mHasTintList || tintInfo.mHasTintMode) { 19522 mForegroundInfo.mDrawable = mForegroundInfo.mDrawable.mutate(); 19523 19524 if (tintInfo.mHasTintList) { 19525 mForegroundInfo.mDrawable.setTintList(tintInfo.mTintList); 19526 } 19527 19528 if (tintInfo.mHasTintMode) { 19529 mForegroundInfo.mDrawable.setTintMode(tintInfo.mTintMode); 19530 } 19531 19532 // The drawable (or one of its children) may not have been 19533 // stateful before applying the tint, so let's try again. 19534 if (mForegroundInfo.mDrawable.isStateful()) { 19535 mForegroundInfo.mDrawable.setState(getDrawableState()); 19536 } 19537 } 19538 } 19539 } 19540 19541 /** 19542 * Draw any foreground content for this view. 19543 * 19544 * <p>Foreground content may consist of scroll bars, a {@link #setForeground foreground} 19545 * drawable or other view-specific decorations. The foreground is drawn on top of the 19546 * primary view content.</p> 19547 * 19548 * @param canvas canvas to draw into 19549 */ 19550 public void onDrawForeground(Canvas canvas) { 19551 onDrawScrollIndicators(canvas); 19552 onDrawScrollBars(canvas); 19553 19554 final Drawable foreground = mForegroundInfo != null ? mForegroundInfo.mDrawable : null; 19555 if (foreground != null) { 19556 if (mForegroundInfo.mBoundsChanged) { 19557 mForegroundInfo.mBoundsChanged = false; 19558 final Rect selfBounds = mForegroundInfo.mSelfBounds; 19559 final Rect overlayBounds = mForegroundInfo.mOverlayBounds; 19560 19561 if (mForegroundInfo.mInsidePadding) { 19562 selfBounds.set(0, 0, getWidth(), getHeight()); 19563 } else { 19564 selfBounds.set(getPaddingLeft(), getPaddingTop(), 19565 getWidth() - getPaddingRight(), getHeight() - getPaddingBottom()); 19566 } 19567 19568 final int ld = getLayoutDirection(); 19569 Gravity.apply(mForegroundInfo.mGravity, foreground.getIntrinsicWidth(), 19570 foreground.getIntrinsicHeight(), selfBounds, overlayBounds, ld); 19571 foreground.setBounds(overlayBounds); 19572 } 19573 19574 foreground.draw(canvas); 19575 } 19576 } 19577 19578 /** 19579 * Sets the padding. The view may add on the space required to display 19580 * the scrollbars, depending on the style and visibility of the scrollbars. 19581 * So the values returned from {@link #getPaddingLeft}, {@link #getPaddingTop}, 19582 * {@link #getPaddingRight} and {@link #getPaddingBottom} may be different 19583 * from the values set in this call. 19584 * 19585 * @attr ref android.R.styleable#View_padding 19586 * @attr ref android.R.styleable#View_paddingBottom 19587 * @attr ref android.R.styleable#View_paddingLeft 19588 * @attr ref android.R.styleable#View_paddingRight 19589 * @attr ref android.R.styleable#View_paddingTop 19590 * @param left the left padding in pixels 19591 * @param top the top padding in pixels 19592 * @param right the right padding in pixels 19593 * @param bottom the bottom padding in pixels 19594 */ 19595 public void setPadding(int left, int top, int right, int bottom) { 19596 resetResolvedPaddingInternal(); 19597 19598 mUserPaddingStart = UNDEFINED_PADDING; 19599 mUserPaddingEnd = UNDEFINED_PADDING; 19600 19601 mUserPaddingLeftInitial = left; 19602 mUserPaddingRightInitial = right; 19603 19604 mLeftPaddingDefined = true; 19605 mRightPaddingDefined = true; 19606 19607 internalSetPadding(left, top, right, bottom); 19608 } 19609 19610 /** 19611 * @hide 19612 */ 19613 protected void internalSetPadding(int left, int top, int right, int bottom) { 19614 mUserPaddingLeft = left; 19615 mUserPaddingRight = right; 19616 mUserPaddingBottom = bottom; 19617 19618 final int viewFlags = mViewFlags; 19619 boolean changed = false; 19620 19621 // Common case is there are no scroll bars. 19622 if ((viewFlags & (SCROLLBARS_VERTICAL|SCROLLBARS_HORIZONTAL)) != 0) { 19623 if ((viewFlags & SCROLLBARS_VERTICAL) != 0) { 19624 final int offset = (viewFlags & SCROLLBARS_INSET_MASK) == 0 19625 ? 0 : getVerticalScrollbarWidth(); 19626 switch (mVerticalScrollbarPosition) { 19627 case SCROLLBAR_POSITION_DEFAULT: 19628 if (isLayoutRtl()) { 19629 left += offset; 19630 } else { 19631 right += offset; 19632 } 19633 break; 19634 case SCROLLBAR_POSITION_RIGHT: 19635 right += offset; 19636 break; 19637 case SCROLLBAR_POSITION_LEFT: 19638 left += offset; 19639 break; 19640 } 19641 } 19642 if ((viewFlags & SCROLLBARS_HORIZONTAL) != 0) { 19643 bottom += (viewFlags & SCROLLBARS_INSET_MASK) == 0 19644 ? 0 : getHorizontalScrollbarHeight(); 19645 } 19646 } 19647 19648 if (mPaddingLeft != left) { 19649 changed = true; 19650 mPaddingLeft = left; 19651 } 19652 if (mPaddingTop != top) { 19653 changed = true; 19654 mPaddingTop = top; 19655 } 19656 if (mPaddingRight != right) { 19657 changed = true; 19658 mPaddingRight = right; 19659 } 19660 if (mPaddingBottom != bottom) { 19661 changed = true; 19662 mPaddingBottom = bottom; 19663 } 19664 19665 if (changed) { 19666 requestLayout(); 19667 invalidateOutline(); 19668 } 19669 } 19670 19671 /** 19672 * Sets the relative padding. The view may add on the space required to display 19673 * the scrollbars, depending on the style and visibility of the scrollbars. 19674 * So the values returned from {@link #getPaddingStart}, {@link #getPaddingTop}, 19675 * {@link #getPaddingEnd} and {@link #getPaddingBottom} may be different 19676 * from the values set in this call. 19677 * 19678 * @attr ref android.R.styleable#View_padding 19679 * @attr ref android.R.styleable#View_paddingBottom 19680 * @attr ref android.R.styleable#View_paddingStart 19681 * @attr ref android.R.styleable#View_paddingEnd 19682 * @attr ref android.R.styleable#View_paddingTop 19683 * @param start the start padding in pixels 19684 * @param top the top padding in pixels 19685 * @param end the end padding in pixels 19686 * @param bottom the bottom padding in pixels 19687 */ 19688 public void setPaddingRelative(int start, int top, int end, int bottom) { 19689 resetResolvedPaddingInternal(); 19690 19691 mUserPaddingStart = start; 19692 mUserPaddingEnd = end; 19693 mLeftPaddingDefined = true; 19694 mRightPaddingDefined = true; 19695 19696 switch(getLayoutDirection()) { 19697 case LAYOUT_DIRECTION_RTL: 19698 mUserPaddingLeftInitial = end; 19699 mUserPaddingRightInitial = start; 19700 internalSetPadding(end, top, start, bottom); 19701 break; 19702 case LAYOUT_DIRECTION_LTR: 19703 default: 19704 mUserPaddingLeftInitial = start; 19705 mUserPaddingRightInitial = end; 19706 internalSetPadding(start, top, end, bottom); 19707 } 19708 } 19709 19710 /** 19711 * Returns the top padding of this view. 19712 * 19713 * @return the top padding in pixels 19714 */ 19715 public int getPaddingTop() { 19716 return mPaddingTop; 19717 } 19718 19719 /** 19720 * Returns the bottom padding of this view. If there are inset and enabled 19721 * scrollbars, this value may include the space required to display the 19722 * scrollbars as well. 19723 * 19724 * @return the bottom padding in pixels 19725 */ 19726 public int getPaddingBottom() { 19727 return mPaddingBottom; 19728 } 19729 19730 /** 19731 * Returns the left padding of this view. If there are inset and enabled 19732 * scrollbars, this value may include the space required to display the 19733 * scrollbars as well. 19734 * 19735 * @return the left padding in pixels 19736 */ 19737 public int getPaddingLeft() { 19738 if (!isPaddingResolved()) { 19739 resolvePadding(); 19740 } 19741 return mPaddingLeft; 19742 } 19743 19744 /** 19745 * Returns the start padding of this view depending on its resolved layout direction. 19746 * If there are inset and enabled scrollbars, this value may include the space 19747 * required to display the scrollbars as well. 19748 * 19749 * @return the start padding in pixels 19750 */ 19751 public int getPaddingStart() { 19752 if (!isPaddingResolved()) { 19753 resolvePadding(); 19754 } 19755 return (getLayoutDirection() == LAYOUT_DIRECTION_RTL) ? 19756 mPaddingRight : mPaddingLeft; 19757 } 19758 19759 /** 19760 * Returns the right padding of this view. If there are inset and enabled 19761 * scrollbars, this value may include the space required to display the 19762 * scrollbars as well. 19763 * 19764 * @return the right padding in pixels 19765 */ 19766 public int getPaddingRight() { 19767 if (!isPaddingResolved()) { 19768 resolvePadding(); 19769 } 19770 return mPaddingRight; 19771 } 19772 19773 /** 19774 * Returns the end padding of this view depending on its resolved layout direction. 19775 * If there are inset and enabled scrollbars, this value may include the space 19776 * required to display the scrollbars as well. 19777 * 19778 * @return the end padding in pixels 19779 */ 19780 public int getPaddingEnd() { 19781 if (!isPaddingResolved()) { 19782 resolvePadding(); 19783 } 19784 return (getLayoutDirection() == LAYOUT_DIRECTION_RTL) ? 19785 mPaddingLeft : mPaddingRight; 19786 } 19787 19788 /** 19789 * Return if the padding has been set through relative values 19790 * {@link #setPaddingRelative(int, int, int, int)} or through 19791 * @attr ref android.R.styleable#View_paddingStart or 19792 * @attr ref android.R.styleable#View_paddingEnd 19793 * 19794 * @return true if the padding is relative or false if it is not. 19795 */ 19796 public boolean isPaddingRelative() { 19797 return (mUserPaddingStart != UNDEFINED_PADDING || mUserPaddingEnd != UNDEFINED_PADDING); 19798 } 19799 19800 Insets computeOpticalInsets() { 19801 return (mBackground == null) ? Insets.NONE : mBackground.getOpticalInsets(); 19802 } 19803 19804 /** 19805 * @hide 19806 */ 19807 public void resetPaddingToInitialValues() { 19808 if (isRtlCompatibilityMode()) { 19809 mPaddingLeft = mUserPaddingLeftInitial; 19810 mPaddingRight = mUserPaddingRightInitial; 19811 return; 19812 } 19813 if (isLayoutRtl()) { 19814 mPaddingLeft = (mUserPaddingEnd >= 0) ? mUserPaddingEnd : mUserPaddingLeftInitial; 19815 mPaddingRight = (mUserPaddingStart >= 0) ? mUserPaddingStart : mUserPaddingRightInitial; 19816 } else { 19817 mPaddingLeft = (mUserPaddingStart >= 0) ? mUserPaddingStart : mUserPaddingLeftInitial; 19818 mPaddingRight = (mUserPaddingEnd >= 0) ? mUserPaddingEnd : mUserPaddingRightInitial; 19819 } 19820 } 19821 19822 /** 19823 * @hide 19824 */ 19825 public Insets getOpticalInsets() { 19826 if (mLayoutInsets == null) { 19827 mLayoutInsets = computeOpticalInsets(); 19828 } 19829 return mLayoutInsets; 19830 } 19831 19832 /** 19833 * Set this view's optical insets. 19834 * 19835 * <p>This method should be treated similarly to setMeasuredDimension and not as a general 19836 * property. Views that compute their own optical insets should call it as part of measurement. 19837 * This method does not request layout. If you are setting optical insets outside of 19838 * measure/layout itself you will want to call requestLayout() yourself. 19839 * </p> 19840 * @hide 19841 */ 19842 public void setOpticalInsets(Insets insets) { 19843 mLayoutInsets = insets; 19844 } 19845 19846 /** 19847 * Changes the selection state of this view. A view can be selected or not. 19848 * Note that selection is not the same as focus. Views are typically 19849 * selected in the context of an AdapterView like ListView or GridView; 19850 * the selected view is the view that is highlighted. 19851 * 19852 * @param selected true if the view must be selected, false otherwise 19853 */ 19854 public void setSelected(boolean selected) { 19855 //noinspection DoubleNegation 19856 if (((mPrivateFlags & PFLAG_SELECTED) != 0) != selected) { 19857 mPrivateFlags = (mPrivateFlags & ~PFLAG_SELECTED) | (selected ? PFLAG_SELECTED : 0); 19858 if (!selected) resetPressedState(); 19859 invalidate(true); 19860 refreshDrawableState(); 19861 dispatchSetSelected(selected); 19862 if (selected) { 19863 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED); 19864 } else { 19865 notifyViewAccessibilityStateChangedIfNeeded( 19866 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 19867 } 19868 } 19869 } 19870 19871 /** 19872 * Dispatch setSelected to all of this View's children. 19873 * 19874 * @see #setSelected(boolean) 19875 * 19876 * @param selected The new selected state 19877 */ 19878 protected void dispatchSetSelected(boolean selected) { 19879 } 19880 19881 /** 19882 * Indicates the selection state of this view. 19883 * 19884 * @return true if the view is selected, false otherwise 19885 */ 19886 @ViewDebug.ExportedProperty 19887 public boolean isSelected() { 19888 return (mPrivateFlags & PFLAG_SELECTED) != 0; 19889 } 19890 19891 /** 19892 * Changes the activated state of this view. A view can be activated or not. 19893 * Note that activation is not the same as selection. Selection is 19894 * a transient property, representing the view (hierarchy) the user is 19895 * currently interacting with. Activation is a longer-term state that the 19896 * user can move views in and out of. For example, in a list view with 19897 * single or multiple selection enabled, the views in the current selection 19898 * set are activated. (Um, yeah, we are deeply sorry about the terminology 19899 * here.) The activated state is propagated down to children of the view it 19900 * is set on. 19901 * 19902 * @param activated true if the view must be activated, false otherwise 19903 */ 19904 public void setActivated(boolean activated) { 19905 //noinspection DoubleNegation 19906 if (((mPrivateFlags & PFLAG_ACTIVATED) != 0) != activated) { 19907 mPrivateFlags = (mPrivateFlags & ~PFLAG_ACTIVATED) | (activated ? PFLAG_ACTIVATED : 0); 19908 invalidate(true); 19909 refreshDrawableState(); 19910 dispatchSetActivated(activated); 19911 } 19912 } 19913 19914 /** 19915 * Dispatch setActivated to all of this View's children. 19916 * 19917 * @see #setActivated(boolean) 19918 * 19919 * @param activated The new activated state 19920 */ 19921 protected void dispatchSetActivated(boolean activated) { 19922 } 19923 19924 /** 19925 * Indicates the activation state of this view. 19926 * 19927 * @return true if the view is activated, false otherwise 19928 */ 19929 @ViewDebug.ExportedProperty 19930 public boolean isActivated() { 19931 return (mPrivateFlags & PFLAG_ACTIVATED) != 0; 19932 } 19933 19934 /** 19935 * Returns the ViewTreeObserver for this view's hierarchy. The view tree 19936 * observer can be used to get notifications when global events, like 19937 * layout, happen. 19938 * 19939 * The returned ViewTreeObserver observer is not guaranteed to remain 19940 * valid for the lifetime of this View. If the caller of this method keeps 19941 * a long-lived reference to ViewTreeObserver, it should always check for 19942 * the return value of {@link ViewTreeObserver#isAlive()}. 19943 * 19944 * @return The ViewTreeObserver for this view's hierarchy. 19945 */ 19946 public ViewTreeObserver getViewTreeObserver() { 19947 if (mAttachInfo != null) { 19948 return mAttachInfo.mTreeObserver; 19949 } 19950 if (mFloatingTreeObserver == null) { 19951 mFloatingTreeObserver = new ViewTreeObserver(mContext); 19952 } 19953 return mFloatingTreeObserver; 19954 } 19955 19956 /** 19957 * <p>Finds the topmost view in the current view hierarchy.</p> 19958 * 19959 * @return the topmost view containing this view 19960 */ 19961 public View getRootView() { 19962 if (mAttachInfo != null) { 19963 final View v = mAttachInfo.mRootView; 19964 if (v != null) { 19965 return v; 19966 } 19967 } 19968 19969 View parent = this; 19970 19971 while (parent.mParent != null && parent.mParent instanceof View) { 19972 parent = (View) parent.mParent; 19973 } 19974 19975 return parent; 19976 } 19977 19978 /** 19979 * Transforms a motion event from view-local coordinates to on-screen 19980 * coordinates. 19981 * 19982 * @param ev the view-local motion event 19983 * @return false if the transformation could not be applied 19984 * @hide 19985 */ 19986 public boolean toGlobalMotionEvent(MotionEvent ev) { 19987 final AttachInfo info = mAttachInfo; 19988 if (info == null) { 19989 return false; 19990 } 19991 19992 final Matrix m = info.mTmpMatrix; 19993 m.set(Matrix.IDENTITY_MATRIX); 19994 transformMatrixToGlobal(m); 19995 ev.transform(m); 19996 return true; 19997 } 19998 19999 /** 20000 * Transforms a motion event from on-screen coordinates to view-local 20001 * coordinates. 20002 * 20003 * @param ev the on-screen motion event 20004 * @return false if the transformation could not be applied 20005 * @hide 20006 */ 20007 public boolean toLocalMotionEvent(MotionEvent ev) { 20008 final AttachInfo info = mAttachInfo; 20009 if (info == null) { 20010 return false; 20011 } 20012 20013 final Matrix m = info.mTmpMatrix; 20014 m.set(Matrix.IDENTITY_MATRIX); 20015 transformMatrixToLocal(m); 20016 ev.transform(m); 20017 return true; 20018 } 20019 20020 /** 20021 * Modifies the input matrix such that it maps view-local coordinates to 20022 * on-screen coordinates. 20023 * 20024 * @param m input matrix to modify 20025 * @hide 20026 */ 20027 public void transformMatrixToGlobal(Matrix m) { 20028 final ViewParent parent = mParent; 20029 if (parent instanceof View) { 20030 final View vp = (View) parent; 20031 vp.transformMatrixToGlobal(m); 20032 m.preTranslate(-vp.mScrollX, -vp.mScrollY); 20033 } else if (parent instanceof ViewRootImpl) { 20034 final ViewRootImpl vr = (ViewRootImpl) parent; 20035 vr.transformMatrixToGlobal(m); 20036 m.preTranslate(0, -vr.mCurScrollY); 20037 } 20038 20039 m.preTranslate(mLeft, mTop); 20040 20041 if (!hasIdentityMatrix()) { 20042 m.preConcat(getMatrix()); 20043 } 20044 } 20045 20046 /** 20047 * Modifies the input matrix such that it maps on-screen coordinates to 20048 * view-local coordinates. 20049 * 20050 * @param m input matrix to modify 20051 * @hide 20052 */ 20053 public void transformMatrixToLocal(Matrix m) { 20054 final ViewParent parent = mParent; 20055 if (parent instanceof View) { 20056 final View vp = (View) parent; 20057 vp.transformMatrixToLocal(m); 20058 m.postTranslate(vp.mScrollX, vp.mScrollY); 20059 } else if (parent instanceof ViewRootImpl) { 20060 final ViewRootImpl vr = (ViewRootImpl) parent; 20061 vr.transformMatrixToLocal(m); 20062 m.postTranslate(0, vr.mCurScrollY); 20063 } 20064 20065 m.postTranslate(-mLeft, -mTop); 20066 20067 if (!hasIdentityMatrix()) { 20068 m.postConcat(getInverseMatrix()); 20069 } 20070 } 20071 20072 /** 20073 * @hide 20074 */ 20075 @ViewDebug.ExportedProperty(category = "layout", indexMapping = { 20076 @ViewDebug.IntToString(from = 0, to = "x"), 20077 @ViewDebug.IntToString(from = 1, to = "y") 20078 }) 20079 public int[] getLocationOnScreen() { 20080 int[] location = new int[2]; 20081 getLocationOnScreen(location); 20082 return location; 20083 } 20084 20085 /** 20086 * <p>Computes the coordinates of this view on the screen. The argument 20087 * must be an array of two integers. After the method returns, the array 20088 * contains the x and y location in that order.</p> 20089 * 20090 * @param outLocation an array of two integers in which to hold the coordinates 20091 */ 20092 public void getLocationOnScreen(@Size(2) int[] outLocation) { 20093 getLocationInWindow(outLocation); 20094 20095 final AttachInfo info = mAttachInfo; 20096 if (info != null) { 20097 outLocation[0] += info.mWindowLeft; 20098 outLocation[1] += info.mWindowTop; 20099 } 20100 } 20101 20102 /** 20103 * <p>Computes the coordinates of this view in its window. The argument 20104 * must be an array of two integers. After the method returns, the array 20105 * contains the x and y location in that order.</p> 20106 * 20107 * @param outLocation an array of two integers in which to hold the coordinates 20108 */ 20109 public void getLocationInWindow(@Size(2) int[] outLocation) { 20110 if (outLocation == null || outLocation.length < 2) { 20111 throw new IllegalArgumentException("outLocation must be an array of two integers"); 20112 } 20113 20114 outLocation[0] = 0; 20115 outLocation[1] = 0; 20116 20117 transformFromViewToWindowSpace(outLocation); 20118 } 20119 20120 /** @hide */ 20121 public void transformFromViewToWindowSpace(@Size(2) int[] inOutLocation) { 20122 if (inOutLocation == null || inOutLocation.length < 2) { 20123 throw new IllegalArgumentException("inOutLocation must be an array of two integers"); 20124 } 20125 20126 if (mAttachInfo == null) { 20127 // When the view is not attached to a window, this method does not make sense 20128 inOutLocation[0] = inOutLocation[1] = 0; 20129 return; 20130 } 20131 20132 float position[] = mAttachInfo.mTmpTransformLocation; 20133 position[0] = inOutLocation[0]; 20134 position[1] = inOutLocation[1]; 20135 20136 if (!hasIdentityMatrix()) { 20137 getMatrix().mapPoints(position); 20138 } 20139 20140 position[0] += mLeft; 20141 position[1] += mTop; 20142 20143 ViewParent viewParent = mParent; 20144 while (viewParent instanceof View) { 20145 final View view = (View) viewParent; 20146 20147 position[0] -= view.mScrollX; 20148 position[1] -= view.mScrollY; 20149 20150 if (!view.hasIdentityMatrix()) { 20151 view.getMatrix().mapPoints(position); 20152 } 20153 20154 position[0] += view.mLeft; 20155 position[1] += view.mTop; 20156 20157 viewParent = view.mParent; 20158 } 20159 20160 if (viewParent instanceof ViewRootImpl) { 20161 // *cough* 20162 final ViewRootImpl vr = (ViewRootImpl) viewParent; 20163 position[1] -= vr.mCurScrollY; 20164 } 20165 20166 inOutLocation[0] = Math.round(position[0]); 20167 inOutLocation[1] = Math.round(position[1]); 20168 } 20169 20170 /** 20171 * @param id the id of the view to be found 20172 * @return the view of the specified id, null if cannot be found 20173 * @hide 20174 */ 20175 protected View findViewTraversal(@IdRes int id) { 20176 if (id == mID) { 20177 return this; 20178 } 20179 return null; 20180 } 20181 20182 /** 20183 * @param tag the tag of the view to be found 20184 * @return the view of specified tag, null if cannot be found 20185 * @hide 20186 */ 20187 protected View findViewWithTagTraversal(Object tag) { 20188 if (tag != null && tag.equals(mTag)) { 20189 return this; 20190 } 20191 return null; 20192 } 20193 20194 /** 20195 * @param predicate The predicate to evaluate. 20196 * @param childToSkip If not null, ignores this child during the recursive traversal. 20197 * @return The first view that matches the predicate or null. 20198 * @hide 20199 */ 20200 protected View findViewByPredicateTraversal(Predicate<View> predicate, View childToSkip) { 20201 if (predicate.test(this)) { 20202 return this; 20203 } 20204 return null; 20205 } 20206 20207 /** 20208 * Look for a child view with the given id. If this view has the given 20209 * id, return this view. 20210 * 20211 * @param id The id to search for. 20212 * @return The view that has the given id in the hierarchy or null 20213 */ 20214 @Nullable 20215 public final View findViewById(@IdRes int id) { 20216 if (id < 0) { 20217 return null; 20218 } 20219 return findViewTraversal(id); 20220 } 20221 20222 /** 20223 * Finds a view by its unuque and stable accessibility id. 20224 * 20225 * @param accessibilityId The searched accessibility id. 20226 * @return The found view. 20227 */ 20228 final View findViewByAccessibilityId(int accessibilityId) { 20229 if (accessibilityId < 0) { 20230 return null; 20231 } 20232 View view = findViewByAccessibilityIdTraversal(accessibilityId); 20233 if (view != null) { 20234 return view.includeForAccessibility() ? view : null; 20235 } 20236 return null; 20237 } 20238 20239 /** 20240 * Performs the traversal to find a view by its unuque and stable accessibility id. 20241 * 20242 * <strong>Note:</strong>This method does not stop at the root namespace 20243 * boundary since the user can touch the screen at an arbitrary location 20244 * potentially crossing the root namespace bounday which will send an 20245 * accessibility event to accessibility services and they should be able 20246 * to obtain the event source. Also accessibility ids are guaranteed to be 20247 * unique in the window. 20248 * 20249 * @param accessibilityId The accessibility id. 20250 * @return The found view. 20251 * 20252 * @hide 20253 */ 20254 public View findViewByAccessibilityIdTraversal(int accessibilityId) { 20255 if (getAccessibilityViewId() == accessibilityId) { 20256 return this; 20257 } 20258 return null; 20259 } 20260 20261 /** 20262 * Look for a child view with the given tag. If this view has the given 20263 * tag, return this view. 20264 * 20265 * @param tag The tag to search for, using "tag.equals(getTag())". 20266 * @return The View that has the given tag in the hierarchy or null 20267 */ 20268 public final View findViewWithTag(Object tag) { 20269 if (tag == null) { 20270 return null; 20271 } 20272 return findViewWithTagTraversal(tag); 20273 } 20274 20275 /** 20276 * Look for a child view that matches the specified predicate. 20277 * If this view matches the predicate, return this view. 20278 * 20279 * @param predicate The predicate to evaluate. 20280 * @return The first view that matches the predicate or null. 20281 * @hide 20282 */ 20283 public final View findViewByPredicate(Predicate<View> predicate) { 20284 return findViewByPredicateTraversal(predicate, null); 20285 } 20286 20287 /** 20288 * Look for a child view that matches the specified predicate, 20289 * starting with the specified view and its descendents and then 20290 * recusively searching the ancestors and siblings of that view 20291 * until this view is reached. 20292 * 20293 * This method is useful in cases where the predicate does not match 20294 * a single unique view (perhaps multiple views use the same id) 20295 * and we are trying to find the view that is "closest" in scope to the 20296 * starting view. 20297 * 20298 * @param start The view to start from. 20299 * @param predicate The predicate to evaluate. 20300 * @return The first view that matches the predicate or null. 20301 * @hide 20302 */ 20303 public final View findViewByPredicateInsideOut(View start, Predicate<View> predicate) { 20304 View childToSkip = null; 20305 for (;;) { 20306 View view = start.findViewByPredicateTraversal(predicate, childToSkip); 20307 if (view != null || start == this) { 20308 return view; 20309 } 20310 20311 ViewParent parent = start.getParent(); 20312 if (parent == null || !(parent instanceof View)) { 20313 return null; 20314 } 20315 20316 childToSkip = start; 20317 start = (View) parent; 20318 } 20319 } 20320 20321 /** 20322 * Sets the identifier for this view. The identifier does not have to be 20323 * unique in this view's hierarchy. The identifier should be a positive 20324 * number. 20325 * 20326 * @see #NO_ID 20327 * @see #getId() 20328 * @see #findViewById(int) 20329 * 20330 * @param id a number used to identify the view 20331 * 20332 * @attr ref android.R.styleable#View_id 20333 */ 20334 public void setId(@IdRes int id) { 20335 mID = id; 20336 if (mID == View.NO_ID && mLabelForId != View.NO_ID) { 20337 mID = generateViewId(); 20338 } 20339 } 20340 20341 /** 20342 * {@hide} 20343 * 20344 * @param isRoot true if the view belongs to the root namespace, false 20345 * otherwise 20346 */ 20347 public void setIsRootNamespace(boolean isRoot) { 20348 if (isRoot) { 20349 mPrivateFlags |= PFLAG_IS_ROOT_NAMESPACE; 20350 } else { 20351 mPrivateFlags &= ~PFLAG_IS_ROOT_NAMESPACE; 20352 } 20353 } 20354 20355 /** 20356 * {@hide} 20357 * 20358 * @return true if the view belongs to the root namespace, false otherwise 20359 */ 20360 public boolean isRootNamespace() { 20361 return (mPrivateFlags&PFLAG_IS_ROOT_NAMESPACE) != 0; 20362 } 20363 20364 /** 20365 * Returns this view's identifier. 20366 * 20367 * @return a positive integer used to identify the view or {@link #NO_ID} 20368 * if the view has no ID 20369 * 20370 * @see #setId(int) 20371 * @see #findViewById(int) 20372 * @attr ref android.R.styleable#View_id 20373 */ 20374 @IdRes 20375 @ViewDebug.CapturedViewProperty 20376 public int getId() { 20377 return mID; 20378 } 20379 20380 /** 20381 * Returns this view's tag. 20382 * 20383 * @return the Object stored in this view as a tag, or {@code null} if not 20384 * set 20385 * 20386 * @see #setTag(Object) 20387 * @see #getTag(int) 20388 */ 20389 @ViewDebug.ExportedProperty 20390 public Object getTag() { 20391 return mTag; 20392 } 20393 20394 /** 20395 * Sets the tag associated with this view. A tag can be used to mark 20396 * a view in its hierarchy and does not have to be unique within the 20397 * hierarchy. Tags can also be used to store data within a view without 20398 * resorting to another data structure. 20399 * 20400 * @param tag an Object to tag the view with 20401 * 20402 * @see #getTag() 20403 * @see #setTag(int, Object) 20404 */ 20405 public void setTag(final Object tag) { 20406 mTag = tag; 20407 } 20408 20409 /** 20410 * Returns the tag associated with this view and the specified key. 20411 * 20412 * @param key The key identifying the tag 20413 * 20414 * @return the Object stored in this view as a tag, or {@code null} if not 20415 * set 20416 * 20417 * @see #setTag(int, Object) 20418 * @see #getTag() 20419 */ 20420 public Object getTag(int key) { 20421 if (mKeyedTags != null) return mKeyedTags.get(key); 20422 return null; 20423 } 20424 20425 /** 20426 * Sets a tag associated with this view and a key. A tag can be used 20427 * to mark a view in its hierarchy and does not have to be unique within 20428 * the hierarchy. Tags can also be used to store data within a view 20429 * without resorting to another data structure. 20430 * 20431 * The specified key should be an id declared in the resources of the 20432 * application to ensure it is unique (see the <a 20433 * href="{@docRoot}guide/topics/resources/more-resources.html#Id">ID resource type</a>). 20434 * Keys identified as belonging to 20435 * the Android framework or not associated with any package will cause 20436 * an {@link IllegalArgumentException} to be thrown. 20437 * 20438 * @param key The key identifying the tag 20439 * @param tag An Object to tag the view with 20440 * 20441 * @throws IllegalArgumentException If they specified key is not valid 20442 * 20443 * @see #setTag(Object) 20444 * @see #getTag(int) 20445 */ 20446 public void setTag(int key, final Object tag) { 20447 // If the package id is 0x00 or 0x01, it's either an undefined package 20448 // or a framework id 20449 if ((key >>> 24) < 2) { 20450 throw new IllegalArgumentException("The key must be an application-specific " 20451 + "resource id."); 20452 } 20453 20454 setKeyedTag(key, tag); 20455 } 20456 20457 /** 20458 * Variation of {@link #setTag(int, Object)} that enforces the key to be a 20459 * framework id. 20460 * 20461 * @hide 20462 */ 20463 public void setTagInternal(int key, Object tag) { 20464 if ((key >>> 24) != 0x1) { 20465 throw new IllegalArgumentException("The key must be a framework-specific " 20466 + "resource id."); 20467 } 20468 20469 setKeyedTag(key, tag); 20470 } 20471 20472 private void setKeyedTag(int key, Object tag) { 20473 if (mKeyedTags == null) { 20474 mKeyedTags = new SparseArray<Object>(2); 20475 } 20476 20477 mKeyedTags.put(key, tag); 20478 } 20479 20480 /** 20481 * Prints information about this view in the log output, with the tag 20482 * {@link #VIEW_LOG_TAG}. 20483 * 20484 * @hide 20485 */ 20486 public void debug() { 20487 debug(0); 20488 } 20489 20490 /** 20491 * Prints information about this view in the log output, with the tag 20492 * {@link #VIEW_LOG_TAG}. Each line in the output is preceded with an 20493 * indentation defined by the <code>depth</code>. 20494 * 20495 * @param depth the indentation level 20496 * 20497 * @hide 20498 */ 20499 protected void debug(int depth) { 20500 String output = debugIndent(depth - 1); 20501 20502 output += "+ " + this; 20503 int id = getId(); 20504 if (id != -1) { 20505 output += " (id=" + id + ")"; 20506 } 20507 Object tag = getTag(); 20508 if (tag != null) { 20509 output += " (tag=" + tag + ")"; 20510 } 20511 Log.d(VIEW_LOG_TAG, output); 20512 20513 if ((mPrivateFlags & PFLAG_FOCUSED) != 0) { 20514 output = debugIndent(depth) + " FOCUSED"; 20515 Log.d(VIEW_LOG_TAG, output); 20516 } 20517 20518 output = debugIndent(depth); 20519 output += "frame={" + mLeft + ", " + mTop + ", " + mRight 20520 + ", " + mBottom + "} scroll={" + mScrollX + ", " + mScrollY 20521 + "} "; 20522 Log.d(VIEW_LOG_TAG, output); 20523 20524 if (mPaddingLeft != 0 || mPaddingTop != 0 || mPaddingRight != 0 20525 || mPaddingBottom != 0) { 20526 output = debugIndent(depth); 20527 output += "padding={" + mPaddingLeft + ", " + mPaddingTop 20528 + ", " + mPaddingRight + ", " + mPaddingBottom + "}"; 20529 Log.d(VIEW_LOG_TAG, output); 20530 } 20531 20532 output = debugIndent(depth); 20533 output += "mMeasureWidth=" + mMeasuredWidth + 20534 " mMeasureHeight=" + mMeasuredHeight; 20535 Log.d(VIEW_LOG_TAG, output); 20536 20537 output = debugIndent(depth); 20538 if (mLayoutParams == null) { 20539 output += "BAD! no layout params"; 20540 } else { 20541 output = mLayoutParams.debug(output); 20542 } 20543 Log.d(VIEW_LOG_TAG, output); 20544 20545 output = debugIndent(depth); 20546 output += "flags={"; 20547 output += View.printFlags(mViewFlags); 20548 output += "}"; 20549 Log.d(VIEW_LOG_TAG, output); 20550 20551 output = debugIndent(depth); 20552 output += "privateFlags={"; 20553 output += View.printPrivateFlags(mPrivateFlags); 20554 output += "}"; 20555 Log.d(VIEW_LOG_TAG, output); 20556 } 20557 20558 /** 20559 * Creates a string of whitespaces used for indentation. 20560 * 20561 * @param depth the indentation level 20562 * @return a String containing (depth * 2 + 3) * 2 white spaces 20563 * 20564 * @hide 20565 */ 20566 protected static String debugIndent(int depth) { 20567 StringBuilder spaces = new StringBuilder((depth * 2 + 3) * 2); 20568 for (int i = 0; i < (depth * 2) + 3; i++) { 20569 spaces.append(' ').append(' '); 20570 } 20571 return spaces.toString(); 20572 } 20573 20574 /** 20575 * <p>Return the offset of the widget's text baseline from the widget's top 20576 * boundary. If this widget does not support baseline alignment, this 20577 * method returns -1. </p> 20578 * 20579 * @return the offset of the baseline within the widget's bounds or -1 20580 * if baseline alignment is not supported 20581 */ 20582 @ViewDebug.ExportedProperty(category = "layout") 20583 public int getBaseline() { 20584 return -1; 20585 } 20586 20587 /** 20588 * Returns whether the view hierarchy is currently undergoing a layout pass. This 20589 * information is useful to avoid situations such as calling {@link #requestLayout()} during 20590 * a layout pass. 20591 * 20592 * @return whether the view hierarchy is currently undergoing a layout pass 20593 */ 20594 public boolean isInLayout() { 20595 ViewRootImpl viewRoot = getViewRootImpl(); 20596 return (viewRoot != null && viewRoot.isInLayout()); 20597 } 20598 20599 /** 20600 * Call this when something has changed which has invalidated the 20601 * layout of this view. This will schedule a layout pass of the view 20602 * tree. This should not be called while the view hierarchy is currently in a layout 20603 * pass ({@link #isInLayout()}. If layout is happening, the request may be honored at the 20604 * end of the current layout pass (and then layout will run again) or after the current 20605 * frame is drawn and the next layout occurs. 20606 * 20607 * <p>Subclasses which override this method should call the superclass method to 20608 * handle possible request-during-layout errors correctly.</p> 20609 */ 20610 @CallSuper 20611 public void requestLayout() { 20612 if (mMeasureCache != null) mMeasureCache.clear(); 20613 20614 if (mAttachInfo != null && mAttachInfo.mViewRequestingLayout == null) { 20615 // Only trigger request-during-layout logic if this is the view requesting it, 20616 // not the views in its parent hierarchy 20617 ViewRootImpl viewRoot = getViewRootImpl(); 20618 if (viewRoot != null && viewRoot.isInLayout()) { 20619 if (!viewRoot.requestLayoutDuringLayout(this)) { 20620 return; 20621 } 20622 } 20623 mAttachInfo.mViewRequestingLayout = this; 20624 } 20625 20626 mPrivateFlags |= PFLAG_FORCE_LAYOUT; 20627 mPrivateFlags |= PFLAG_INVALIDATED; 20628 20629 if (mParent != null && !mParent.isLayoutRequested()) { 20630 mParent.requestLayout(); 20631 } 20632 if (mAttachInfo != null && mAttachInfo.mViewRequestingLayout == this) { 20633 mAttachInfo.mViewRequestingLayout = null; 20634 } 20635 } 20636 20637 /** 20638 * Forces this view to be laid out during the next layout pass. 20639 * This method does not call requestLayout() or forceLayout() 20640 * on the parent. 20641 */ 20642 public void forceLayout() { 20643 if (mMeasureCache != null) mMeasureCache.clear(); 20644 20645 mPrivateFlags |= PFLAG_FORCE_LAYOUT; 20646 mPrivateFlags |= PFLAG_INVALIDATED; 20647 } 20648 20649 /** 20650 * <p> 20651 * This is called to find out how big a view should be. The parent 20652 * supplies constraint information in the width and height parameters. 20653 * </p> 20654 * 20655 * <p> 20656 * The actual measurement work of a view is performed in 20657 * {@link #onMeasure(int, int)}, called by this method. Therefore, only 20658 * {@link #onMeasure(int, int)} can and must be overridden by subclasses. 20659 * </p> 20660 * 20661 * 20662 * @param widthMeasureSpec Horizontal space requirements as imposed by the 20663 * parent 20664 * @param heightMeasureSpec Vertical space requirements as imposed by the 20665 * parent 20666 * 20667 * @see #onMeasure(int, int) 20668 */ 20669 public final void measure(int widthMeasureSpec, int heightMeasureSpec) { 20670 boolean optical = isLayoutModeOptical(this); 20671 if (optical != isLayoutModeOptical(mParent)) { 20672 Insets insets = getOpticalInsets(); 20673 int oWidth = insets.left + insets.right; 20674 int oHeight = insets.top + insets.bottom; 20675 widthMeasureSpec = MeasureSpec.adjust(widthMeasureSpec, optical ? -oWidth : oWidth); 20676 heightMeasureSpec = MeasureSpec.adjust(heightMeasureSpec, optical ? -oHeight : oHeight); 20677 } 20678 20679 // Suppress sign extension for the low bytes 20680 long key = (long) widthMeasureSpec << 32 | (long) heightMeasureSpec & 0xffffffffL; 20681 if (mMeasureCache == null) mMeasureCache = new LongSparseLongArray(2); 20682 20683 final boolean forceLayout = (mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT; 20684 20685 // Optimize layout by avoiding an extra EXACTLY pass when the view is 20686 // already measured as the correct size. In API 23 and below, this 20687 // extra pass is required to make LinearLayout re-distribute weight. 20688 final boolean specChanged = widthMeasureSpec != mOldWidthMeasureSpec 20689 || heightMeasureSpec != mOldHeightMeasureSpec; 20690 final boolean isSpecExactly = MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY 20691 && MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.EXACTLY; 20692 final boolean matchesSpecSize = getMeasuredWidth() == MeasureSpec.getSize(widthMeasureSpec) 20693 && getMeasuredHeight() == MeasureSpec.getSize(heightMeasureSpec); 20694 final boolean needsLayout = specChanged 20695 && (sAlwaysRemeasureExactly || !isSpecExactly || !matchesSpecSize); 20696 20697 if (forceLayout || needsLayout) { 20698 // first clears the measured dimension flag 20699 mPrivateFlags &= ~PFLAG_MEASURED_DIMENSION_SET; 20700 20701 resolveRtlPropertiesIfNeeded(); 20702 20703 int cacheIndex = forceLayout ? -1 : mMeasureCache.indexOfKey(key); 20704 if (cacheIndex < 0 || sIgnoreMeasureCache) { 20705 // measure ourselves, this should set the measured dimension flag back 20706 onMeasure(widthMeasureSpec, heightMeasureSpec); 20707 mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT; 20708 } else { 20709 long value = mMeasureCache.valueAt(cacheIndex); 20710 // Casting a long to int drops the high 32 bits, no mask needed 20711 setMeasuredDimensionRaw((int) (value >> 32), (int) value); 20712 mPrivateFlags3 |= PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT; 20713 } 20714 20715 // flag not set, setMeasuredDimension() was not invoked, we raise 20716 // an exception to warn the developer 20717 if ((mPrivateFlags & PFLAG_MEASURED_DIMENSION_SET) != PFLAG_MEASURED_DIMENSION_SET) { 20718 throw new IllegalStateException("View with id " + getId() + ": " 20719 + getClass().getName() + "#onMeasure() did not set the" 20720 + " measured dimension by calling" 20721 + " setMeasuredDimension()"); 20722 } 20723 20724 mPrivateFlags |= PFLAG_LAYOUT_REQUIRED; 20725 } 20726 20727 mOldWidthMeasureSpec = widthMeasureSpec; 20728 mOldHeightMeasureSpec = heightMeasureSpec; 20729 20730 mMeasureCache.put(key, ((long) mMeasuredWidth) << 32 | 20731 (long) mMeasuredHeight & 0xffffffffL); // suppress sign extension 20732 } 20733 20734 /** 20735 * <p> 20736 * Measure the view and its content to determine the measured width and the 20737 * measured height. This method is invoked by {@link #measure(int, int)} and 20738 * should be overridden by subclasses to provide accurate and efficient 20739 * measurement of their contents. 20740 * </p> 20741 * 20742 * <p> 20743 * <strong>CONTRACT:</strong> When overriding this method, you 20744 * <em>must</em> call {@link #setMeasuredDimension(int, int)} to store the 20745 * measured width and height of this view. Failure to do so will trigger an 20746 * <code>IllegalStateException</code>, thrown by 20747 * {@link #measure(int, int)}. Calling the superclass' 20748 * {@link #onMeasure(int, int)} is a valid use. 20749 * </p> 20750 * 20751 * <p> 20752 * The base class implementation of measure defaults to the background size, 20753 * unless a larger size is allowed by the MeasureSpec. Subclasses should 20754 * override {@link #onMeasure(int, int)} to provide better measurements of 20755 * their content. 20756 * </p> 20757 * 20758 * <p> 20759 * If this method is overridden, it is the subclass's responsibility to make 20760 * sure the measured height and width are at least the view's minimum height 20761 * and width ({@link #getSuggestedMinimumHeight()} and 20762 * {@link #getSuggestedMinimumWidth()}). 20763 * </p> 20764 * 20765 * @param widthMeasureSpec horizontal space requirements as imposed by the parent. 20766 * The requirements are encoded with 20767 * {@link android.view.View.MeasureSpec}. 20768 * @param heightMeasureSpec vertical space requirements as imposed by the parent. 20769 * The requirements are encoded with 20770 * {@link android.view.View.MeasureSpec}. 20771 * 20772 * @see #getMeasuredWidth() 20773 * @see #getMeasuredHeight() 20774 * @see #setMeasuredDimension(int, int) 20775 * @see #getSuggestedMinimumHeight() 20776 * @see #getSuggestedMinimumWidth() 20777 * @see android.view.View.MeasureSpec#getMode(int) 20778 * @see android.view.View.MeasureSpec#getSize(int) 20779 */ 20780 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 20781 setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec), 20782 getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec)); 20783 } 20784 20785 /** 20786 * <p>This method must be called by {@link #onMeasure(int, int)} to store the 20787 * measured width and measured height. Failing to do so will trigger an 20788 * exception at measurement time.</p> 20789 * 20790 * @param measuredWidth The measured width of this view. May be a complex 20791 * bit mask as defined by {@link #MEASURED_SIZE_MASK} and 20792 * {@link #MEASURED_STATE_TOO_SMALL}. 20793 * @param measuredHeight The measured height of this view. May be a complex 20794 * bit mask as defined by {@link #MEASURED_SIZE_MASK} and 20795 * {@link #MEASURED_STATE_TOO_SMALL}. 20796 */ 20797 protected final void setMeasuredDimension(int measuredWidth, int measuredHeight) { 20798 boolean optical = isLayoutModeOptical(this); 20799 if (optical != isLayoutModeOptical(mParent)) { 20800 Insets insets = getOpticalInsets(); 20801 int opticalWidth = insets.left + insets.right; 20802 int opticalHeight = insets.top + insets.bottom; 20803 20804 measuredWidth += optical ? opticalWidth : -opticalWidth; 20805 measuredHeight += optical ? opticalHeight : -opticalHeight; 20806 } 20807 setMeasuredDimensionRaw(measuredWidth, measuredHeight); 20808 } 20809 20810 /** 20811 * Sets the measured dimension without extra processing for things like optical bounds. 20812 * Useful for reapplying consistent values that have already been cooked with adjustments 20813 * for optical bounds, etc. such as those from the measurement cache. 20814 * 20815 * @param measuredWidth The measured width of this view. May be a complex 20816 * bit mask as defined by {@link #MEASURED_SIZE_MASK} and 20817 * {@link #MEASURED_STATE_TOO_SMALL}. 20818 * @param measuredHeight The measured height of this view. May be a complex 20819 * bit mask as defined by {@link #MEASURED_SIZE_MASK} and 20820 * {@link #MEASURED_STATE_TOO_SMALL}. 20821 */ 20822 private void setMeasuredDimensionRaw(int measuredWidth, int measuredHeight) { 20823 mMeasuredWidth = measuredWidth; 20824 mMeasuredHeight = measuredHeight; 20825 20826 mPrivateFlags |= PFLAG_MEASURED_DIMENSION_SET; 20827 } 20828 20829 /** 20830 * Merge two states as returned by {@link #getMeasuredState()}. 20831 * @param curState The current state as returned from a view or the result 20832 * of combining multiple views. 20833 * @param newState The new view state to combine. 20834 * @return Returns a new integer reflecting the combination of the two 20835 * states. 20836 */ 20837 public static int combineMeasuredStates(int curState, int newState) { 20838 return curState | newState; 20839 } 20840 20841 /** 20842 * Version of {@link #resolveSizeAndState(int, int, int)} 20843 * returning only the {@link #MEASURED_SIZE_MASK} bits of the result. 20844 */ 20845 public static int resolveSize(int size, int measureSpec) { 20846 return resolveSizeAndState(size, measureSpec, 0) & MEASURED_SIZE_MASK; 20847 } 20848 20849 /** 20850 * Utility to reconcile a desired size and state, with constraints imposed 20851 * by a MeasureSpec. Will take the desired size, unless a different size 20852 * is imposed by the constraints. The returned value is a compound integer, 20853 * with the resolved size in the {@link #MEASURED_SIZE_MASK} bits and 20854 * optionally the bit {@link #MEASURED_STATE_TOO_SMALL} set if the 20855 * resulting size is smaller than the size the view wants to be. 20856 * 20857 * @param size How big the view wants to be. 20858 * @param measureSpec Constraints imposed by the parent. 20859 * @param childMeasuredState Size information bit mask for the view's 20860 * children. 20861 * @return Size information bit mask as defined by 20862 * {@link #MEASURED_SIZE_MASK} and 20863 * {@link #MEASURED_STATE_TOO_SMALL}. 20864 */ 20865 public static int resolveSizeAndState(int size, int measureSpec, int childMeasuredState) { 20866 final int specMode = MeasureSpec.getMode(measureSpec); 20867 final int specSize = MeasureSpec.getSize(measureSpec); 20868 final int result; 20869 switch (specMode) { 20870 case MeasureSpec.AT_MOST: 20871 if (specSize < size) { 20872 result = specSize | MEASURED_STATE_TOO_SMALL; 20873 } else { 20874 result = size; 20875 } 20876 break; 20877 case MeasureSpec.EXACTLY: 20878 result = specSize; 20879 break; 20880 case MeasureSpec.UNSPECIFIED: 20881 default: 20882 result = size; 20883 } 20884 return result | (childMeasuredState & MEASURED_STATE_MASK); 20885 } 20886 20887 /** 20888 * Utility to return a default size. Uses the supplied size if the 20889 * MeasureSpec imposed no constraints. Will get larger if allowed 20890 * by the MeasureSpec. 20891 * 20892 * @param size Default size for this view 20893 * @param measureSpec Constraints imposed by the parent 20894 * @return The size this view should be. 20895 */ 20896 public static int getDefaultSize(int size, int measureSpec) { 20897 int result = size; 20898 int specMode = MeasureSpec.getMode(measureSpec); 20899 int specSize = MeasureSpec.getSize(measureSpec); 20900 20901 switch (specMode) { 20902 case MeasureSpec.UNSPECIFIED: 20903 result = size; 20904 break; 20905 case MeasureSpec.AT_MOST: 20906 case MeasureSpec.EXACTLY: 20907 result = specSize; 20908 break; 20909 } 20910 return result; 20911 } 20912 20913 /** 20914 * Returns the suggested minimum height that the view should use. This 20915 * returns the maximum of the view's minimum height 20916 * and the background's minimum height 20917 * ({@link android.graphics.drawable.Drawable#getMinimumHeight()}). 20918 * <p> 20919 * When being used in {@link #onMeasure(int, int)}, the caller should still 20920 * ensure the returned height is within the requirements of the parent. 20921 * 20922 * @return The suggested minimum height of the view. 20923 */ 20924 protected int getSuggestedMinimumHeight() { 20925 return (mBackground == null) ? mMinHeight : max(mMinHeight, mBackground.getMinimumHeight()); 20926 20927 } 20928 20929 /** 20930 * Returns the suggested minimum width that the view should use. This 20931 * returns the maximum of the view's minimum width 20932 * and the background's minimum width 20933 * ({@link android.graphics.drawable.Drawable#getMinimumWidth()}). 20934 * <p> 20935 * When being used in {@link #onMeasure(int, int)}, the caller should still 20936 * ensure the returned width is within the requirements of the parent. 20937 * 20938 * @return The suggested minimum width of the view. 20939 */ 20940 protected int getSuggestedMinimumWidth() { 20941 return (mBackground == null) ? mMinWidth : max(mMinWidth, mBackground.getMinimumWidth()); 20942 } 20943 20944 /** 20945 * Returns the minimum height of the view. 20946 * 20947 * @return the minimum height the view will try to be, in pixels 20948 * 20949 * @see #setMinimumHeight(int) 20950 * 20951 * @attr ref android.R.styleable#View_minHeight 20952 */ 20953 public int getMinimumHeight() { 20954 return mMinHeight; 20955 } 20956 20957 /** 20958 * Sets the minimum height of the view. It is not guaranteed the view will 20959 * be able to achieve this minimum height (for example, if its parent layout 20960 * constrains it with less available height). 20961 * 20962 * @param minHeight The minimum height the view will try to be, in pixels 20963 * 20964 * @see #getMinimumHeight() 20965 * 20966 * @attr ref android.R.styleable#View_minHeight 20967 */ 20968 @RemotableViewMethod 20969 public void setMinimumHeight(int minHeight) { 20970 mMinHeight = minHeight; 20971 requestLayout(); 20972 } 20973 20974 /** 20975 * Returns the minimum width of the view. 20976 * 20977 * @return the minimum width the view will try to be, in pixels 20978 * 20979 * @see #setMinimumWidth(int) 20980 * 20981 * @attr ref android.R.styleable#View_minWidth 20982 */ 20983 public int getMinimumWidth() { 20984 return mMinWidth; 20985 } 20986 20987 /** 20988 * Sets the minimum width of the view. It is not guaranteed the view will 20989 * be able to achieve this minimum width (for example, if its parent layout 20990 * constrains it with less available width). 20991 * 20992 * @param minWidth The minimum width the view will try to be, in pixels 20993 * 20994 * @see #getMinimumWidth() 20995 * 20996 * @attr ref android.R.styleable#View_minWidth 20997 */ 20998 public void setMinimumWidth(int minWidth) { 20999 mMinWidth = minWidth; 21000 requestLayout(); 21001 21002 } 21003 21004 /** 21005 * Get the animation currently associated with this view. 21006 * 21007 * @return The animation that is currently playing or 21008 * scheduled to play for this view. 21009 */ 21010 public Animation getAnimation() { 21011 return mCurrentAnimation; 21012 } 21013 21014 /** 21015 * Start the specified animation now. 21016 * 21017 * @param animation the animation to start now 21018 */ 21019 public void startAnimation(Animation animation) { 21020 animation.setStartTime(Animation.START_ON_FIRST_FRAME); 21021 setAnimation(animation); 21022 invalidateParentCaches(); 21023 invalidate(true); 21024 } 21025 21026 /** 21027 * Cancels any animations for this view. 21028 */ 21029 public void clearAnimation() { 21030 if (mCurrentAnimation != null) { 21031 mCurrentAnimation.detach(); 21032 } 21033 mCurrentAnimation = null; 21034 invalidateParentIfNeeded(); 21035 } 21036 21037 /** 21038 * Sets the next animation to play for this view. 21039 * If you want the animation to play immediately, use 21040 * {@link #startAnimation(android.view.animation.Animation)} instead. 21041 * This method provides allows fine-grained 21042 * control over the start time and invalidation, but you 21043 * must make sure that 1) the animation has a start time set, and 21044 * 2) the view's parent (which controls animations on its children) 21045 * will be invalidated when the animation is supposed to 21046 * start. 21047 * 21048 * @param animation The next animation, or null. 21049 */ 21050 public void setAnimation(Animation animation) { 21051 mCurrentAnimation = animation; 21052 21053 if (animation != null) { 21054 // If the screen is off assume the animation start time is now instead of 21055 // the next frame we draw. Keeping the START_ON_FIRST_FRAME start time 21056 // would cause the animation to start when the screen turns back on 21057 if (mAttachInfo != null && mAttachInfo.mDisplayState == Display.STATE_OFF 21058 && animation.getStartTime() == Animation.START_ON_FIRST_FRAME) { 21059 animation.setStartTime(AnimationUtils.currentAnimationTimeMillis()); 21060 } 21061 animation.reset(); 21062 } 21063 } 21064 21065 /** 21066 * Invoked by a parent ViewGroup to notify the start of the animation 21067 * currently associated with this view. If you override this method, 21068 * always call super.onAnimationStart(); 21069 * 21070 * @see #setAnimation(android.view.animation.Animation) 21071 * @see #getAnimation() 21072 */ 21073 @CallSuper 21074 protected void onAnimationStart() { 21075 mPrivateFlags |= PFLAG_ANIMATION_STARTED; 21076 } 21077 21078 /** 21079 * Invoked by a parent ViewGroup to notify the end of the animation 21080 * currently associated with this view. If you override this method, 21081 * always call super.onAnimationEnd(); 21082 * 21083 * @see #setAnimation(android.view.animation.Animation) 21084 * @see #getAnimation() 21085 */ 21086 @CallSuper 21087 protected void onAnimationEnd() { 21088 mPrivateFlags &= ~PFLAG_ANIMATION_STARTED; 21089 } 21090 21091 /** 21092 * Invoked if there is a Transform that involves alpha. Subclass that can 21093 * draw themselves with the specified alpha should return true, and then 21094 * respect that alpha when their onDraw() is called. If this returns false 21095 * then the view may be redirected to draw into an offscreen buffer to 21096 * fulfill the request, which will look fine, but may be slower than if the 21097 * subclass handles it internally. The default implementation returns false. 21098 * 21099 * @param alpha The alpha (0..255) to apply to the view's drawing 21100 * @return true if the view can draw with the specified alpha. 21101 */ 21102 protected boolean onSetAlpha(int alpha) { 21103 return false; 21104 } 21105 21106 /** 21107 * This is used by the RootView to perform an optimization when 21108 * the view hierarchy contains one or several SurfaceView. 21109 * SurfaceView is always considered transparent, but its children are not, 21110 * therefore all View objects remove themselves from the global transparent 21111 * region (passed as a parameter to this function). 21112 * 21113 * @param region The transparent region for this ViewAncestor (window). 21114 * 21115 * @return Returns true if the effective visibility of the view at this 21116 * point is opaque, regardless of the transparent region; returns false 21117 * if it is possible for underlying windows to be seen behind the view. 21118 * 21119 * {@hide} 21120 */ 21121 public boolean gatherTransparentRegion(Region region) { 21122 final AttachInfo attachInfo = mAttachInfo; 21123 if (region != null && attachInfo != null) { 21124 final int pflags = mPrivateFlags; 21125 if ((pflags & PFLAG_SKIP_DRAW) == 0) { 21126 // The SKIP_DRAW flag IS NOT set, so this view draws. We need to 21127 // remove it from the transparent region. 21128 final int[] location = attachInfo.mTransparentLocation; 21129 getLocationInWindow(location); 21130 // When a view has Z value, then it will be better to leave some area below the view 21131 // for drawing shadow. The shadow outset is proportional to the Z value. Note that 21132 // the bottom part needs more offset than the left, top and right parts due to the 21133 // spot light effects. 21134 int shadowOffset = getZ() > 0 ? (int) getZ() : 0; 21135 region.op(location[0] - shadowOffset, location[1] - shadowOffset, 21136 location[0] + mRight - mLeft + shadowOffset, 21137 location[1] + mBottom - mTop + (shadowOffset * 3), Region.Op.DIFFERENCE); 21138 } else { 21139 if (mBackground != null && mBackground.getOpacity() != PixelFormat.TRANSPARENT) { 21140 // The SKIP_DRAW flag IS set and the background drawable exists, we remove 21141 // the background drawable's non-transparent parts from this transparent region. 21142 applyDrawableToTransparentRegion(mBackground, region); 21143 } 21144 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null 21145 && mForegroundInfo.mDrawable.getOpacity() != PixelFormat.TRANSPARENT) { 21146 // Similarly, we remove the foreground drawable's non-transparent parts. 21147 applyDrawableToTransparentRegion(mForegroundInfo.mDrawable, region); 21148 } 21149 } 21150 } 21151 return true; 21152 } 21153 21154 /** 21155 * Play a sound effect for this view. 21156 * 21157 * <p>The framework will play sound effects for some built in actions, such as 21158 * clicking, but you may wish to play these effects in your widget, 21159 * for instance, for internal navigation. 21160 * 21161 * <p>The sound effect will only be played if sound effects are enabled by the user, and 21162 * {@link #isSoundEffectsEnabled()} is true. 21163 * 21164 * @param soundConstant One of the constants defined in {@link SoundEffectConstants} 21165 */ 21166 public void playSoundEffect(int soundConstant) { 21167 if (mAttachInfo == null || mAttachInfo.mRootCallbacks == null || !isSoundEffectsEnabled()) { 21168 return; 21169 } 21170 mAttachInfo.mRootCallbacks.playSoundEffect(soundConstant); 21171 } 21172 21173 /** 21174 * BZZZTT!!1! 21175 * 21176 * <p>Provide haptic feedback to the user for this view. 21177 * 21178 * <p>The framework will provide haptic feedback for some built in actions, 21179 * such as long presses, but you may wish to provide feedback for your 21180 * own widget. 21181 * 21182 * <p>The feedback will only be performed if 21183 * {@link #isHapticFeedbackEnabled()} is true. 21184 * 21185 * @param feedbackConstant One of the constants defined in 21186 * {@link HapticFeedbackConstants} 21187 */ 21188 public boolean performHapticFeedback(int feedbackConstant) { 21189 return performHapticFeedback(feedbackConstant, 0); 21190 } 21191 21192 /** 21193 * BZZZTT!!1! 21194 * 21195 * <p>Like {@link #performHapticFeedback(int)}, with additional options. 21196 * 21197 * @param feedbackConstant One of the constants defined in 21198 * {@link HapticFeedbackConstants} 21199 * @param flags Additional flags as per {@link HapticFeedbackConstants}. 21200 */ 21201 public boolean performHapticFeedback(int feedbackConstant, int flags) { 21202 if (mAttachInfo == null) { 21203 return false; 21204 } 21205 //noinspection SimplifiableIfStatement 21206 if ((flags & HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING) == 0 21207 && !isHapticFeedbackEnabled()) { 21208 return false; 21209 } 21210 return mAttachInfo.mRootCallbacks.performHapticFeedback(feedbackConstant, 21211 (flags & HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING) != 0); 21212 } 21213 21214 /** 21215 * Request that the visibility of the status bar or other screen/window 21216 * decorations be changed. 21217 * 21218 * <p>This method is used to put the over device UI into temporary modes 21219 * where the user's attention is focused more on the application content, 21220 * by dimming or hiding surrounding system affordances. This is typically 21221 * used in conjunction with {@link Window#FEATURE_ACTION_BAR_OVERLAY 21222 * Window.FEATURE_ACTION_BAR_OVERLAY}, allowing the applications content 21223 * to be placed behind the action bar (and with these flags other system 21224 * affordances) so that smooth transitions between hiding and showing them 21225 * can be done. 21226 * 21227 * <p>Two representative examples of the use of system UI visibility is 21228 * implementing a content browsing application (like a magazine reader) 21229 * and a video playing application. 21230 * 21231 * <p>The first code shows a typical implementation of a View in a content 21232 * browsing application. In this implementation, the application goes 21233 * into a content-oriented mode by hiding the status bar and action bar, 21234 * and putting the navigation elements into lights out mode. The user can 21235 * then interact with content while in this mode. Such an application should 21236 * provide an easy way for the user to toggle out of the mode (such as to 21237 * check information in the status bar or access notifications). In the 21238 * implementation here, this is done simply by tapping on the content. 21239 * 21240 * {@sample development/samples/ApiDemos/src/com/example/android/apis/view/ContentBrowserActivity.java 21241 * content} 21242 * 21243 * <p>This second code sample shows a typical implementation of a View 21244 * in a video playing application. In this situation, while the video is 21245 * playing the application would like to go into a complete full-screen mode, 21246 * to use as much of the display as possible for the video. When in this state 21247 * the user can not interact with the application; the system intercepts 21248 * touching on the screen to pop the UI out of full screen mode. See 21249 * {@link #fitSystemWindows(Rect)} for a sample layout that goes with this code. 21250 * 21251 * {@sample development/samples/ApiDemos/src/com/example/android/apis/view/VideoPlayerActivity.java 21252 * content} 21253 * 21254 * @param visibility Bitwise-or of flags {@link #SYSTEM_UI_FLAG_LOW_PROFILE}, 21255 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, {@link #SYSTEM_UI_FLAG_FULLSCREEN}, 21256 * {@link #SYSTEM_UI_FLAG_LAYOUT_STABLE}, {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION}, 21257 * {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN}, {@link #SYSTEM_UI_FLAG_IMMERSIVE}, 21258 * and {@link #SYSTEM_UI_FLAG_IMMERSIVE_STICKY}. 21259 */ 21260 public void setSystemUiVisibility(int visibility) { 21261 if (visibility != mSystemUiVisibility) { 21262 mSystemUiVisibility = visibility; 21263 if (mParent != null && mAttachInfo != null && !mAttachInfo.mRecomputeGlobalAttributes) { 21264 mParent.recomputeViewAttributes(this); 21265 } 21266 } 21267 } 21268 21269 /** 21270 * Returns the last {@link #setSystemUiVisibility(int)} that this view has requested. 21271 * @return Bitwise-or of flags {@link #SYSTEM_UI_FLAG_LOW_PROFILE}, 21272 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, {@link #SYSTEM_UI_FLAG_FULLSCREEN}, 21273 * {@link #SYSTEM_UI_FLAG_LAYOUT_STABLE}, {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION}, 21274 * {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN}, {@link #SYSTEM_UI_FLAG_IMMERSIVE}, 21275 * and {@link #SYSTEM_UI_FLAG_IMMERSIVE_STICKY}. 21276 */ 21277 public int getSystemUiVisibility() { 21278 return mSystemUiVisibility; 21279 } 21280 21281 /** 21282 * Returns the current system UI visibility that is currently set for 21283 * the entire window. This is the combination of the 21284 * {@link #setSystemUiVisibility(int)} values supplied by all of the 21285 * views in the window. 21286 */ 21287 public int getWindowSystemUiVisibility() { 21288 return mAttachInfo != null ? mAttachInfo.mSystemUiVisibility : 0; 21289 } 21290 21291 /** 21292 * Override to find out when the window's requested system UI visibility 21293 * has changed, that is the value returned by {@link #getWindowSystemUiVisibility()}. 21294 * This is different from the callbacks received through 21295 * {@link #setOnSystemUiVisibilityChangeListener(OnSystemUiVisibilityChangeListener)} 21296 * in that this is only telling you about the local request of the window, 21297 * not the actual values applied by the system. 21298 */ 21299 public void onWindowSystemUiVisibilityChanged(int visible) { 21300 } 21301 21302 /** 21303 * Dispatch callbacks to {@link #onWindowSystemUiVisibilityChanged(int)} down 21304 * the view hierarchy. 21305 */ 21306 public void dispatchWindowSystemUiVisiblityChanged(int visible) { 21307 onWindowSystemUiVisibilityChanged(visible); 21308 } 21309 21310 /** 21311 * Set a listener to receive callbacks when the visibility of the system bar changes. 21312 * @param l The {@link OnSystemUiVisibilityChangeListener} to receive callbacks. 21313 */ 21314 public void setOnSystemUiVisibilityChangeListener(OnSystemUiVisibilityChangeListener l) { 21315 getListenerInfo().mOnSystemUiVisibilityChangeListener = l; 21316 if (mParent != null && mAttachInfo != null && !mAttachInfo.mRecomputeGlobalAttributes) { 21317 mParent.recomputeViewAttributes(this); 21318 } 21319 } 21320 21321 /** 21322 * Dispatch callbacks to {@link #setOnSystemUiVisibilityChangeListener} down 21323 * the view hierarchy. 21324 */ 21325 public void dispatchSystemUiVisibilityChanged(int visibility) { 21326 ListenerInfo li = mListenerInfo; 21327 if (li != null && li.mOnSystemUiVisibilityChangeListener != null) { 21328 li.mOnSystemUiVisibilityChangeListener.onSystemUiVisibilityChange( 21329 visibility & PUBLIC_STATUS_BAR_VISIBILITY_MASK); 21330 } 21331 } 21332 21333 boolean updateLocalSystemUiVisibility(int localValue, int localChanges) { 21334 int val = (mSystemUiVisibility&~localChanges) | (localValue&localChanges); 21335 if (val != mSystemUiVisibility) { 21336 setSystemUiVisibility(val); 21337 return true; 21338 } 21339 return false; 21340 } 21341 21342 /** @hide */ 21343 public void setDisabledSystemUiVisibility(int flags) { 21344 if (mAttachInfo != null) { 21345 if (mAttachInfo.mDisabledSystemUiVisibility != flags) { 21346 mAttachInfo.mDisabledSystemUiVisibility = flags; 21347 if (mParent != null) { 21348 mParent.recomputeViewAttributes(this); 21349 } 21350 } 21351 } 21352 } 21353 21354 /** 21355 * Creates an image that the system displays during the drag and drop 21356 * operation. This is called a "drag shadow". The default implementation 21357 * for a DragShadowBuilder based on a View returns an image that has exactly the same 21358 * appearance as the given View. The default also positions the center of the drag shadow 21359 * directly under the touch point. If no View is provided (the constructor with no parameters 21360 * is used), and {@link #onProvideShadowMetrics(Point,Point) onProvideShadowMetrics()} and 21361 * {@link #onDrawShadow(Canvas) onDrawShadow()} are not overridden, then the 21362 * default is an invisible drag shadow. 21363 * <p> 21364 * You are not required to use the View you provide to the constructor as the basis of the 21365 * drag shadow. The {@link #onDrawShadow(Canvas) onDrawShadow()} method allows you to draw 21366 * anything you want as the drag shadow. 21367 * </p> 21368 * <p> 21369 * You pass a DragShadowBuilder object to the system when you start the drag. The system 21370 * calls {@link #onProvideShadowMetrics(Point,Point) onProvideShadowMetrics()} to get the 21371 * size and position of the drag shadow. It uses this data to construct a 21372 * {@link android.graphics.Canvas} object, then it calls {@link #onDrawShadow(Canvas) onDrawShadow()} 21373 * so that your application can draw the shadow image in the Canvas. 21374 * </p> 21375 * 21376 * <div class="special reference"> 21377 * <h3>Developer Guides</h3> 21378 * <p>For a guide to implementing drag and drop features, read the 21379 * <a href="{@docRoot}guide/topics/ui/drag-drop.html">Drag and Drop</a> developer guide.</p> 21380 * </div> 21381 */ 21382 public static class DragShadowBuilder { 21383 private final WeakReference<View> mView; 21384 21385 /** 21386 * Constructs a shadow image builder based on a View. By default, the resulting drag 21387 * shadow will have the same appearance and dimensions as the View, with the touch point 21388 * over the center of the View. 21389 * @param view A View. Any View in scope can be used. 21390 */ 21391 public DragShadowBuilder(View view) { 21392 mView = new WeakReference<View>(view); 21393 } 21394 21395 /** 21396 * Construct a shadow builder object with no associated View. This 21397 * constructor variant is only useful when the {@link #onProvideShadowMetrics(Point, Point)} 21398 * and {@link #onDrawShadow(Canvas)} methods are also overridden in order 21399 * to supply the drag shadow's dimensions and appearance without 21400 * reference to any View object. If they are not overridden, then the result is an 21401 * invisible drag shadow. 21402 */ 21403 public DragShadowBuilder() { 21404 mView = new WeakReference<View>(null); 21405 } 21406 21407 /** 21408 * Returns the View object that had been passed to the 21409 * {@link #View.DragShadowBuilder(View)} 21410 * constructor. If that View parameter was {@code null} or if the 21411 * {@link #View.DragShadowBuilder()} 21412 * constructor was used to instantiate the builder object, this method will return 21413 * null. 21414 * 21415 * @return The View object associate with this builder object. 21416 */ 21417 @SuppressWarnings({"JavadocReference"}) 21418 final public View getView() { 21419 return mView.get(); 21420 } 21421 21422 /** 21423 * Provides the metrics for the shadow image. These include the dimensions of 21424 * the shadow image, and the point within that shadow that should 21425 * be centered under the touch location while dragging. 21426 * <p> 21427 * The default implementation sets the dimensions of the shadow to be the 21428 * same as the dimensions of the View itself and centers the shadow under 21429 * the touch point. 21430 * </p> 21431 * 21432 * @param outShadowSize A {@link android.graphics.Point} containing the width and height 21433 * of the shadow image. Your application must set {@link android.graphics.Point#x} to the 21434 * desired width and must set {@link android.graphics.Point#y} to the desired height of the 21435 * image. 21436 * 21437 * @param outShadowTouchPoint A {@link android.graphics.Point} for the position within the 21438 * shadow image that should be underneath the touch point during the drag and drop 21439 * operation. Your application must set {@link android.graphics.Point#x} to the 21440 * X coordinate and {@link android.graphics.Point#y} to the Y coordinate of this position. 21441 */ 21442 public void onProvideShadowMetrics(Point outShadowSize, Point outShadowTouchPoint) { 21443 final View view = mView.get(); 21444 if (view != null) { 21445 outShadowSize.set(view.getWidth(), view.getHeight()); 21446 outShadowTouchPoint.set(outShadowSize.x / 2, outShadowSize.y / 2); 21447 } else { 21448 Log.e(View.VIEW_LOG_TAG, "Asked for drag thumb metrics but no view"); 21449 } 21450 } 21451 21452 /** 21453 * Draws the shadow image. The system creates the {@link android.graphics.Canvas} object 21454 * based on the dimensions it received from the 21455 * {@link #onProvideShadowMetrics(Point, Point)} callback. 21456 * 21457 * @param canvas A {@link android.graphics.Canvas} object in which to draw the shadow image. 21458 */ 21459 public void onDrawShadow(Canvas canvas) { 21460 final View view = mView.get(); 21461 if (view != null) { 21462 view.draw(canvas); 21463 } else { 21464 Log.e(View.VIEW_LOG_TAG, "Asked to draw drag shadow but no view"); 21465 } 21466 } 21467 } 21468 21469 /** 21470 * @deprecated Use {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, int) 21471 * startDragAndDrop()} for newer platform versions. 21472 */ 21473 @Deprecated 21474 public final boolean startDrag(ClipData data, DragShadowBuilder shadowBuilder, 21475 Object myLocalState, int flags) { 21476 return startDragAndDrop(data, shadowBuilder, myLocalState, flags); 21477 } 21478 21479 /** 21480 * Starts a drag and drop operation. When your application calls this method, it passes a 21481 * {@link android.view.View.DragShadowBuilder} object to the system. The 21482 * system calls this object's {@link DragShadowBuilder#onProvideShadowMetrics(Point, Point)} 21483 * to get metrics for the drag shadow, and then calls the object's 21484 * {@link DragShadowBuilder#onDrawShadow(Canvas)} to draw the drag shadow itself. 21485 * <p> 21486 * Once the system has the drag shadow, it begins the drag and drop operation by sending 21487 * drag events to all the View objects in your application that are currently visible. It does 21488 * this either by calling the View object's drag listener (an implementation of 21489 * {@link android.view.View.OnDragListener#onDrag(View,DragEvent) onDrag()} or by calling the 21490 * View object's {@link android.view.View#onDragEvent(DragEvent) onDragEvent()} method. 21491 * Both are passed a {@link android.view.DragEvent} object that has a 21492 * {@link android.view.DragEvent#getAction()} value of 21493 * {@link android.view.DragEvent#ACTION_DRAG_STARTED}. 21494 * </p> 21495 * <p> 21496 * Your application can invoke {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, 21497 * int) startDragAndDrop()} on any attached View object. The View object does not need to be 21498 * the one used in {@link android.view.View.DragShadowBuilder}, nor does it need to be related 21499 * to the View the user selected for dragging. 21500 * </p> 21501 * @param data A {@link android.content.ClipData} object pointing to the data to be 21502 * transferred by the drag and drop operation. 21503 * @param shadowBuilder A {@link android.view.View.DragShadowBuilder} object for building the 21504 * drag shadow. 21505 * @param myLocalState An {@link java.lang.Object} containing local data about the drag and 21506 * drop operation. When dispatching drag events to views in the same activity this object 21507 * will be available through {@link android.view.DragEvent#getLocalState()}. Views in other 21508 * activities will not have access to this data ({@link android.view.DragEvent#getLocalState()} 21509 * will return null). 21510 * <p> 21511 * myLocalState is a lightweight mechanism for the sending information from the dragged View 21512 * to the target Views. For example, it can contain flags that differentiate between a 21513 * a copy operation and a move operation. 21514 * </p> 21515 * @param flags Flags that control the drag and drop operation. This can be set to 0 for no 21516 * flags, or any combination of the following: 21517 * <ul> 21518 * <li>{@link #DRAG_FLAG_GLOBAL}</li> 21519 * <li>{@link #DRAG_FLAG_GLOBAL_PERSISTABLE_URI_PERMISSION}</li> 21520 * <li>{@link #DRAG_FLAG_GLOBAL_PREFIX_URI_PERMISSION}</li> 21521 * <li>{@link #DRAG_FLAG_GLOBAL_URI_READ}</li> 21522 * <li>{@link #DRAG_FLAG_GLOBAL_URI_WRITE}</li> 21523 * <li>{@link #DRAG_FLAG_OPAQUE}</li> 21524 * </ul> 21525 * @return {@code true} if the method completes successfully, or 21526 * {@code false} if it fails anywhere. Returning {@code false} means the system was unable to 21527 * do a drag, and so no drag operation is in progress. 21528 */ 21529 public final boolean startDragAndDrop(ClipData data, DragShadowBuilder shadowBuilder, 21530 Object myLocalState, int flags) { 21531 if (ViewDebug.DEBUG_DRAG) { 21532 Log.d(VIEW_LOG_TAG, "startDragAndDrop: data=" + data + " flags=" + flags); 21533 } 21534 if (mAttachInfo == null) { 21535 Log.w(VIEW_LOG_TAG, "startDragAndDrop called on a detached view."); 21536 return false; 21537 } 21538 21539 if (data != null) { 21540 data.prepareToLeaveProcess((flags & View.DRAG_FLAG_GLOBAL) != 0); 21541 } 21542 21543 boolean okay = false; 21544 21545 Point shadowSize = new Point(); 21546 Point shadowTouchPoint = new Point(); 21547 shadowBuilder.onProvideShadowMetrics(shadowSize, shadowTouchPoint); 21548 21549 if ((shadowSize.x < 0) || (shadowSize.y < 0) || 21550 (shadowTouchPoint.x < 0) || (shadowTouchPoint.y < 0)) { 21551 throw new IllegalStateException("Drag shadow dimensions must not be negative"); 21552 } 21553 21554 if (ViewDebug.DEBUG_DRAG) { 21555 Log.d(VIEW_LOG_TAG, "drag shadow: width=" + shadowSize.x + " height=" + shadowSize.y 21556 + " shadowX=" + shadowTouchPoint.x + " shadowY=" + shadowTouchPoint.y); 21557 } 21558 if (mAttachInfo.mDragSurface != null) { 21559 mAttachInfo.mDragSurface.release(); 21560 } 21561 mAttachInfo.mDragSurface = new Surface(); 21562 try { 21563 mAttachInfo.mDragToken = mAttachInfo.mSession.prepareDrag(mAttachInfo.mWindow, 21564 flags, shadowSize.x, shadowSize.y, mAttachInfo.mDragSurface); 21565 if (ViewDebug.DEBUG_DRAG) Log.d(VIEW_LOG_TAG, "prepareDrag returned token=" 21566 + mAttachInfo.mDragToken + " surface=" + mAttachInfo.mDragSurface); 21567 if (mAttachInfo.mDragToken != null) { 21568 Canvas canvas = mAttachInfo.mDragSurface.lockCanvas(null); 21569 try { 21570 canvas.drawColor(0, PorterDuff.Mode.CLEAR); 21571 shadowBuilder.onDrawShadow(canvas); 21572 } finally { 21573 mAttachInfo.mDragSurface.unlockCanvasAndPost(canvas); 21574 } 21575 21576 final ViewRootImpl root = getViewRootImpl(); 21577 21578 // Cache the local state object for delivery with DragEvents 21579 root.setLocalDragState(myLocalState); 21580 21581 // repurpose 'shadowSize' for the last touch point 21582 root.getLastTouchPoint(shadowSize); 21583 21584 okay = mAttachInfo.mSession.performDrag(mAttachInfo.mWindow, mAttachInfo.mDragToken, 21585 root.getLastTouchSource(), shadowSize.x, shadowSize.y, 21586 shadowTouchPoint.x, shadowTouchPoint.y, data); 21587 if (ViewDebug.DEBUG_DRAG) Log.d(VIEW_LOG_TAG, "performDrag returned " + okay); 21588 } 21589 } catch (Exception e) { 21590 Log.e(VIEW_LOG_TAG, "Unable to initiate drag", e); 21591 mAttachInfo.mDragSurface.destroy(); 21592 mAttachInfo.mDragSurface = null; 21593 } 21594 21595 return okay; 21596 } 21597 21598 /** 21599 * Cancels an ongoing drag and drop operation. 21600 * <p> 21601 * A {@link android.view.DragEvent} object with 21602 * {@link android.view.DragEvent#getAction()} value of 21603 * {@link android.view.DragEvent#ACTION_DRAG_ENDED} and 21604 * {@link android.view.DragEvent#getResult()} value of {@code false} 21605 * will be sent to every 21606 * View that received {@link android.view.DragEvent#ACTION_DRAG_STARTED} 21607 * even if they are not currently visible. 21608 * </p> 21609 * <p> 21610 * This method can be called on any View in the same window as the View on which 21611 * {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, int) startDragAndDrop} 21612 * was called. 21613 * </p> 21614 */ 21615 public final void cancelDragAndDrop() { 21616 if (ViewDebug.DEBUG_DRAG) { 21617 Log.d(VIEW_LOG_TAG, "cancelDragAndDrop"); 21618 } 21619 if (mAttachInfo == null) { 21620 Log.w(VIEW_LOG_TAG, "cancelDragAndDrop called on a detached view."); 21621 return; 21622 } 21623 if (mAttachInfo.mDragToken != null) { 21624 try { 21625 mAttachInfo.mSession.cancelDragAndDrop(mAttachInfo.mDragToken); 21626 } catch (Exception e) { 21627 Log.e(VIEW_LOG_TAG, "Unable to cancel drag", e); 21628 } 21629 mAttachInfo.mDragToken = null; 21630 } else { 21631 Log.e(VIEW_LOG_TAG, "No active drag to cancel"); 21632 } 21633 } 21634 21635 /** 21636 * Updates the drag shadow for the ongoing drag and drop operation. 21637 * 21638 * @param shadowBuilder A {@link android.view.View.DragShadowBuilder} object for building the 21639 * new drag shadow. 21640 */ 21641 public final void updateDragShadow(DragShadowBuilder shadowBuilder) { 21642 if (ViewDebug.DEBUG_DRAG) { 21643 Log.d(VIEW_LOG_TAG, "updateDragShadow"); 21644 } 21645 if (mAttachInfo == null) { 21646 Log.w(VIEW_LOG_TAG, "updateDragShadow called on a detached view."); 21647 return; 21648 } 21649 if (mAttachInfo.mDragToken != null) { 21650 try { 21651 Canvas canvas = mAttachInfo.mDragSurface.lockCanvas(null); 21652 try { 21653 canvas.drawColor(0, PorterDuff.Mode.CLEAR); 21654 shadowBuilder.onDrawShadow(canvas); 21655 } finally { 21656 mAttachInfo.mDragSurface.unlockCanvasAndPost(canvas); 21657 } 21658 } catch (Exception e) { 21659 Log.e(VIEW_LOG_TAG, "Unable to update drag shadow", e); 21660 } 21661 } else { 21662 Log.e(VIEW_LOG_TAG, "No active drag"); 21663 } 21664 } 21665 21666 /** 21667 * Starts a move from {startX, startY}, the amount of the movement will be the offset 21668 * between {startX, startY} and the new cursor positon. 21669 * @param startX horizontal coordinate where the move started. 21670 * @param startY vertical coordinate where the move started. 21671 * @return whether moving was started successfully. 21672 * @hide 21673 */ 21674 public final boolean startMovingTask(float startX, float startY) { 21675 if (ViewDebug.DEBUG_POSITIONING) { 21676 Log.d(VIEW_LOG_TAG, "startMovingTask: {" + startX + "," + startY + "}"); 21677 } 21678 try { 21679 return mAttachInfo.mSession.startMovingTask(mAttachInfo.mWindow, startX, startY); 21680 } catch (RemoteException e) { 21681 Log.e(VIEW_LOG_TAG, "Unable to start moving", e); 21682 } 21683 return false; 21684 } 21685 21686 /** 21687 * Handles drag events sent by the system following a call to 21688 * {@link android.view.View#startDragAndDrop(ClipData,DragShadowBuilder,Object,int) 21689 * startDragAndDrop()}. 21690 *<p> 21691 * When the system calls this method, it passes a 21692 * {@link android.view.DragEvent} object. A call to 21693 * {@link android.view.DragEvent#getAction()} returns one of the action type constants defined 21694 * in DragEvent. The method uses these to determine what is happening in the drag and drop 21695 * operation. 21696 * @param event The {@link android.view.DragEvent} sent by the system. 21697 * The {@link android.view.DragEvent#getAction()} method returns an action type constant defined 21698 * in DragEvent, indicating the type of drag event represented by this object. 21699 * @return {@code true} if the method was successful, otherwise {@code false}. 21700 * <p> 21701 * The method should return {@code true} in response to an action type of 21702 * {@link android.view.DragEvent#ACTION_DRAG_STARTED} to receive drag events for the current 21703 * operation. 21704 * </p> 21705 * <p> 21706 * The method should also return {@code true} in response to an action type of 21707 * {@link android.view.DragEvent#ACTION_DROP} if it consumed the drop, or 21708 * {@code false} if it didn't. 21709 * </p> 21710 * <p> 21711 * For all other events, the return value is ignored. 21712 * </p> 21713 */ 21714 public boolean onDragEvent(DragEvent event) { 21715 return false; 21716 } 21717 21718 // Dispatches ACTION_DRAG_ENTERED and ACTION_DRAG_EXITED events for pre-Nougat apps. 21719 boolean dispatchDragEnterExitInPreN(DragEvent event) { 21720 return callDragEventHandler(event); 21721 } 21722 21723 /** 21724 * Detects if this View is enabled and has a drag event listener. 21725 * If both are true, then it calls the drag event listener with the 21726 * {@link android.view.DragEvent} it received. If the drag event listener returns 21727 * {@code true}, then dispatchDragEvent() returns {@code true}. 21728 * <p> 21729 * For all other cases, the method calls the 21730 * {@link android.view.View#onDragEvent(DragEvent) onDragEvent()} drag event handler 21731 * method and returns its result. 21732 * </p> 21733 * <p> 21734 * This ensures that a drag event is always consumed, even if the View does not have a drag 21735 * event listener. However, if the View has a listener and the listener returns true, then 21736 * onDragEvent() is not called. 21737 * </p> 21738 */ 21739 public boolean dispatchDragEvent(DragEvent event) { 21740 event.mEventHandlerWasCalled = true; 21741 if (event.mAction == DragEvent.ACTION_DRAG_LOCATION || 21742 event.mAction == DragEvent.ACTION_DROP) { 21743 // About to deliver an event with coordinates to this view. Notify that now this view 21744 // has drag focus. This will send exit/enter events as needed. 21745 getViewRootImpl().setDragFocus(this, event); 21746 } 21747 return callDragEventHandler(event); 21748 } 21749 21750 final boolean callDragEventHandler(DragEvent event) { 21751 final boolean result; 21752 21753 ListenerInfo li = mListenerInfo; 21754 //noinspection SimplifiableIfStatement 21755 if (li != null && li.mOnDragListener != null && (mViewFlags & ENABLED_MASK) == ENABLED 21756 && li.mOnDragListener.onDrag(this, event)) { 21757 result = true; 21758 } else { 21759 result = onDragEvent(event); 21760 } 21761 21762 switch (event.mAction) { 21763 case DragEvent.ACTION_DRAG_ENTERED: { 21764 mPrivateFlags2 |= View.PFLAG2_DRAG_HOVERED; 21765 refreshDrawableState(); 21766 } break; 21767 case DragEvent.ACTION_DRAG_EXITED: { 21768 mPrivateFlags2 &= ~View.PFLAG2_DRAG_HOVERED; 21769 refreshDrawableState(); 21770 } break; 21771 case DragEvent.ACTION_DRAG_ENDED: { 21772 mPrivateFlags2 &= ~View.DRAG_MASK; 21773 refreshDrawableState(); 21774 } break; 21775 } 21776 21777 return result; 21778 } 21779 21780 boolean canAcceptDrag() { 21781 return (mPrivateFlags2 & PFLAG2_DRAG_CAN_ACCEPT) != 0; 21782 } 21783 21784 /** 21785 * This needs to be a better API (NOT ON VIEW) before it is exposed. If 21786 * it is ever exposed at all. 21787 * @hide 21788 */ 21789 public void onCloseSystemDialogs(String reason) { 21790 } 21791 21792 /** 21793 * Given a Drawable whose bounds have been set to draw into this view, 21794 * update a Region being computed for 21795 * {@link #gatherTransparentRegion(android.graphics.Region)} so 21796 * that any non-transparent parts of the Drawable are removed from the 21797 * given transparent region. 21798 * 21799 * @param dr The Drawable whose transparency is to be applied to the region. 21800 * @param region A Region holding the current transparency information, 21801 * where any parts of the region that are set are considered to be 21802 * transparent. On return, this region will be modified to have the 21803 * transparency information reduced by the corresponding parts of the 21804 * Drawable that are not transparent. 21805 * {@hide} 21806 */ 21807 public void applyDrawableToTransparentRegion(Drawable dr, Region region) { 21808 if (DBG) { 21809 Log.i("View", "Getting transparent region for: " + this); 21810 } 21811 final Region r = dr.getTransparentRegion(); 21812 final Rect db = dr.getBounds(); 21813 final AttachInfo attachInfo = mAttachInfo; 21814 if (r != null && attachInfo != null) { 21815 final int w = getRight()-getLeft(); 21816 final int h = getBottom()-getTop(); 21817 if (db.left > 0) { 21818 //Log.i("VIEW", "Drawable left " + db.left + " > view 0"); 21819 r.op(0, 0, db.left, h, Region.Op.UNION); 21820 } 21821 if (db.right < w) { 21822 //Log.i("VIEW", "Drawable right " + db.right + " < view " + w); 21823 r.op(db.right, 0, w, h, Region.Op.UNION); 21824 } 21825 if (db.top > 0) { 21826 //Log.i("VIEW", "Drawable top " + db.top + " > view 0"); 21827 r.op(0, 0, w, db.top, Region.Op.UNION); 21828 } 21829 if (db.bottom < h) { 21830 //Log.i("VIEW", "Drawable bottom " + db.bottom + " < view " + h); 21831 r.op(0, db.bottom, w, h, Region.Op.UNION); 21832 } 21833 final int[] location = attachInfo.mTransparentLocation; 21834 getLocationInWindow(location); 21835 r.translate(location[0], location[1]); 21836 region.op(r, Region.Op.INTERSECT); 21837 } else { 21838 region.op(db, Region.Op.DIFFERENCE); 21839 } 21840 } 21841 21842 private void checkForLongClick(int delayOffset, float x, float y) { 21843 if ((mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE || (mViewFlags & TOOLTIP) == TOOLTIP) { 21844 mHasPerformedLongPress = false; 21845 21846 if (mPendingCheckForLongPress == null) { 21847 mPendingCheckForLongPress = new CheckForLongPress(); 21848 } 21849 mPendingCheckForLongPress.setAnchor(x, y); 21850 mPendingCheckForLongPress.rememberWindowAttachCount(); 21851 mPendingCheckForLongPress.rememberPressedState(); 21852 postDelayed(mPendingCheckForLongPress, 21853 ViewConfiguration.getLongPressTimeout() - delayOffset); 21854 } 21855 } 21856 21857 /** 21858 * Inflate a view from an XML resource. This convenience method wraps the {@link 21859 * LayoutInflater} class, which provides a full range of options for view inflation. 21860 * 21861 * @param context The Context object for your activity or application. 21862 * @param resource The resource ID to inflate 21863 * @param root A view group that will be the parent. Used to properly inflate the 21864 * layout_* parameters. 21865 * @see LayoutInflater 21866 */ 21867 public static View inflate(Context context, @LayoutRes int resource, ViewGroup root) { 21868 LayoutInflater factory = LayoutInflater.from(context); 21869 return factory.inflate(resource, root); 21870 } 21871 21872 /** 21873 * Scroll the view with standard behavior for scrolling beyond the normal 21874 * content boundaries. Views that call this method should override 21875 * {@link #onOverScrolled(int, int, boolean, boolean)} to respond to the 21876 * results of an over-scroll operation. 21877 * 21878 * Views can use this method to handle any touch or fling-based scrolling. 21879 * 21880 * @param deltaX Change in X in pixels 21881 * @param deltaY Change in Y in pixels 21882 * @param scrollX Current X scroll value in pixels before applying deltaX 21883 * @param scrollY Current Y scroll value in pixels before applying deltaY 21884 * @param scrollRangeX Maximum content scroll range along the X axis 21885 * @param scrollRangeY Maximum content scroll range along the Y axis 21886 * @param maxOverScrollX Number of pixels to overscroll by in either direction 21887 * along the X axis. 21888 * @param maxOverScrollY Number of pixels to overscroll by in either direction 21889 * along the Y axis. 21890 * @param isTouchEvent true if this scroll operation is the result of a touch event. 21891 * @return true if scrolling was clamped to an over-scroll boundary along either 21892 * axis, false otherwise. 21893 */ 21894 @SuppressWarnings({"UnusedParameters"}) 21895 protected boolean overScrollBy(int deltaX, int deltaY, 21896 int scrollX, int scrollY, 21897 int scrollRangeX, int scrollRangeY, 21898 int maxOverScrollX, int maxOverScrollY, 21899 boolean isTouchEvent) { 21900 final int overScrollMode = mOverScrollMode; 21901 final boolean canScrollHorizontal = 21902 computeHorizontalScrollRange() > computeHorizontalScrollExtent(); 21903 final boolean canScrollVertical = 21904 computeVerticalScrollRange() > computeVerticalScrollExtent(); 21905 final boolean overScrollHorizontal = overScrollMode == OVER_SCROLL_ALWAYS || 21906 (overScrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && canScrollHorizontal); 21907 final boolean overScrollVertical = overScrollMode == OVER_SCROLL_ALWAYS || 21908 (overScrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && canScrollVertical); 21909 21910 int newScrollX = scrollX + deltaX; 21911 if (!overScrollHorizontal) { 21912 maxOverScrollX = 0; 21913 } 21914 21915 int newScrollY = scrollY + deltaY; 21916 if (!overScrollVertical) { 21917 maxOverScrollY = 0; 21918 } 21919 21920 // Clamp values if at the limits and record 21921 final int left = -maxOverScrollX; 21922 final int right = maxOverScrollX + scrollRangeX; 21923 final int top = -maxOverScrollY; 21924 final int bottom = maxOverScrollY + scrollRangeY; 21925 21926 boolean clampedX = false; 21927 if (newScrollX > right) { 21928 newScrollX = right; 21929 clampedX = true; 21930 } else if (newScrollX < left) { 21931 newScrollX = left; 21932 clampedX = true; 21933 } 21934 21935 boolean clampedY = false; 21936 if (newScrollY > bottom) { 21937 newScrollY = bottom; 21938 clampedY = true; 21939 } else if (newScrollY < top) { 21940 newScrollY = top; 21941 clampedY = true; 21942 } 21943 21944 onOverScrolled(newScrollX, newScrollY, clampedX, clampedY); 21945 21946 return clampedX || clampedY; 21947 } 21948 21949 /** 21950 * Called by {@link #overScrollBy(int, int, int, int, int, int, int, int, boolean)} to 21951 * respond to the results of an over-scroll operation. 21952 * 21953 * @param scrollX New X scroll value in pixels 21954 * @param scrollY New Y scroll value in pixels 21955 * @param clampedX True if scrollX was clamped to an over-scroll boundary 21956 * @param clampedY True if scrollY was clamped to an over-scroll boundary 21957 */ 21958 protected void onOverScrolled(int scrollX, int scrollY, 21959 boolean clampedX, boolean clampedY) { 21960 // Intentionally empty. 21961 } 21962 21963 /** 21964 * Returns the over-scroll mode for this view. The result will be 21965 * one of {@link #OVER_SCROLL_ALWAYS} (default), {@link #OVER_SCROLL_IF_CONTENT_SCROLLS} 21966 * (allow over-scrolling only if the view content is larger than the container), 21967 * or {@link #OVER_SCROLL_NEVER}. 21968 * 21969 * @return This view's over-scroll mode. 21970 */ 21971 public int getOverScrollMode() { 21972 return mOverScrollMode; 21973 } 21974 21975 /** 21976 * Set the over-scroll mode for this view. Valid over-scroll modes are 21977 * {@link #OVER_SCROLL_ALWAYS} (default), {@link #OVER_SCROLL_IF_CONTENT_SCROLLS} 21978 * (allow over-scrolling only if the view content is larger than the container), 21979 * or {@link #OVER_SCROLL_NEVER}. 21980 * 21981 * Setting the over-scroll mode of a view will have an effect only if the 21982 * view is capable of scrolling. 21983 * 21984 * @param overScrollMode The new over-scroll mode for this view. 21985 */ 21986 public void setOverScrollMode(int overScrollMode) { 21987 if (overScrollMode != OVER_SCROLL_ALWAYS && 21988 overScrollMode != OVER_SCROLL_IF_CONTENT_SCROLLS && 21989 overScrollMode != OVER_SCROLL_NEVER) { 21990 throw new IllegalArgumentException("Invalid overscroll mode " + overScrollMode); 21991 } 21992 mOverScrollMode = overScrollMode; 21993 } 21994 21995 /** 21996 * Enable or disable nested scrolling for this view. 21997 * 21998 * <p>If this property is set to true the view will be permitted to initiate nested 21999 * scrolling operations with a compatible parent view in the current hierarchy. If this 22000 * view does not implement nested scrolling this will have no effect. Disabling nested scrolling 22001 * while a nested scroll is in progress has the effect of {@link #stopNestedScroll() stopping} 22002 * the nested scroll.</p> 22003 * 22004 * @param enabled true to enable nested scrolling, false to disable 22005 * 22006 * @see #isNestedScrollingEnabled() 22007 */ 22008 public void setNestedScrollingEnabled(boolean enabled) { 22009 if (enabled) { 22010 mPrivateFlags3 |= PFLAG3_NESTED_SCROLLING_ENABLED; 22011 } else { 22012 stopNestedScroll(); 22013 mPrivateFlags3 &= ~PFLAG3_NESTED_SCROLLING_ENABLED; 22014 } 22015 } 22016 22017 /** 22018 * Returns true if nested scrolling is enabled for this view. 22019 * 22020 * <p>If nested scrolling is enabled and this View class implementation supports it, 22021 * this view will act as a nested scrolling child view when applicable, forwarding data 22022 * about the scroll operation in progress to a compatible and cooperating nested scrolling 22023 * parent.</p> 22024 * 22025 * @return true if nested scrolling is enabled 22026 * 22027 * @see #setNestedScrollingEnabled(boolean) 22028 */ 22029 public boolean isNestedScrollingEnabled() { 22030 return (mPrivateFlags3 & PFLAG3_NESTED_SCROLLING_ENABLED) == 22031 PFLAG3_NESTED_SCROLLING_ENABLED; 22032 } 22033 22034 /** 22035 * Begin a nestable scroll operation along the given axes. 22036 * 22037 * <p>A view starting a nested scroll promises to abide by the following contract:</p> 22038 * 22039 * <p>The view will call startNestedScroll upon initiating a scroll operation. In the case 22040 * of a touch scroll this corresponds to the initial {@link MotionEvent#ACTION_DOWN}. 22041 * In the case of touch scrolling the nested scroll will be terminated automatically in 22042 * the same manner as {@link ViewParent#requestDisallowInterceptTouchEvent(boolean)}. 22043 * In the event of programmatic scrolling the caller must explicitly call 22044 * {@link #stopNestedScroll()} to indicate the end of the nested scroll.</p> 22045 * 22046 * <p>If <code>startNestedScroll</code> returns true, a cooperative parent was found. 22047 * If it returns false the caller may ignore the rest of this contract until the next scroll. 22048 * Calling startNestedScroll while a nested scroll is already in progress will return true.</p> 22049 * 22050 * <p>At each incremental step of the scroll the caller should invoke 22051 * {@link #dispatchNestedPreScroll(int, int, int[], int[]) dispatchNestedPreScroll} 22052 * once it has calculated the requested scrolling delta. If it returns true the nested scrolling 22053 * parent at least partially consumed the scroll and the caller should adjust the amount it 22054 * scrolls by.</p> 22055 * 22056 * <p>After applying the remainder of the scroll delta the caller should invoke 22057 * {@link #dispatchNestedScroll(int, int, int, int, int[]) dispatchNestedScroll}, passing 22058 * both the delta consumed and the delta unconsumed. A nested scrolling parent may treat 22059 * these values differently. See {@link ViewParent#onNestedScroll(View, int, int, int, int)}. 22060 * </p> 22061 * 22062 * @param axes Flags consisting of a combination of {@link #SCROLL_AXIS_HORIZONTAL} and/or 22063 * {@link #SCROLL_AXIS_VERTICAL}. 22064 * @return true if a cooperative parent was found and nested scrolling has been enabled for 22065 * the current gesture. 22066 * 22067 * @see #stopNestedScroll() 22068 * @see #dispatchNestedPreScroll(int, int, int[], int[]) 22069 * @see #dispatchNestedScroll(int, int, int, int, int[]) 22070 */ 22071 public boolean startNestedScroll(int axes) { 22072 if (hasNestedScrollingParent()) { 22073 // Already in progress 22074 return true; 22075 } 22076 if (isNestedScrollingEnabled()) { 22077 ViewParent p = getParent(); 22078 View child = this; 22079 while (p != null) { 22080 try { 22081 if (p.onStartNestedScroll(child, this, axes)) { 22082 mNestedScrollingParent = p; 22083 p.onNestedScrollAccepted(child, this, axes); 22084 return true; 22085 } 22086 } catch (AbstractMethodError e) { 22087 Log.e(VIEW_LOG_TAG, "ViewParent " + p + " does not implement interface " + 22088 "method onStartNestedScroll", e); 22089 // Allow the search upward to continue 22090 } 22091 if (p instanceof View) { 22092 child = (View) p; 22093 } 22094 p = p.getParent(); 22095 } 22096 } 22097 return false; 22098 } 22099 22100 /** 22101 * Stop a nested scroll in progress. 22102 * 22103 * <p>Calling this method when a nested scroll is not currently in progress is harmless.</p> 22104 * 22105 * @see #startNestedScroll(int) 22106 */ 22107 public void stopNestedScroll() { 22108 if (mNestedScrollingParent != null) { 22109 mNestedScrollingParent.onStopNestedScroll(this); 22110 mNestedScrollingParent = null; 22111 } 22112 } 22113 22114 /** 22115 * Returns true if this view has a nested scrolling parent. 22116 * 22117 * <p>The presence of a nested scrolling parent indicates that this view has initiated 22118 * a nested scroll and it was accepted by an ancestor view further up the view hierarchy.</p> 22119 * 22120 * @return whether this view has a nested scrolling parent 22121 */ 22122 public boolean hasNestedScrollingParent() { 22123 return mNestedScrollingParent != null; 22124 } 22125 22126 /** 22127 * Dispatch one step of a nested scroll in progress. 22128 * 22129 * <p>Implementations of views that support nested scrolling should call this to report 22130 * info about a scroll in progress to the current nested scrolling parent. If a nested scroll 22131 * is not currently in progress or nested scrolling is not 22132 * {@link #isNestedScrollingEnabled() enabled} for this view this method does nothing.</p> 22133 * 22134 * <p>Compatible View implementations should also call 22135 * {@link #dispatchNestedPreScroll(int, int, int[], int[]) dispatchNestedPreScroll} before 22136 * consuming a component of the scroll event themselves.</p> 22137 * 22138 * @param dxConsumed Horizontal distance in pixels consumed by this view during this scroll step 22139 * @param dyConsumed Vertical distance in pixels consumed by this view during this scroll step 22140 * @param dxUnconsumed Horizontal scroll distance in pixels not consumed by this view 22141 * @param dyUnconsumed Horizontal scroll distance in pixels not consumed by this view 22142 * @param offsetInWindow Optional. If not null, on return this will contain the offset 22143 * in local view coordinates of this view from before this operation 22144 * to after it completes. View implementations may use this to adjust 22145 * expected input coordinate tracking. 22146 * @return true if the event was dispatched, false if it could not be dispatched. 22147 * @see #dispatchNestedPreScroll(int, int, int[], int[]) 22148 */ 22149 public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed, 22150 int dxUnconsumed, int dyUnconsumed, @Nullable @Size(2) int[] offsetInWindow) { 22151 if (isNestedScrollingEnabled() && mNestedScrollingParent != null) { 22152 if (dxConsumed != 0 || dyConsumed != 0 || dxUnconsumed != 0 || dyUnconsumed != 0) { 22153 int startX = 0; 22154 int startY = 0; 22155 if (offsetInWindow != null) { 22156 getLocationInWindow(offsetInWindow); 22157 startX = offsetInWindow[0]; 22158 startY = offsetInWindow[1]; 22159 } 22160 22161 mNestedScrollingParent.onNestedScroll(this, dxConsumed, dyConsumed, 22162 dxUnconsumed, dyUnconsumed); 22163 22164 if (offsetInWindow != null) { 22165 getLocationInWindow(offsetInWindow); 22166 offsetInWindow[0] -= startX; 22167 offsetInWindow[1] -= startY; 22168 } 22169 return true; 22170 } else if (offsetInWindow != null) { 22171 // No motion, no dispatch. Keep offsetInWindow up to date. 22172 offsetInWindow[0] = 0; 22173 offsetInWindow[1] = 0; 22174 } 22175 } 22176 return false; 22177 } 22178 22179 /** 22180 * Dispatch one step of a nested scroll in progress before this view consumes any portion of it. 22181 * 22182 * <p>Nested pre-scroll events are to nested scroll events what touch intercept is to touch. 22183 * <code>dispatchNestedPreScroll</code> offers an opportunity for the parent view in a nested 22184 * scrolling operation to consume some or all of the scroll operation before the child view 22185 * consumes it.</p> 22186 * 22187 * @param dx Horizontal scroll distance in pixels 22188 * @param dy Vertical scroll distance in pixels 22189 * @param consumed Output. If not null, consumed[0] will contain the consumed component of dx 22190 * and consumed[1] the consumed dy. 22191 * @param offsetInWindow Optional. If not null, on return this will contain the offset 22192 * in local view coordinates of this view from before this operation 22193 * to after it completes. View implementations may use this to adjust 22194 * expected input coordinate tracking. 22195 * @return true if the parent consumed some or all of the scroll delta 22196 * @see #dispatchNestedScroll(int, int, int, int, int[]) 22197 */ 22198 public boolean dispatchNestedPreScroll(int dx, int dy, 22199 @Nullable @Size(2) int[] consumed, @Nullable @Size(2) int[] offsetInWindow) { 22200 if (isNestedScrollingEnabled() && mNestedScrollingParent != null) { 22201 if (dx != 0 || dy != 0) { 22202 int startX = 0; 22203 int startY = 0; 22204 if (offsetInWindow != null) { 22205 getLocationInWindow(offsetInWindow); 22206 startX = offsetInWindow[0]; 22207 startY = offsetInWindow[1]; 22208 } 22209 22210 if (consumed == null) { 22211 if (mTempNestedScrollConsumed == null) { 22212 mTempNestedScrollConsumed = new int[2]; 22213 } 22214 consumed = mTempNestedScrollConsumed; 22215 } 22216 consumed[0] = 0; 22217 consumed[1] = 0; 22218 mNestedScrollingParent.onNestedPreScroll(this, dx, dy, consumed); 22219 22220 if (offsetInWindow != null) { 22221 getLocationInWindow(offsetInWindow); 22222 offsetInWindow[0] -= startX; 22223 offsetInWindow[1] -= startY; 22224 } 22225 return consumed[0] != 0 || consumed[1] != 0; 22226 } else if (offsetInWindow != null) { 22227 offsetInWindow[0] = 0; 22228 offsetInWindow[1] = 0; 22229 } 22230 } 22231 return false; 22232 } 22233 22234 /** 22235 * Dispatch a fling to a nested scrolling parent. 22236 * 22237 * <p>This method should be used to indicate that a nested scrolling child has detected 22238 * suitable conditions for a fling. Generally this means that a touch scroll has ended with a 22239 * {@link VelocityTracker velocity} in the direction of scrolling that meets or exceeds 22240 * the {@link ViewConfiguration#getScaledMinimumFlingVelocity() minimum fling velocity} 22241 * along a scrollable axis.</p> 22242 * 22243 * <p>If a nested scrolling child view would normally fling but it is at the edge of 22244 * its own content, it can use this method to delegate the fling to its nested scrolling 22245 * parent instead. The parent may optionally consume the fling or observe a child fling.</p> 22246 * 22247 * @param velocityX Horizontal fling velocity in pixels per second 22248 * @param velocityY Vertical fling velocity in pixels per second 22249 * @param consumed true if the child consumed the fling, false otherwise 22250 * @return true if the nested scrolling parent consumed or otherwise reacted to the fling 22251 */ 22252 public boolean dispatchNestedFling(float velocityX, float velocityY, boolean consumed) { 22253 if (isNestedScrollingEnabled() && mNestedScrollingParent != null) { 22254 return mNestedScrollingParent.onNestedFling(this, velocityX, velocityY, consumed); 22255 } 22256 return false; 22257 } 22258 22259 /** 22260 * Dispatch a fling to a nested scrolling parent before it is processed by this view. 22261 * 22262 * <p>Nested pre-fling events are to nested fling events what touch intercept is to touch 22263 * and what nested pre-scroll is to nested scroll. <code>dispatchNestedPreFling</code> 22264 * offsets an opportunity for the parent view in a nested fling to fully consume the fling 22265 * before the child view consumes it. If this method returns <code>true</code>, a nested 22266 * parent view consumed the fling and this view should not scroll as a result.</p> 22267 * 22268 * <p>For a better user experience, only one view in a nested scrolling chain should consume 22269 * the fling at a time. If a parent view consumed the fling this method will return false. 22270 * Custom view implementations should account for this in two ways:</p> 22271 * 22272 * <ul> 22273 * <li>If a custom view is paged and needs to settle to a fixed page-point, do not 22274 * call <code>dispatchNestedPreFling</code>; consume the fling and settle to a valid 22275 * position regardless.</li> 22276 * <li>If a nested parent does consume the fling, this view should not scroll at all, 22277 * even to settle back to a valid idle position.</li> 22278 * </ul> 22279 * 22280 * <p>Views should also not offer fling velocities to nested parent views along an axis 22281 * where scrolling is not currently supported; a {@link android.widget.ScrollView ScrollView} 22282 * should not offer a horizontal fling velocity to its parents since scrolling along that 22283 * axis is not permitted and carrying velocity along that motion does not make sense.</p> 22284 * 22285 * @param velocityX Horizontal fling velocity in pixels per second 22286 * @param velocityY Vertical fling velocity in pixels per second 22287 * @return true if a nested scrolling parent consumed the fling 22288 */ 22289 public boolean dispatchNestedPreFling(float velocityX, float velocityY) { 22290 if (isNestedScrollingEnabled() && mNestedScrollingParent != null) { 22291 return mNestedScrollingParent.onNestedPreFling(this, velocityX, velocityY); 22292 } 22293 return false; 22294 } 22295 22296 /** 22297 * Gets a scale factor that determines the distance the view should scroll 22298 * vertically in response to {@link MotionEvent#ACTION_SCROLL}. 22299 * @return The vertical scroll scale factor. 22300 * @hide 22301 */ 22302 protected float getVerticalScrollFactor() { 22303 if (mVerticalScrollFactor == 0) { 22304 TypedValue outValue = new TypedValue(); 22305 if (!mContext.getTheme().resolveAttribute( 22306 com.android.internal.R.attr.listPreferredItemHeight, outValue, true)) { 22307 throw new IllegalStateException( 22308 "Expected theme to define listPreferredItemHeight."); 22309 } 22310 mVerticalScrollFactor = outValue.getDimension( 22311 mContext.getResources().getDisplayMetrics()); 22312 } 22313 return mVerticalScrollFactor; 22314 } 22315 22316 /** 22317 * Gets a scale factor that determines the distance the view should scroll 22318 * horizontally in response to {@link MotionEvent#ACTION_SCROLL}. 22319 * @return The horizontal scroll scale factor. 22320 * @hide 22321 */ 22322 protected float getHorizontalScrollFactor() { 22323 // TODO: Should use something else. 22324 return getVerticalScrollFactor(); 22325 } 22326 22327 /** 22328 * Return the value specifying the text direction or policy that was set with 22329 * {@link #setTextDirection(int)}. 22330 * 22331 * @return the defined text direction. It can be one of: 22332 * 22333 * {@link #TEXT_DIRECTION_INHERIT}, 22334 * {@link #TEXT_DIRECTION_FIRST_STRONG}, 22335 * {@link #TEXT_DIRECTION_ANY_RTL}, 22336 * {@link #TEXT_DIRECTION_LTR}, 22337 * {@link #TEXT_DIRECTION_RTL}, 22338 * {@link #TEXT_DIRECTION_LOCALE}, 22339 * {@link #TEXT_DIRECTION_FIRST_STRONG_LTR}, 22340 * {@link #TEXT_DIRECTION_FIRST_STRONG_RTL} 22341 * 22342 * @attr ref android.R.styleable#View_textDirection 22343 * 22344 * @hide 22345 */ 22346 @ViewDebug.ExportedProperty(category = "text", mapping = { 22347 @ViewDebug.IntToString(from = TEXT_DIRECTION_INHERIT, to = "INHERIT"), 22348 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG, to = "FIRST_STRONG"), 22349 @ViewDebug.IntToString(from = TEXT_DIRECTION_ANY_RTL, to = "ANY_RTL"), 22350 @ViewDebug.IntToString(from = TEXT_DIRECTION_LTR, to = "LTR"), 22351 @ViewDebug.IntToString(from = TEXT_DIRECTION_RTL, to = "RTL"), 22352 @ViewDebug.IntToString(from = TEXT_DIRECTION_LOCALE, to = "LOCALE"), 22353 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_LTR, to = "FIRST_STRONG_LTR"), 22354 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_RTL, to = "FIRST_STRONG_RTL") 22355 }) 22356 public int getRawTextDirection() { 22357 return (mPrivateFlags2 & PFLAG2_TEXT_DIRECTION_MASK) >> PFLAG2_TEXT_DIRECTION_MASK_SHIFT; 22358 } 22359 22360 /** 22361 * Set the text direction. 22362 * 22363 * @param textDirection the direction to set. Should be one of: 22364 * 22365 * {@link #TEXT_DIRECTION_INHERIT}, 22366 * {@link #TEXT_DIRECTION_FIRST_STRONG}, 22367 * {@link #TEXT_DIRECTION_ANY_RTL}, 22368 * {@link #TEXT_DIRECTION_LTR}, 22369 * {@link #TEXT_DIRECTION_RTL}, 22370 * {@link #TEXT_DIRECTION_LOCALE} 22371 * {@link #TEXT_DIRECTION_FIRST_STRONG_LTR}, 22372 * {@link #TEXT_DIRECTION_FIRST_STRONG_RTL}, 22373 * 22374 * Resolution will be done if the value is set to TEXT_DIRECTION_INHERIT. The resolution 22375 * proceeds up the parent chain of the view to get the value. If there is no parent, then it will 22376 * return the default {@link #TEXT_DIRECTION_FIRST_STRONG}. 22377 * 22378 * @attr ref android.R.styleable#View_textDirection 22379 */ 22380 public void setTextDirection(int textDirection) { 22381 if (getRawTextDirection() != textDirection) { 22382 // Reset the current text direction and the resolved one 22383 mPrivateFlags2 &= ~PFLAG2_TEXT_DIRECTION_MASK; 22384 resetResolvedTextDirection(); 22385 // Set the new text direction 22386 mPrivateFlags2 |= ((textDirection << PFLAG2_TEXT_DIRECTION_MASK_SHIFT) & PFLAG2_TEXT_DIRECTION_MASK); 22387 // Do resolution 22388 resolveTextDirection(); 22389 // Notify change 22390 onRtlPropertiesChanged(getLayoutDirection()); 22391 // Refresh 22392 requestLayout(); 22393 invalidate(true); 22394 } 22395 } 22396 22397 /** 22398 * Return the resolved text direction. 22399 * 22400 * @return the resolved text direction. Returns one of: 22401 * 22402 * {@link #TEXT_DIRECTION_FIRST_STRONG}, 22403 * {@link #TEXT_DIRECTION_ANY_RTL}, 22404 * {@link #TEXT_DIRECTION_LTR}, 22405 * {@link #TEXT_DIRECTION_RTL}, 22406 * {@link #TEXT_DIRECTION_LOCALE}, 22407 * {@link #TEXT_DIRECTION_FIRST_STRONG_LTR}, 22408 * {@link #TEXT_DIRECTION_FIRST_STRONG_RTL} 22409 * 22410 * @attr ref android.R.styleable#View_textDirection 22411 */ 22412 @ViewDebug.ExportedProperty(category = "text", mapping = { 22413 @ViewDebug.IntToString(from = TEXT_DIRECTION_INHERIT, to = "INHERIT"), 22414 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG, to = "FIRST_STRONG"), 22415 @ViewDebug.IntToString(from = TEXT_DIRECTION_ANY_RTL, to = "ANY_RTL"), 22416 @ViewDebug.IntToString(from = TEXT_DIRECTION_LTR, to = "LTR"), 22417 @ViewDebug.IntToString(from = TEXT_DIRECTION_RTL, to = "RTL"), 22418 @ViewDebug.IntToString(from = TEXT_DIRECTION_LOCALE, to = "LOCALE"), 22419 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_LTR, to = "FIRST_STRONG_LTR"), 22420 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_RTL, to = "FIRST_STRONG_RTL") 22421 }) 22422 public int getTextDirection() { 22423 return (mPrivateFlags2 & PFLAG2_TEXT_DIRECTION_RESOLVED_MASK) >> PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT; 22424 } 22425 22426 /** 22427 * Resolve the text direction. 22428 * 22429 * @return true if resolution has been done, false otherwise. 22430 * 22431 * @hide 22432 */ 22433 public boolean resolveTextDirection() { 22434 // Reset any previous text direction resolution 22435 mPrivateFlags2 &= ~(PFLAG2_TEXT_DIRECTION_RESOLVED | PFLAG2_TEXT_DIRECTION_RESOLVED_MASK); 22436 22437 if (hasRtlSupport()) { 22438 // Set resolved text direction flag depending on text direction flag 22439 final int textDirection = getRawTextDirection(); 22440 switch(textDirection) { 22441 case TEXT_DIRECTION_INHERIT: 22442 if (!canResolveTextDirection()) { 22443 // We cannot do the resolution if there is no parent, so use the default one 22444 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 22445 // Resolution will need to happen again later 22446 return false; 22447 } 22448 22449 // Parent has not yet resolved, so we still return the default 22450 try { 22451 if (!mParent.isTextDirectionResolved()) { 22452 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 22453 // Resolution will need to happen again later 22454 return false; 22455 } 22456 } catch (AbstractMethodError e) { 22457 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 22458 " does not fully implement ViewParent", e); 22459 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED | 22460 PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 22461 return true; 22462 } 22463 22464 // Set current resolved direction to the same value as the parent's one 22465 int parentResolvedDirection; 22466 try { 22467 parentResolvedDirection = mParent.getTextDirection(); 22468 } catch (AbstractMethodError e) { 22469 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 22470 " does not fully implement ViewParent", e); 22471 parentResolvedDirection = TEXT_DIRECTION_LTR; 22472 } 22473 switch (parentResolvedDirection) { 22474 case TEXT_DIRECTION_FIRST_STRONG: 22475 case TEXT_DIRECTION_ANY_RTL: 22476 case TEXT_DIRECTION_LTR: 22477 case TEXT_DIRECTION_RTL: 22478 case TEXT_DIRECTION_LOCALE: 22479 case TEXT_DIRECTION_FIRST_STRONG_LTR: 22480 case TEXT_DIRECTION_FIRST_STRONG_RTL: 22481 mPrivateFlags2 |= 22482 (parentResolvedDirection << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT); 22483 break; 22484 default: 22485 // Default resolved direction is "first strong" heuristic 22486 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 22487 } 22488 break; 22489 case TEXT_DIRECTION_FIRST_STRONG: 22490 case TEXT_DIRECTION_ANY_RTL: 22491 case TEXT_DIRECTION_LTR: 22492 case TEXT_DIRECTION_RTL: 22493 case TEXT_DIRECTION_LOCALE: 22494 case TEXT_DIRECTION_FIRST_STRONG_LTR: 22495 case TEXT_DIRECTION_FIRST_STRONG_RTL: 22496 // Resolved direction is the same as text direction 22497 mPrivateFlags2 |= (textDirection << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT); 22498 break; 22499 default: 22500 // Default resolved direction is "first strong" heuristic 22501 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 22502 } 22503 } else { 22504 // Default resolved direction is "first strong" heuristic 22505 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 22506 } 22507 22508 // Set to resolved 22509 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED; 22510 return true; 22511 } 22512 22513 /** 22514 * Check if text direction resolution can be done. 22515 * 22516 * @return true if text direction resolution can be done otherwise return false. 22517 */ 22518 public boolean canResolveTextDirection() { 22519 switch (getRawTextDirection()) { 22520 case TEXT_DIRECTION_INHERIT: 22521 if (mParent != null) { 22522 try { 22523 return mParent.canResolveTextDirection(); 22524 } catch (AbstractMethodError e) { 22525 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 22526 " does not fully implement ViewParent", e); 22527 } 22528 } 22529 return false; 22530 22531 default: 22532 return true; 22533 } 22534 } 22535 22536 /** 22537 * Reset resolved text direction. Text direction will be resolved during a call to 22538 * {@link #onMeasure(int, int)}. 22539 * 22540 * @hide 22541 */ 22542 public void resetResolvedTextDirection() { 22543 // Reset any previous text direction resolution 22544 mPrivateFlags2 &= ~(PFLAG2_TEXT_DIRECTION_RESOLVED | PFLAG2_TEXT_DIRECTION_RESOLVED_MASK); 22545 // Set to default value 22546 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 22547 } 22548 22549 /** 22550 * @return true if text direction is inherited. 22551 * 22552 * @hide 22553 */ 22554 public boolean isTextDirectionInherited() { 22555 return (getRawTextDirection() == TEXT_DIRECTION_INHERIT); 22556 } 22557 22558 /** 22559 * @return true if text direction is resolved. 22560 */ 22561 public boolean isTextDirectionResolved() { 22562 return (mPrivateFlags2 & PFLAG2_TEXT_DIRECTION_RESOLVED) == PFLAG2_TEXT_DIRECTION_RESOLVED; 22563 } 22564 22565 /** 22566 * Return the value specifying the text alignment or policy that was set with 22567 * {@link #setTextAlignment(int)}. 22568 * 22569 * @return the defined text alignment. It can be one of: 22570 * 22571 * {@link #TEXT_ALIGNMENT_INHERIT}, 22572 * {@link #TEXT_ALIGNMENT_GRAVITY}, 22573 * {@link #TEXT_ALIGNMENT_CENTER}, 22574 * {@link #TEXT_ALIGNMENT_TEXT_START}, 22575 * {@link #TEXT_ALIGNMENT_TEXT_END}, 22576 * {@link #TEXT_ALIGNMENT_VIEW_START}, 22577 * {@link #TEXT_ALIGNMENT_VIEW_END} 22578 * 22579 * @attr ref android.R.styleable#View_textAlignment 22580 * 22581 * @hide 22582 */ 22583 @ViewDebug.ExportedProperty(category = "text", mapping = { 22584 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_INHERIT, to = "INHERIT"), 22585 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_GRAVITY, to = "GRAVITY"), 22586 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_TEXT_START, to = "TEXT_START"), 22587 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_TEXT_END, to = "TEXT_END"), 22588 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_CENTER, to = "CENTER"), 22589 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_START, to = "VIEW_START"), 22590 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_END, to = "VIEW_END") 22591 }) 22592 @TextAlignment 22593 public int getRawTextAlignment() { 22594 return (mPrivateFlags2 & PFLAG2_TEXT_ALIGNMENT_MASK) >> PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT; 22595 } 22596 22597 /** 22598 * Set the text alignment. 22599 * 22600 * @param textAlignment The text alignment to set. Should be one of 22601 * 22602 * {@link #TEXT_ALIGNMENT_INHERIT}, 22603 * {@link #TEXT_ALIGNMENT_GRAVITY}, 22604 * {@link #TEXT_ALIGNMENT_CENTER}, 22605 * {@link #TEXT_ALIGNMENT_TEXT_START}, 22606 * {@link #TEXT_ALIGNMENT_TEXT_END}, 22607 * {@link #TEXT_ALIGNMENT_VIEW_START}, 22608 * {@link #TEXT_ALIGNMENT_VIEW_END} 22609 * 22610 * Resolution will be done if the value is set to TEXT_ALIGNMENT_INHERIT. The resolution 22611 * proceeds up the parent chain of the view to get the value. If there is no parent, then it 22612 * will return the default {@link #TEXT_ALIGNMENT_GRAVITY}. 22613 * 22614 * @attr ref android.R.styleable#View_textAlignment 22615 */ 22616 public void setTextAlignment(@TextAlignment int textAlignment) { 22617 if (textAlignment != getRawTextAlignment()) { 22618 // Reset the current and resolved text alignment 22619 mPrivateFlags2 &= ~PFLAG2_TEXT_ALIGNMENT_MASK; 22620 resetResolvedTextAlignment(); 22621 // Set the new text alignment 22622 mPrivateFlags2 |= 22623 ((textAlignment << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT) & PFLAG2_TEXT_ALIGNMENT_MASK); 22624 // Do resolution 22625 resolveTextAlignment(); 22626 // Notify change 22627 onRtlPropertiesChanged(getLayoutDirection()); 22628 // Refresh 22629 requestLayout(); 22630 invalidate(true); 22631 } 22632 } 22633 22634 /** 22635 * Return the resolved text alignment. 22636 * 22637 * @return the resolved text alignment. Returns one of: 22638 * 22639 * {@link #TEXT_ALIGNMENT_GRAVITY}, 22640 * {@link #TEXT_ALIGNMENT_CENTER}, 22641 * {@link #TEXT_ALIGNMENT_TEXT_START}, 22642 * {@link #TEXT_ALIGNMENT_TEXT_END}, 22643 * {@link #TEXT_ALIGNMENT_VIEW_START}, 22644 * {@link #TEXT_ALIGNMENT_VIEW_END} 22645 * 22646 * @attr ref android.R.styleable#View_textAlignment 22647 */ 22648 @ViewDebug.ExportedProperty(category = "text", mapping = { 22649 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_INHERIT, to = "INHERIT"), 22650 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_GRAVITY, to = "GRAVITY"), 22651 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_TEXT_START, to = "TEXT_START"), 22652 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_TEXT_END, to = "TEXT_END"), 22653 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_CENTER, to = "CENTER"), 22654 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_START, to = "VIEW_START"), 22655 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_END, to = "VIEW_END") 22656 }) 22657 @TextAlignment 22658 public int getTextAlignment() { 22659 return (mPrivateFlags2 & PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK) >> 22660 PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT; 22661 } 22662 22663 /** 22664 * Resolve the text alignment. 22665 * 22666 * @return true if resolution has been done, false otherwise. 22667 * 22668 * @hide 22669 */ 22670 public boolean resolveTextAlignment() { 22671 // Reset any previous text alignment resolution 22672 mPrivateFlags2 &= ~(PFLAG2_TEXT_ALIGNMENT_RESOLVED | PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK); 22673 22674 if (hasRtlSupport()) { 22675 // Set resolved text alignment flag depending on text alignment flag 22676 final int textAlignment = getRawTextAlignment(); 22677 switch (textAlignment) { 22678 case TEXT_ALIGNMENT_INHERIT: 22679 // Check if we can resolve the text alignment 22680 if (!canResolveTextAlignment()) { 22681 // We cannot do the resolution if there is no parent so use the default 22682 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 22683 // Resolution will need to happen again later 22684 return false; 22685 } 22686 22687 // Parent has not yet resolved, so we still return the default 22688 try { 22689 if (!mParent.isTextAlignmentResolved()) { 22690 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 22691 // Resolution will need to happen again later 22692 return false; 22693 } 22694 } catch (AbstractMethodError e) { 22695 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 22696 " does not fully implement ViewParent", e); 22697 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED | 22698 PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 22699 return true; 22700 } 22701 22702 int parentResolvedTextAlignment; 22703 try { 22704 parentResolvedTextAlignment = mParent.getTextAlignment(); 22705 } catch (AbstractMethodError e) { 22706 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 22707 " does not fully implement ViewParent", e); 22708 parentResolvedTextAlignment = TEXT_ALIGNMENT_GRAVITY; 22709 } 22710 switch (parentResolvedTextAlignment) { 22711 case TEXT_ALIGNMENT_GRAVITY: 22712 case TEXT_ALIGNMENT_TEXT_START: 22713 case TEXT_ALIGNMENT_TEXT_END: 22714 case TEXT_ALIGNMENT_CENTER: 22715 case TEXT_ALIGNMENT_VIEW_START: 22716 case TEXT_ALIGNMENT_VIEW_END: 22717 // Resolved text alignment is the same as the parent resolved 22718 // text alignment 22719 mPrivateFlags2 |= 22720 (parentResolvedTextAlignment << PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT); 22721 break; 22722 default: 22723 // Use default resolved text alignment 22724 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 22725 } 22726 break; 22727 case TEXT_ALIGNMENT_GRAVITY: 22728 case TEXT_ALIGNMENT_TEXT_START: 22729 case TEXT_ALIGNMENT_TEXT_END: 22730 case TEXT_ALIGNMENT_CENTER: 22731 case TEXT_ALIGNMENT_VIEW_START: 22732 case TEXT_ALIGNMENT_VIEW_END: 22733 // Resolved text alignment is the same as text alignment 22734 mPrivateFlags2 |= (textAlignment << PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT); 22735 break; 22736 default: 22737 // Use default resolved text alignment 22738 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 22739 } 22740 } else { 22741 // Use default resolved text alignment 22742 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 22743 } 22744 22745 // Set the resolved 22746 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED; 22747 return true; 22748 } 22749 22750 /** 22751 * Check if text alignment resolution can be done. 22752 * 22753 * @return true if text alignment resolution can be done otherwise return false. 22754 */ 22755 public boolean canResolveTextAlignment() { 22756 switch (getRawTextAlignment()) { 22757 case TEXT_DIRECTION_INHERIT: 22758 if (mParent != null) { 22759 try { 22760 return mParent.canResolveTextAlignment(); 22761 } catch (AbstractMethodError e) { 22762 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 22763 " does not fully implement ViewParent", e); 22764 } 22765 } 22766 return false; 22767 22768 default: 22769 return true; 22770 } 22771 } 22772 22773 /** 22774 * Reset resolved text alignment. Text alignment will be resolved during a call to 22775 * {@link #onMeasure(int, int)}. 22776 * 22777 * @hide 22778 */ 22779 public void resetResolvedTextAlignment() { 22780 // Reset any previous text alignment resolution 22781 mPrivateFlags2 &= ~(PFLAG2_TEXT_ALIGNMENT_RESOLVED | PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK); 22782 // Set to default 22783 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 22784 } 22785 22786 /** 22787 * @return true if text alignment is inherited. 22788 * 22789 * @hide 22790 */ 22791 public boolean isTextAlignmentInherited() { 22792 return (getRawTextAlignment() == TEXT_ALIGNMENT_INHERIT); 22793 } 22794 22795 /** 22796 * @return true if text alignment is resolved. 22797 */ 22798 public boolean isTextAlignmentResolved() { 22799 return (mPrivateFlags2 & PFLAG2_TEXT_ALIGNMENT_RESOLVED) == PFLAG2_TEXT_ALIGNMENT_RESOLVED; 22800 } 22801 22802 /** 22803 * Generate a value suitable for use in {@link #setId(int)}. 22804 * This value will not collide with ID values generated at build time by aapt for R.id. 22805 * 22806 * @return a generated ID value 22807 */ 22808 public static int generateViewId() { 22809 for (;;) { 22810 final int result = sNextGeneratedId.get(); 22811 // aapt-generated IDs have the high byte nonzero; clamp to the range under that. 22812 int newValue = result + 1; 22813 if (newValue > 0x00FFFFFF) newValue = 1; // Roll over to 1, not 0. 22814 if (sNextGeneratedId.compareAndSet(result, newValue)) { 22815 return result; 22816 } 22817 } 22818 } 22819 22820 private static boolean isViewIdGenerated(int id) { 22821 return (id & 0xFF000000) == 0 && (id & 0x00FFFFFF) != 0; 22822 } 22823 22824 /** 22825 * Gets the Views in the hierarchy affected by entering and exiting Activity Scene transitions. 22826 * @param transitioningViews This View will be added to transitioningViews if it is VISIBLE and 22827 * a normal View or a ViewGroup with 22828 * {@link android.view.ViewGroup#isTransitionGroup()} true. 22829 * @hide 22830 */ 22831 public void captureTransitioningViews(List<View> transitioningViews) { 22832 if (getVisibility() == View.VISIBLE) { 22833 transitioningViews.add(this); 22834 } 22835 } 22836 22837 /** 22838 * Adds all Views that have {@link #getTransitionName()} non-null to namedElements. 22839 * @param namedElements Will contain all Views in the hierarchy having a transitionName. 22840 * @hide 22841 */ 22842 public void findNamedViews(Map<String, View> namedElements) { 22843 if (getVisibility() == VISIBLE || mGhostView != null) { 22844 String transitionName = getTransitionName(); 22845 if (transitionName != null) { 22846 namedElements.put(transitionName, this); 22847 } 22848 } 22849 } 22850 22851 /** 22852 * Returns the pointer icon for the motion event, or null if it doesn't specify the icon. 22853 * The default implementation does not care the location or event types, but some subclasses 22854 * may use it (such as WebViews). 22855 * @param event The MotionEvent from a mouse 22856 * @param pointerIndex The index of the pointer for which to retrieve the {@link PointerIcon}. 22857 * This will be between 0 and {@link MotionEvent#getPointerCount()}. 22858 * @see PointerIcon 22859 */ 22860 public PointerIcon onResolvePointerIcon(MotionEvent event, int pointerIndex) { 22861 final float x = event.getX(pointerIndex); 22862 final float y = event.getY(pointerIndex); 22863 if (isDraggingScrollBar() || isOnScrollbarThumb(x, y)) { 22864 return PointerIcon.getSystemIcon(mContext, PointerIcon.TYPE_ARROW); 22865 } 22866 return mPointerIcon; 22867 } 22868 22869 /** 22870 * Set the pointer icon for the current view. 22871 * Passing {@code null} will restore the pointer icon to its default value. 22872 * @param pointerIcon A PointerIcon instance which will be shown when the mouse hovers. 22873 */ 22874 public void setPointerIcon(PointerIcon pointerIcon) { 22875 mPointerIcon = pointerIcon; 22876 if (mAttachInfo == null || mAttachInfo.mHandlingPointerEvent) { 22877 return; 22878 } 22879 try { 22880 mAttachInfo.mSession.updatePointerIcon(mAttachInfo.mWindow); 22881 } catch (RemoteException e) { 22882 } 22883 } 22884 22885 /** 22886 * Gets the pointer icon for the current view. 22887 */ 22888 public PointerIcon getPointerIcon() { 22889 return mPointerIcon; 22890 } 22891 22892 /** 22893 * Checks pointer capture status. 22894 * 22895 * @return true if the view has pointer capture. 22896 * @see #requestPointerCapture() 22897 * @see #hasPointerCapture() 22898 */ 22899 public boolean hasPointerCapture() { 22900 final ViewRootImpl viewRootImpl = getViewRootImpl(); 22901 if (viewRootImpl == null) { 22902 return false; 22903 } 22904 return viewRootImpl.hasPointerCapture(); 22905 } 22906 22907 /** 22908 * Requests pointer capture mode. 22909 * <p> 22910 * When the window has pointer capture, the mouse pointer icon will disappear and will not 22911 * change its position. Further mouse will be dispatched with the source 22912 * {@link InputDevice#SOURCE_MOUSE_RELATIVE}, and relative position changes will be available 22913 * through {@link MotionEvent#getX} and {@link MotionEvent#getY}. Non-mouse events 22914 * (touchscreens, or stylus) will not be affected. 22915 * <p> 22916 * If the window already has pointer capture, this call does nothing. 22917 * <p> 22918 * The capture may be released through {@link #releasePointerCapture()}, or will be lost 22919 * automatically when the window loses focus. 22920 * 22921 * @see #releasePointerCapture() 22922 * @see #hasPointerCapture() 22923 */ 22924 public void requestPointerCapture() { 22925 final ViewRootImpl viewRootImpl = getViewRootImpl(); 22926 if (viewRootImpl != null) { 22927 viewRootImpl.requestPointerCapture(true); 22928 } 22929 } 22930 22931 22932 /** 22933 * Releases the pointer capture. 22934 * <p> 22935 * If the window does not have pointer capture, this call will do nothing. 22936 * @see #requestPointerCapture() 22937 * @see #hasPointerCapture() 22938 */ 22939 public void releasePointerCapture() { 22940 final ViewRootImpl viewRootImpl = getViewRootImpl(); 22941 if (viewRootImpl != null) { 22942 viewRootImpl.requestPointerCapture(false); 22943 } 22944 } 22945 22946 /** 22947 * Called when the window has just acquired or lost pointer capture. 22948 * 22949 * @param hasCapture True if the view now has pointerCapture, false otherwise. 22950 */ 22951 @CallSuper 22952 public void onPointerCaptureChange(boolean hasCapture) { 22953 } 22954 22955 /** 22956 * @see #onPointerCaptureChange 22957 */ 22958 public void dispatchPointerCaptureChanged(boolean hasCapture) { 22959 onPointerCaptureChange(hasCapture); 22960 } 22961 22962 /** 22963 * Implement this method to handle captured pointer events 22964 * 22965 * @param event The captured pointer event. 22966 * @return True if the event was handled, false otherwise. 22967 * @see #requestPointerCapture() 22968 */ 22969 public boolean onCapturedPointerEvent(MotionEvent event) { 22970 return false; 22971 } 22972 22973 /** 22974 * Interface definition for a callback to be invoked when a captured pointer event 22975 * is being dispatched this view. The callback will be invoked before the event is 22976 * given to the view. 22977 */ 22978 public interface OnCapturedPointerListener { 22979 /** 22980 * Called when a captured pointer event is dispatched to a view. 22981 * @param view The view this event has been dispatched to. 22982 * @param event The captured event. 22983 * @return True if the listener has consumed the event, false otherwise. 22984 */ 22985 boolean onCapturedPointer(View view, MotionEvent event); 22986 } 22987 22988 /** 22989 * Set a listener to receive callbacks when the pointer capture state of a view changes. 22990 * @param l The {@link OnCapturedPointerListener} to receive callbacks. 22991 */ 22992 public void setOnCapturedPointerListener(OnCapturedPointerListener l) { 22993 getListenerInfo().mOnCapturedPointerListener = l; 22994 } 22995 22996 // Properties 22997 // 22998 /** 22999 * A Property wrapper around the <code>alpha</code> functionality handled by the 23000 * {@link View#setAlpha(float)} and {@link View#getAlpha()} methods. 23001 */ 23002 public static final Property<View, Float> ALPHA = new FloatProperty<View>("alpha") { 23003 @Override 23004 public void setValue(View object, float value) { 23005 object.setAlpha(value); 23006 } 23007 23008 @Override 23009 public Float get(View object) { 23010 return object.getAlpha(); 23011 } 23012 }; 23013 23014 /** 23015 * A Property wrapper around the <code>translationX</code> functionality handled by the 23016 * {@link View#setTranslationX(float)} and {@link View#getTranslationX()} methods. 23017 */ 23018 public static final Property<View, Float> TRANSLATION_X = new FloatProperty<View>("translationX") { 23019 @Override 23020 public void setValue(View object, float value) { 23021 object.setTranslationX(value); 23022 } 23023 23024 @Override 23025 public Float get(View object) { 23026 return object.getTranslationX(); 23027 } 23028 }; 23029 23030 /** 23031 * A Property wrapper around the <code>translationY</code> functionality handled by the 23032 * {@link View#setTranslationY(float)} and {@link View#getTranslationY()} methods. 23033 */ 23034 public static final Property<View, Float> TRANSLATION_Y = new FloatProperty<View>("translationY") { 23035 @Override 23036 public void setValue(View object, float value) { 23037 object.setTranslationY(value); 23038 } 23039 23040 @Override 23041 public Float get(View object) { 23042 return object.getTranslationY(); 23043 } 23044 }; 23045 23046 /** 23047 * A Property wrapper around the <code>translationZ</code> functionality handled by the 23048 * {@link View#setTranslationZ(float)} and {@link View#getTranslationZ()} methods. 23049 */ 23050 public static final Property<View, Float> TRANSLATION_Z = new FloatProperty<View>("translationZ") { 23051 @Override 23052 public void setValue(View object, float value) { 23053 object.setTranslationZ(value); 23054 } 23055 23056 @Override 23057 public Float get(View object) { 23058 return object.getTranslationZ(); 23059 } 23060 }; 23061 23062 /** 23063 * A Property wrapper around the <code>x</code> functionality handled by the 23064 * {@link View#setX(float)} and {@link View#getX()} methods. 23065 */ 23066 public static final Property<View, Float> X = new FloatProperty<View>("x") { 23067 @Override 23068 public void setValue(View object, float value) { 23069 object.setX(value); 23070 } 23071 23072 @Override 23073 public Float get(View object) { 23074 return object.getX(); 23075 } 23076 }; 23077 23078 /** 23079 * A Property wrapper around the <code>y</code> functionality handled by the 23080 * {@link View#setY(float)} and {@link View#getY()} methods. 23081 */ 23082 public static final Property<View, Float> Y = new FloatProperty<View>("y") { 23083 @Override 23084 public void setValue(View object, float value) { 23085 object.setY(value); 23086 } 23087 23088 @Override 23089 public Float get(View object) { 23090 return object.getY(); 23091 } 23092 }; 23093 23094 /** 23095 * A Property wrapper around the <code>z</code> functionality handled by the 23096 * {@link View#setZ(float)} and {@link View#getZ()} methods. 23097 */ 23098 public static final Property<View, Float> Z = new FloatProperty<View>("z") { 23099 @Override 23100 public void setValue(View object, float value) { 23101 object.setZ(value); 23102 } 23103 23104 @Override 23105 public Float get(View object) { 23106 return object.getZ(); 23107 } 23108 }; 23109 23110 /** 23111 * A Property wrapper around the <code>rotation</code> functionality handled by the 23112 * {@link View#setRotation(float)} and {@link View#getRotation()} methods. 23113 */ 23114 public static final Property<View, Float> ROTATION = new FloatProperty<View>("rotation") { 23115 @Override 23116 public void setValue(View object, float value) { 23117 object.setRotation(value); 23118 } 23119 23120 @Override 23121 public Float get(View object) { 23122 return object.getRotation(); 23123 } 23124 }; 23125 23126 /** 23127 * A Property wrapper around the <code>rotationX</code> functionality handled by the 23128 * {@link View#setRotationX(float)} and {@link View#getRotationX()} methods. 23129 */ 23130 public static final Property<View, Float> ROTATION_X = new FloatProperty<View>("rotationX") { 23131 @Override 23132 public void setValue(View object, float value) { 23133 object.setRotationX(value); 23134 } 23135 23136 @Override 23137 public Float get(View object) { 23138 return object.getRotationX(); 23139 } 23140 }; 23141 23142 /** 23143 * A Property wrapper around the <code>rotationY</code> functionality handled by the 23144 * {@link View#setRotationY(float)} and {@link View#getRotationY()} methods. 23145 */ 23146 public static final Property<View, Float> ROTATION_Y = new FloatProperty<View>("rotationY") { 23147 @Override 23148 public void setValue(View object, float value) { 23149 object.setRotationY(value); 23150 } 23151 23152 @Override 23153 public Float get(View object) { 23154 return object.getRotationY(); 23155 } 23156 }; 23157 23158 /** 23159 * A Property wrapper around the <code>scaleX</code> functionality handled by the 23160 * {@link View#setScaleX(float)} and {@link View#getScaleX()} methods. 23161 */ 23162 public static final Property<View, Float> SCALE_X = new FloatProperty<View>("scaleX") { 23163 @Override 23164 public void setValue(View object, float value) { 23165 object.setScaleX(value); 23166 } 23167 23168 @Override 23169 public Float get(View object) { 23170 return object.getScaleX(); 23171 } 23172 }; 23173 23174 /** 23175 * A Property wrapper around the <code>scaleY</code> functionality handled by the 23176 * {@link View#setScaleY(float)} and {@link View#getScaleY()} methods. 23177 */ 23178 public static final Property<View, Float> SCALE_Y = new FloatProperty<View>("scaleY") { 23179 @Override 23180 public void setValue(View object, float value) { 23181 object.setScaleY(value); 23182 } 23183 23184 @Override 23185 public Float get(View object) { 23186 return object.getScaleY(); 23187 } 23188 }; 23189 23190 /** 23191 * A MeasureSpec encapsulates the layout requirements passed from parent to child. 23192 * Each MeasureSpec represents a requirement for either the width or the height. 23193 * A MeasureSpec is comprised of a size and a mode. There are three possible 23194 * modes: 23195 * <dl> 23196 * <dt>UNSPECIFIED</dt> 23197 * <dd> 23198 * The parent has not imposed any constraint on the child. It can be whatever size 23199 * it wants. 23200 * </dd> 23201 * 23202 * <dt>EXACTLY</dt> 23203 * <dd> 23204 * The parent has determined an exact size for the child. The child is going to be 23205 * given those bounds regardless of how big it wants to be. 23206 * </dd> 23207 * 23208 * <dt>AT_MOST</dt> 23209 * <dd> 23210 * The child can be as large as it wants up to the specified size. 23211 * </dd> 23212 * </dl> 23213 * 23214 * MeasureSpecs are implemented as ints to reduce object allocation. This class 23215 * is provided to pack and unpack the <size, mode> tuple into the int. 23216 */ 23217 public static class MeasureSpec { 23218 private static final int MODE_SHIFT = 30; 23219 private static final int MODE_MASK = 0x3 << MODE_SHIFT; 23220 23221 /** @hide */ 23222 @IntDef({UNSPECIFIED, EXACTLY, AT_MOST}) 23223 @Retention(RetentionPolicy.SOURCE) 23224 public @interface MeasureSpecMode {} 23225 23226 /** 23227 * Measure specification mode: The parent has not imposed any constraint 23228 * on the child. It can be whatever size it wants. 23229 */ 23230 public static final int UNSPECIFIED = 0 << MODE_SHIFT; 23231 23232 /** 23233 * Measure specification mode: The parent has determined an exact size 23234 * for the child. The child is going to be given those bounds regardless 23235 * of how big it wants to be. 23236 */ 23237 public static final int EXACTLY = 1 << MODE_SHIFT; 23238 23239 /** 23240 * Measure specification mode: The child can be as large as it wants up 23241 * to the specified size. 23242 */ 23243 public static final int AT_MOST = 2 << MODE_SHIFT; 23244 23245 /** 23246 * Creates a measure specification based on the supplied size and mode. 23247 * 23248 * The mode must always be one of the following: 23249 * <ul> 23250 * <li>{@link android.view.View.MeasureSpec#UNSPECIFIED}</li> 23251 * <li>{@link android.view.View.MeasureSpec#EXACTLY}</li> 23252 * <li>{@link android.view.View.MeasureSpec#AT_MOST}</li> 23253 * </ul> 23254 * 23255 * <p><strong>Note:</strong> On API level 17 and lower, makeMeasureSpec's 23256 * implementation was such that the order of arguments did not matter 23257 * and overflow in either value could impact the resulting MeasureSpec. 23258 * {@link android.widget.RelativeLayout} was affected by this bug. 23259 * Apps targeting API levels greater than 17 will get the fixed, more strict 23260 * behavior.</p> 23261 * 23262 * @param size the size of the measure specification 23263 * @param mode the mode of the measure specification 23264 * @return the measure specification based on size and mode 23265 */ 23266 public static int makeMeasureSpec(@IntRange(from = 0, to = (1 << MeasureSpec.MODE_SHIFT) - 1) int size, 23267 @MeasureSpecMode int mode) { 23268 if (sUseBrokenMakeMeasureSpec) { 23269 return size + mode; 23270 } else { 23271 return (size & ~MODE_MASK) | (mode & MODE_MASK); 23272 } 23273 } 23274 23275 /** 23276 * Like {@link #makeMeasureSpec(int, int)}, but any spec with a mode of UNSPECIFIED 23277 * will automatically get a size of 0. Older apps expect this. 23278 * 23279 * @hide internal use only for compatibility with system widgets and older apps 23280 */ 23281 public static int makeSafeMeasureSpec(int size, int mode) { 23282 if (sUseZeroUnspecifiedMeasureSpec && mode == UNSPECIFIED) { 23283 return 0; 23284 } 23285 return makeMeasureSpec(size, mode); 23286 } 23287 23288 /** 23289 * Extracts the mode from the supplied measure specification. 23290 * 23291 * @param measureSpec the measure specification to extract the mode from 23292 * @return {@link android.view.View.MeasureSpec#UNSPECIFIED}, 23293 * {@link android.view.View.MeasureSpec#AT_MOST} or 23294 * {@link android.view.View.MeasureSpec#EXACTLY} 23295 */ 23296 @MeasureSpecMode 23297 public static int getMode(int measureSpec) { 23298 //noinspection ResourceType 23299 return (measureSpec & MODE_MASK); 23300 } 23301 23302 /** 23303 * Extracts the size from the supplied measure specification. 23304 * 23305 * @param measureSpec the measure specification to extract the size from 23306 * @return the size in pixels defined in the supplied measure specification 23307 */ 23308 public static int getSize(int measureSpec) { 23309 return (measureSpec & ~MODE_MASK); 23310 } 23311 23312 static int adjust(int measureSpec, int delta) { 23313 final int mode = getMode(measureSpec); 23314 int size = getSize(measureSpec); 23315 if (mode == UNSPECIFIED) { 23316 // No need to adjust size for UNSPECIFIED mode. 23317 return makeMeasureSpec(size, UNSPECIFIED); 23318 } 23319 size += delta; 23320 if (size < 0) { 23321 Log.e(VIEW_LOG_TAG, "MeasureSpec.adjust: new size would be negative! (" + size + 23322 ") spec: " + toString(measureSpec) + " delta: " + delta); 23323 size = 0; 23324 } 23325 return makeMeasureSpec(size, mode); 23326 } 23327 23328 /** 23329 * Returns a String representation of the specified measure 23330 * specification. 23331 * 23332 * @param measureSpec the measure specification to convert to a String 23333 * @return a String with the following format: "MeasureSpec: MODE SIZE" 23334 */ 23335 public static String toString(int measureSpec) { 23336 int mode = getMode(measureSpec); 23337 int size = getSize(measureSpec); 23338 23339 StringBuilder sb = new StringBuilder("MeasureSpec: "); 23340 23341 if (mode == UNSPECIFIED) 23342 sb.append("UNSPECIFIED "); 23343 else if (mode == EXACTLY) 23344 sb.append("EXACTLY "); 23345 else if (mode == AT_MOST) 23346 sb.append("AT_MOST "); 23347 else 23348 sb.append(mode).append(" "); 23349 23350 sb.append(size); 23351 return sb.toString(); 23352 } 23353 } 23354 23355 private final class CheckForLongPress implements Runnable { 23356 private int mOriginalWindowAttachCount; 23357 private float mX; 23358 private float mY; 23359 private boolean mOriginalPressedState; 23360 23361 @Override 23362 public void run() { 23363 if ((mOriginalPressedState == isPressed()) && (mParent != null) 23364 && mOriginalWindowAttachCount == mWindowAttachCount) { 23365 if (performLongClick(mX, mY)) { 23366 mHasPerformedLongPress = true; 23367 } 23368 } 23369 } 23370 23371 public void setAnchor(float x, float y) { 23372 mX = x; 23373 mY = y; 23374 } 23375 23376 public void rememberWindowAttachCount() { 23377 mOriginalWindowAttachCount = mWindowAttachCount; 23378 } 23379 23380 public void rememberPressedState() { 23381 mOriginalPressedState = isPressed(); 23382 } 23383 } 23384 23385 private final class CheckForTap implements Runnable { 23386 public float x; 23387 public float y; 23388 23389 @Override 23390 public void run() { 23391 mPrivateFlags &= ~PFLAG_PREPRESSED; 23392 setPressed(true, x, y); 23393 checkForLongClick(ViewConfiguration.getTapTimeout(), x, y); 23394 } 23395 } 23396 23397 private final class PerformClick implements Runnable { 23398 @Override 23399 public void run() { 23400 performClick(); 23401 } 23402 } 23403 23404 /** 23405 * This method returns a ViewPropertyAnimator object, which can be used to animate 23406 * specific properties on this View. 23407 * 23408 * @return ViewPropertyAnimator The ViewPropertyAnimator associated with this View. 23409 */ 23410 public ViewPropertyAnimator animate() { 23411 if (mAnimator == null) { 23412 mAnimator = new ViewPropertyAnimator(this); 23413 } 23414 return mAnimator; 23415 } 23416 23417 /** 23418 * Sets the name of the View to be used to identify Views in Transitions. 23419 * Names should be unique in the View hierarchy. 23420 * 23421 * @param transitionName The name of the View to uniquely identify it for Transitions. 23422 */ 23423 public final void setTransitionName(String transitionName) { 23424 mTransitionName = transitionName; 23425 } 23426 23427 /** 23428 * Returns the name of the View to be used to identify Views in Transitions. 23429 * Names should be unique in the View hierarchy. 23430 * 23431 * <p>This returns null if the View has not been given a name.</p> 23432 * 23433 * @return The name used of the View to be used to identify Views in Transitions or null 23434 * if no name has been given. 23435 */ 23436 @ViewDebug.ExportedProperty 23437 public String getTransitionName() { 23438 return mTransitionName; 23439 } 23440 23441 /** 23442 * @hide 23443 */ 23444 public void requestKeyboardShortcuts(List<KeyboardShortcutGroup> data, int deviceId) { 23445 // Do nothing. 23446 } 23447 23448 /** 23449 * Interface definition for a callback to be invoked when a hardware key event is 23450 * dispatched to this view. The callback will be invoked before the key event is 23451 * given to the view. This is only useful for hardware keyboards; a software input 23452 * method has no obligation to trigger this listener. 23453 */ 23454 public interface OnKeyListener { 23455 /** 23456 * Called when a hardware key is dispatched to a view. This allows listeners to 23457 * get a chance to respond before the target view. 23458 * <p>Key presses in software keyboards will generally NOT trigger this method, 23459 * although some may elect to do so in some situations. Do not assume a 23460 * software input method has to be key-based; even if it is, it may use key presses 23461 * in a different way than you expect, so there is no way to reliably catch soft 23462 * input key presses. 23463 * 23464 * @param v The view the key has been dispatched to. 23465 * @param keyCode The code for the physical key that was pressed 23466 * @param event The KeyEvent object containing full information about 23467 * the event. 23468 * @return True if the listener has consumed the event, false otherwise. 23469 */ 23470 boolean onKey(View v, int keyCode, KeyEvent event); 23471 } 23472 23473 /** 23474 * Interface definition for a callback to be invoked when a touch event is 23475 * dispatched to this view. The callback will be invoked before the touch 23476 * event is given to the view. 23477 */ 23478 public interface OnTouchListener { 23479 /** 23480 * Called when a touch event is dispatched to a view. This allows listeners to 23481 * get a chance to respond before the target view. 23482 * 23483 * @param v The view the touch event has been dispatched to. 23484 * @param event The MotionEvent object containing full information about 23485 * the event. 23486 * @return True if the listener has consumed the event, false otherwise. 23487 */ 23488 boolean onTouch(View v, MotionEvent event); 23489 } 23490 23491 /** 23492 * Interface definition for a callback to be invoked when a hover event is 23493 * dispatched to this view. The callback will be invoked before the hover 23494 * event is given to the view. 23495 */ 23496 public interface OnHoverListener { 23497 /** 23498 * Called when a hover event is dispatched to a view. This allows listeners to 23499 * get a chance to respond before the target view. 23500 * 23501 * @param v The view the hover event has been dispatched to. 23502 * @param event The MotionEvent object containing full information about 23503 * the event. 23504 * @return True if the listener has consumed the event, false otherwise. 23505 */ 23506 boolean onHover(View v, MotionEvent event); 23507 } 23508 23509 /** 23510 * Interface definition for a callback to be invoked when a generic motion event is 23511 * dispatched to this view. The callback will be invoked before the generic motion 23512 * event is given to the view. 23513 */ 23514 public interface OnGenericMotionListener { 23515 /** 23516 * Called when a generic motion event is dispatched to a view. This allows listeners to 23517 * get a chance to respond before the target view. 23518 * 23519 * @param v The view the generic motion event has been dispatched to. 23520 * @param event The MotionEvent object containing full information about 23521 * the event. 23522 * @return True if the listener has consumed the event, false otherwise. 23523 */ 23524 boolean onGenericMotion(View v, MotionEvent event); 23525 } 23526 23527 /** 23528 * Interface definition for a callback to be invoked when a view has been clicked and held. 23529 */ 23530 public interface OnLongClickListener { 23531 /** 23532 * Called when a view has been clicked and held. 23533 * 23534 * @param v The view that was clicked and held. 23535 * 23536 * @return true if the callback consumed the long click, false otherwise. 23537 */ 23538 boolean onLongClick(View v); 23539 } 23540 23541 /** 23542 * Interface definition for a callback to be invoked when a drag is being dispatched 23543 * to this view. The callback will be invoked before the hosting view's own 23544 * onDrag(event) method. If the listener wants to fall back to the hosting view's 23545 * onDrag(event) behavior, it should return 'false' from this callback. 23546 * 23547 * <div class="special reference"> 23548 * <h3>Developer Guides</h3> 23549 * <p>For a guide to implementing drag and drop features, read the 23550 * <a href="{@docRoot}guide/topics/ui/drag-drop.html">Drag and Drop</a> developer guide.</p> 23551 * </div> 23552 */ 23553 public interface OnDragListener { 23554 /** 23555 * Called when a drag event is dispatched to a view. This allows listeners 23556 * to get a chance to override base View behavior. 23557 * 23558 * @param v The View that received the drag event. 23559 * @param event The {@link android.view.DragEvent} object for the drag event. 23560 * @return {@code true} if the drag event was handled successfully, or {@code false} 23561 * if the drag event was not handled. Note that {@code false} will trigger the View 23562 * to call its {@link #onDragEvent(DragEvent) onDragEvent()} handler. 23563 */ 23564 boolean onDrag(View v, DragEvent event); 23565 } 23566 23567 /** 23568 * Interface definition for a callback to be invoked when the focus state of 23569 * a view changed. 23570 */ 23571 public interface OnFocusChangeListener { 23572 /** 23573 * Called when the focus state of a view has changed. 23574 * 23575 * @param v The view whose state has changed. 23576 * @param hasFocus The new focus state of v. 23577 */ 23578 void onFocusChange(View v, boolean hasFocus); 23579 } 23580 23581 /** 23582 * Interface definition for a callback to be invoked when a view is clicked. 23583 */ 23584 public interface OnClickListener { 23585 /** 23586 * Called when a view has been clicked. 23587 * 23588 * @param v The view that was clicked. 23589 */ 23590 void onClick(View v); 23591 } 23592 23593 /** 23594 * Interface definition for a callback to be invoked when a view is context clicked. 23595 */ 23596 public interface OnContextClickListener { 23597 /** 23598 * Called when a view is context clicked. 23599 * 23600 * @param v The view that has been context clicked. 23601 * @return true if the callback consumed the context click, false otherwise. 23602 */ 23603 boolean onContextClick(View v); 23604 } 23605 23606 /** 23607 * Interface definition for a callback to be invoked when the context menu 23608 * for this view is being built. 23609 */ 23610 public interface OnCreateContextMenuListener { 23611 /** 23612 * Called when the context menu for this view is being built. It is not 23613 * safe to hold onto the menu after this method returns. 23614 * 23615 * @param menu The context menu that is being built 23616 * @param v The view for which the context menu is being built 23617 * @param menuInfo Extra information about the item for which the 23618 * context menu should be shown. This information will vary 23619 * depending on the class of v. 23620 */ 23621 void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo); 23622 } 23623 23624 /** 23625 * Interface definition for a callback to be invoked when the status bar changes 23626 * visibility. This reports <strong>global</strong> changes to the system UI 23627 * state, not what the application is requesting. 23628 * 23629 * @see View#setOnSystemUiVisibilityChangeListener(android.view.View.OnSystemUiVisibilityChangeListener) 23630 */ 23631 public interface OnSystemUiVisibilityChangeListener { 23632 /** 23633 * Called when the status bar changes visibility because of a call to 23634 * {@link View#setSystemUiVisibility(int)}. 23635 * 23636 * @param visibility Bitwise-or of flags {@link #SYSTEM_UI_FLAG_LOW_PROFILE}, 23637 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, and {@link #SYSTEM_UI_FLAG_FULLSCREEN}. 23638 * This tells you the <strong>global</strong> state of these UI visibility 23639 * flags, not what your app is currently applying. 23640 */ 23641 public void onSystemUiVisibilityChange(int visibility); 23642 } 23643 23644 /** 23645 * Interface definition for a callback to be invoked when this view is attached 23646 * or detached from its window. 23647 */ 23648 public interface OnAttachStateChangeListener { 23649 /** 23650 * Called when the view is attached to a window. 23651 * @param v The view that was attached 23652 */ 23653 public void onViewAttachedToWindow(View v); 23654 /** 23655 * Called when the view is detached from a window. 23656 * @param v The view that was detached 23657 */ 23658 public void onViewDetachedFromWindow(View v); 23659 } 23660 23661 /** 23662 * Listener for applying window insets on a view in a custom way. 23663 * 23664 * <p>Apps may choose to implement this interface if they want to apply custom policy 23665 * to the way that window insets are treated for a view. If an OnApplyWindowInsetsListener 23666 * is set, its 23667 * {@link OnApplyWindowInsetsListener#onApplyWindowInsets(View, WindowInsets) onApplyWindowInsets} 23668 * method will be called instead of the View's own 23669 * {@link #onApplyWindowInsets(WindowInsets) onApplyWindowInsets} method. The listener 23670 * may optionally call the parameter View's <code>onApplyWindowInsets</code> method to apply 23671 * the View's normal behavior as part of its own.</p> 23672 */ 23673 public interface OnApplyWindowInsetsListener { 23674 /** 23675 * When {@link View#setOnApplyWindowInsetsListener(View.OnApplyWindowInsetsListener) set} 23676 * on a View, this listener method will be called instead of the view's own 23677 * {@link View#onApplyWindowInsets(WindowInsets) onApplyWindowInsets} method. 23678 * 23679 * @param v The view applying window insets 23680 * @param insets The insets to apply 23681 * @return The insets supplied, minus any insets that were consumed 23682 */ 23683 public WindowInsets onApplyWindowInsets(View v, WindowInsets insets); 23684 } 23685 23686 private final class UnsetPressedState implements Runnable { 23687 @Override 23688 public void run() { 23689 setPressed(false); 23690 } 23691 } 23692 23693 /** 23694 * Base class for derived classes that want to save and restore their own 23695 * state in {@link android.view.View#onSaveInstanceState()}. 23696 */ 23697 public static class BaseSavedState extends AbsSavedState { 23698 String mStartActivityRequestWhoSaved; 23699 23700 /** 23701 * Constructor used when reading from a parcel. Reads the state of the superclass. 23702 * 23703 * @param source parcel to read from 23704 */ 23705 public BaseSavedState(Parcel source) { 23706 this(source, null); 23707 } 23708 23709 /** 23710 * Constructor used when reading from a parcel using a given class loader. 23711 * Reads the state of the superclass. 23712 * 23713 * @param source parcel to read from 23714 * @param loader ClassLoader to use for reading 23715 */ 23716 public BaseSavedState(Parcel source, ClassLoader loader) { 23717 super(source, loader); 23718 mStartActivityRequestWhoSaved = source.readString(); 23719 } 23720 23721 /** 23722 * Constructor called by derived classes when creating their SavedState objects 23723 * 23724 * @param superState The state of the superclass of this view 23725 */ 23726 public BaseSavedState(Parcelable superState) { 23727 super(superState); 23728 } 23729 23730 @Override 23731 public void writeToParcel(Parcel out, int flags) { 23732 super.writeToParcel(out, flags); 23733 out.writeString(mStartActivityRequestWhoSaved); 23734 } 23735 23736 public static final Parcelable.Creator<BaseSavedState> CREATOR 23737 = new Parcelable.ClassLoaderCreator<BaseSavedState>() { 23738 @Override 23739 public BaseSavedState createFromParcel(Parcel in) { 23740 return new BaseSavedState(in); 23741 } 23742 23743 @Override 23744 public BaseSavedState createFromParcel(Parcel in, ClassLoader loader) { 23745 return new BaseSavedState(in, loader); 23746 } 23747 23748 @Override 23749 public BaseSavedState[] newArray(int size) { 23750 return new BaseSavedState[size]; 23751 } 23752 }; 23753 } 23754 23755 /** 23756 * A set of information given to a view when it is attached to its parent 23757 * window. 23758 */ 23759 final static class AttachInfo { 23760 interface Callbacks { 23761 void playSoundEffect(int effectId); 23762 boolean performHapticFeedback(int effectId, boolean always); 23763 } 23764 23765 /** 23766 * InvalidateInfo is used to post invalidate(int, int, int, int) messages 23767 * to a Handler. This class contains the target (View) to invalidate and 23768 * the coordinates of the dirty rectangle. 23769 * 23770 * For performance purposes, this class also implements a pool of up to 23771 * POOL_LIMIT objects that get reused. This reduces memory allocations 23772 * whenever possible. 23773 */ 23774 static class InvalidateInfo { 23775 private static final int POOL_LIMIT = 10; 23776 23777 private static final SynchronizedPool<InvalidateInfo> sPool = 23778 new SynchronizedPool<InvalidateInfo>(POOL_LIMIT); 23779 23780 View target; 23781 23782 int left; 23783 int top; 23784 int right; 23785 int bottom; 23786 23787 public static InvalidateInfo obtain() { 23788 InvalidateInfo instance = sPool.acquire(); 23789 return (instance != null) ? instance : new InvalidateInfo(); 23790 } 23791 23792 public void recycle() { 23793 target = null; 23794 sPool.release(this); 23795 } 23796 } 23797 23798 final IWindowSession mSession; 23799 23800 final IWindow mWindow; 23801 23802 final IBinder mWindowToken; 23803 23804 Display mDisplay; 23805 23806 final Callbacks mRootCallbacks; 23807 23808 IWindowId mIWindowId; 23809 WindowId mWindowId; 23810 23811 /** 23812 * The top view of the hierarchy. 23813 */ 23814 View mRootView; 23815 23816 IBinder mPanelParentWindowToken; 23817 23818 boolean mHardwareAccelerated; 23819 boolean mHardwareAccelerationRequested; 23820 ThreadedRenderer mThreadedRenderer; 23821 List<RenderNode> mPendingAnimatingRenderNodes; 23822 23823 /** 23824 * The state of the display to which the window is attached, as reported 23825 * by {@link Display#getState()}. Note that the display state constants 23826 * declared by {@link Display} do not exactly line up with the screen state 23827 * constants declared by {@link View} (there are more display states than 23828 * screen states). 23829 */ 23830 int mDisplayState = Display.STATE_UNKNOWN; 23831 23832 /** 23833 * Scale factor used by the compatibility mode 23834 */ 23835 float mApplicationScale; 23836 23837 /** 23838 * Indicates whether the application is in compatibility mode 23839 */ 23840 boolean mScalingRequired; 23841 23842 /** 23843 * Left position of this view's window 23844 */ 23845 int mWindowLeft; 23846 23847 /** 23848 * Top position of this view's window 23849 */ 23850 int mWindowTop; 23851 23852 /** 23853 * Indicates whether views need to use 32-bit drawing caches 23854 */ 23855 boolean mUse32BitDrawingCache; 23856 23857 /** 23858 * For windows that are full-screen but using insets to layout inside 23859 * of the screen areas, these are the current insets to appear inside 23860 * the overscan area of the display. 23861 */ 23862 final Rect mOverscanInsets = new Rect(); 23863 23864 /** 23865 * For windows that are full-screen but using insets to layout inside 23866 * of the screen decorations, these are the current insets for the 23867 * content of the window. 23868 */ 23869 final Rect mContentInsets = new Rect(); 23870 23871 /** 23872 * For windows that are full-screen but using insets to layout inside 23873 * of the screen decorations, these are the current insets for the 23874 * actual visible parts of the window. 23875 */ 23876 final Rect mVisibleInsets = new Rect(); 23877 23878 /** 23879 * For windows that are full-screen but using insets to layout inside 23880 * of the screen decorations, these are the current insets for the 23881 * stable system windows. 23882 */ 23883 final Rect mStableInsets = new Rect(); 23884 23885 /** 23886 * For windows that include areas that are not covered by real surface these are the outsets 23887 * for real surface. 23888 */ 23889 final Rect mOutsets = new Rect(); 23890 23891 /** 23892 * In multi-window we force show the navigation bar. Because we don't want that the surface 23893 * size changes in this mode, we instead have a flag whether the navigation bar size should 23894 * always be consumed, so the app is treated like there is no virtual navigation bar at all. 23895 */ 23896 boolean mAlwaysConsumeNavBar; 23897 23898 /** 23899 * The internal insets given by this window. This value is 23900 * supplied by the client (through 23901 * {@link ViewTreeObserver.OnComputeInternalInsetsListener}) and will 23902 * be given to the window manager when changed to be used in laying 23903 * out windows behind it. 23904 */ 23905 final ViewTreeObserver.InternalInsetsInfo mGivenInternalInsets 23906 = new ViewTreeObserver.InternalInsetsInfo(); 23907 23908 /** 23909 * Set to true when mGivenInternalInsets is non-empty. 23910 */ 23911 boolean mHasNonEmptyGivenInternalInsets; 23912 23913 /** 23914 * All views in the window's hierarchy that serve as scroll containers, 23915 * used to determine if the window can be resized or must be panned 23916 * to adjust for a soft input area. 23917 */ 23918 final ArrayList<View> mScrollContainers = new ArrayList<View>(); 23919 23920 final KeyEvent.DispatcherState mKeyDispatchState 23921 = new KeyEvent.DispatcherState(); 23922 23923 /** 23924 * Indicates whether the view's window currently has the focus. 23925 */ 23926 boolean mHasWindowFocus; 23927 23928 /** 23929 * The current visibility of the window. 23930 */ 23931 int mWindowVisibility; 23932 23933 /** 23934 * Indicates the time at which drawing started to occur. 23935 */ 23936 long mDrawingTime; 23937 23938 /** 23939 * Indicates whether or not ignoring the DIRTY_MASK flags. 23940 */ 23941 boolean mIgnoreDirtyState; 23942 23943 /** 23944 * This flag tracks when the mIgnoreDirtyState flag is set during draw(), 23945 * to avoid clearing that flag prematurely. 23946 */ 23947 boolean mSetIgnoreDirtyState = false; 23948 23949 /** 23950 * Indicates whether the view's window is currently in touch mode. 23951 */ 23952 boolean mInTouchMode; 23953 23954 /** 23955 * Indicates whether the view has requested unbuffered input dispatching for the current 23956 * event stream. 23957 */ 23958 boolean mUnbufferedDispatchRequested; 23959 23960 /** 23961 * Indicates that ViewAncestor should trigger a global layout change 23962 * the next time it performs a traversal 23963 */ 23964 boolean mRecomputeGlobalAttributes; 23965 23966 /** 23967 * Always report new attributes at next traversal. 23968 */ 23969 boolean mForceReportNewAttributes; 23970 23971 /** 23972 * Set during a traveral if any views want to keep the screen on. 23973 */ 23974 boolean mKeepScreenOn; 23975 23976 /** 23977 * Set during a traveral if the light center needs to be updated. 23978 */ 23979 boolean mNeedsUpdateLightCenter; 23980 23981 /** 23982 * Bitwise-or of all of the values that views have passed to setSystemUiVisibility(). 23983 */ 23984 int mSystemUiVisibility; 23985 23986 /** 23987 * Hack to force certain system UI visibility flags to be cleared. 23988 */ 23989 int mDisabledSystemUiVisibility; 23990 23991 /** 23992 * Last global system UI visibility reported by the window manager. 23993 */ 23994 int mGlobalSystemUiVisibility = -1; 23995 23996 /** 23997 * True if a view in this hierarchy has an OnSystemUiVisibilityChangeListener 23998 * attached. 23999 */ 24000 boolean mHasSystemUiListeners; 24001 24002 /** 24003 * Set if the window has requested to extend into the overscan region 24004 * via WindowManager.LayoutParams.FLAG_LAYOUT_IN_OVERSCAN. 24005 */ 24006 boolean mOverscanRequested; 24007 24008 /** 24009 * Set if the visibility of any views has changed. 24010 */ 24011 boolean mViewVisibilityChanged; 24012 24013 /** 24014 * Set to true if a view has been scrolled. 24015 */ 24016 boolean mViewScrollChanged; 24017 24018 /** 24019 * Set to true if high contrast mode enabled 24020 */ 24021 boolean mHighContrastText; 24022 24023 /** 24024 * Set to true if a pointer event is currently being handled. 24025 */ 24026 boolean mHandlingPointerEvent; 24027 24028 /** 24029 * Global to the view hierarchy used as a temporary for dealing with 24030 * x/y points in the transparent region computations. 24031 */ 24032 final int[] mTransparentLocation = new int[2]; 24033 24034 /** 24035 * Global to the view hierarchy used as a temporary for dealing with 24036 * x/y points in the ViewGroup.invalidateChild implementation. 24037 */ 24038 final int[] mInvalidateChildLocation = new int[2]; 24039 24040 /** 24041 * Global to the view hierarchy used as a temporary for dealing with 24042 * computing absolute on-screen location. 24043 */ 24044 final int[] mTmpLocation = new int[2]; 24045 24046 /** 24047 * Global to the view hierarchy used as a temporary for dealing with 24048 * x/y location when view is transformed. 24049 */ 24050 final float[] mTmpTransformLocation = new float[2]; 24051 24052 /** 24053 * The view tree observer used to dispatch global events like 24054 * layout, pre-draw, touch mode change, etc. 24055 */ 24056 final ViewTreeObserver mTreeObserver; 24057 24058 /** 24059 * A Canvas used by the view hierarchy to perform bitmap caching. 24060 */ 24061 Canvas mCanvas; 24062 24063 /** 24064 * The view root impl. 24065 */ 24066 final ViewRootImpl mViewRootImpl; 24067 24068 /** 24069 * A Handler supplied by a view's {@link android.view.ViewRootImpl}. This 24070 * handler can be used to pump events in the UI events queue. 24071 */ 24072 final Handler mHandler; 24073 24074 /** 24075 * Temporary for use in computing invalidate rectangles while 24076 * calling up the hierarchy. 24077 */ 24078 final Rect mTmpInvalRect = new Rect(); 24079 24080 /** 24081 * Temporary for use in computing hit areas with transformed views 24082 */ 24083 final RectF mTmpTransformRect = new RectF(); 24084 24085 /** 24086 * Temporary for use in computing hit areas with transformed views 24087 */ 24088 final RectF mTmpTransformRect1 = new RectF(); 24089 24090 /** 24091 * Temporary list of rectanges. 24092 */ 24093 final List<RectF> mTmpRectList = new ArrayList<>(); 24094 24095 /** 24096 * Temporary for use in transforming invalidation rect 24097 */ 24098 final Matrix mTmpMatrix = new Matrix(); 24099 24100 /** 24101 * Temporary for use in transforming invalidation rect 24102 */ 24103 final Transformation mTmpTransformation = new Transformation(); 24104 24105 /** 24106 * Temporary for use in querying outlines from OutlineProviders 24107 */ 24108 final Outline mTmpOutline = new Outline(); 24109 24110 /** 24111 * Temporary list for use in collecting focusable descendents of a view. 24112 */ 24113 final ArrayList<View> mTempArrayList = new ArrayList<View>(24); 24114 24115 /** 24116 * The id of the window for accessibility purposes. 24117 */ 24118 int mAccessibilityWindowId = AccessibilityNodeInfo.UNDEFINED_ITEM_ID; 24119 24120 /** 24121 * Flags related to accessibility processing. 24122 * 24123 * @see AccessibilityNodeInfo#FLAG_INCLUDE_NOT_IMPORTANT_VIEWS 24124 * @see AccessibilityNodeInfo#FLAG_REPORT_VIEW_IDS 24125 */ 24126 int mAccessibilityFetchFlags; 24127 24128 /** 24129 * The drawable for highlighting accessibility focus. 24130 */ 24131 Drawable mAccessibilityFocusDrawable; 24132 24133 /** 24134 * Show where the margins, bounds and layout bounds are for each view. 24135 */ 24136 boolean mDebugLayout = SystemProperties.getBoolean(DEBUG_LAYOUT_PROPERTY, false); 24137 24138 /** 24139 * Point used to compute visible regions. 24140 */ 24141 final Point mPoint = new Point(); 24142 24143 /** 24144 * Used to track which View originated a requestLayout() call, used when 24145 * requestLayout() is called during layout. 24146 */ 24147 View mViewRequestingLayout; 24148 24149 /** 24150 * Used to track views that need (at least) a partial relayout at their current size 24151 * during the next traversal. 24152 */ 24153 List<View> mPartialLayoutViews = new ArrayList<>(); 24154 24155 /** 24156 * Swapped with mPartialLayoutViews during layout to avoid concurrent 24157 * modification. Lazily assigned during ViewRootImpl layout. 24158 */ 24159 List<View> mEmptyPartialLayoutViews; 24160 24161 /** 24162 * Used to track the identity of the current drag operation. 24163 */ 24164 IBinder mDragToken; 24165 24166 /** 24167 * The drag shadow surface for the current drag operation. 24168 */ 24169 public Surface mDragSurface; 24170 24171 24172 /** 24173 * The view that currently has a tooltip displayed. 24174 */ 24175 View mTooltipHost; 24176 24177 /** 24178 * Creates a new set of attachment information with the specified 24179 * events handler and thread. 24180 * 24181 * @param handler the events handler the view must use 24182 */ 24183 AttachInfo(IWindowSession session, IWindow window, Display display, 24184 ViewRootImpl viewRootImpl, Handler handler, Callbacks effectPlayer, 24185 Context context) { 24186 mSession = session; 24187 mWindow = window; 24188 mWindowToken = window.asBinder(); 24189 mDisplay = display; 24190 mViewRootImpl = viewRootImpl; 24191 mHandler = handler; 24192 mRootCallbacks = effectPlayer; 24193 mTreeObserver = new ViewTreeObserver(context); 24194 } 24195 } 24196 24197 /** 24198 * <p>ScrollabilityCache holds various fields used by a View when scrolling 24199 * is supported. This avoids keeping too many unused fields in most 24200 * instances of View.</p> 24201 */ 24202 private static class ScrollabilityCache implements Runnable { 24203 24204 /** 24205 * Scrollbars are not visible 24206 */ 24207 public static final int OFF = 0; 24208 24209 /** 24210 * Scrollbars are visible 24211 */ 24212 public static final int ON = 1; 24213 24214 /** 24215 * Scrollbars are fading away 24216 */ 24217 public static final int FADING = 2; 24218 24219 public boolean fadeScrollBars; 24220 24221 public int fadingEdgeLength; 24222 public int scrollBarDefaultDelayBeforeFade; 24223 public int scrollBarFadeDuration; 24224 24225 public int scrollBarSize; 24226 public int scrollBarMinTouchTarget; 24227 public ScrollBarDrawable scrollBar; 24228 public float[] interpolatorValues; 24229 public View host; 24230 24231 public final Paint paint; 24232 public final Matrix matrix; 24233 public Shader shader; 24234 24235 public final Interpolator scrollBarInterpolator = new Interpolator(1, 2); 24236 24237 private static final float[] OPAQUE = { 255 }; 24238 private static final float[] TRANSPARENT = { 0.0f }; 24239 24240 /** 24241 * When fading should start. This time moves into the future every time 24242 * a new scroll happens. Measured based on SystemClock.uptimeMillis() 24243 */ 24244 public long fadeStartTime; 24245 24246 24247 /** 24248 * The current state of the scrollbars: ON, OFF, or FADING 24249 */ 24250 public int state = OFF; 24251 24252 private int mLastColor; 24253 24254 public final Rect mScrollBarBounds = new Rect(); 24255 public final Rect mScrollBarTouchBounds = new Rect(); 24256 24257 public static final int NOT_DRAGGING = 0; 24258 public static final int DRAGGING_VERTICAL_SCROLL_BAR = 1; 24259 public static final int DRAGGING_HORIZONTAL_SCROLL_BAR = 2; 24260 public int mScrollBarDraggingState = NOT_DRAGGING; 24261 24262 public float mScrollBarDraggingPos = 0; 24263 24264 public ScrollabilityCache(ViewConfiguration configuration, View host) { 24265 fadingEdgeLength = configuration.getScaledFadingEdgeLength(); 24266 scrollBarSize = configuration.getScaledScrollBarSize(); 24267 scrollBarMinTouchTarget = configuration.getScaledMinScrollbarTouchTarget(); 24268 scrollBarDefaultDelayBeforeFade = ViewConfiguration.getScrollDefaultDelay(); 24269 scrollBarFadeDuration = ViewConfiguration.getScrollBarFadeDuration(); 24270 24271 paint = new Paint(); 24272 matrix = new Matrix(); 24273 // use use a height of 1, and then wack the matrix each time we 24274 // actually use it. 24275 shader = new LinearGradient(0, 0, 0, 1, 0xFF000000, 0, Shader.TileMode.CLAMP); 24276 paint.setShader(shader); 24277 paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); 24278 24279 this.host = host; 24280 } 24281 24282 public void setFadeColor(int color) { 24283 if (color != mLastColor) { 24284 mLastColor = color; 24285 24286 if (color != 0) { 24287 shader = new LinearGradient(0, 0, 0, 1, color | 0xFF000000, 24288 color & 0x00FFFFFF, Shader.TileMode.CLAMP); 24289 paint.setShader(shader); 24290 // Restore the default transfer mode (src_over) 24291 paint.setXfermode(null); 24292 } else { 24293 shader = new LinearGradient(0, 0, 0, 1, 0xFF000000, 0, Shader.TileMode.CLAMP); 24294 paint.setShader(shader); 24295 paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); 24296 } 24297 } 24298 } 24299 24300 public void run() { 24301 long now = AnimationUtils.currentAnimationTimeMillis(); 24302 if (now >= fadeStartTime) { 24303 24304 // the animation fades the scrollbars out by changing 24305 // the opacity (alpha) from fully opaque to fully 24306 // transparent 24307 int nextFrame = (int) now; 24308 int framesCount = 0; 24309 24310 Interpolator interpolator = scrollBarInterpolator; 24311 24312 // Start opaque 24313 interpolator.setKeyFrame(framesCount++, nextFrame, OPAQUE); 24314 24315 // End transparent 24316 nextFrame += scrollBarFadeDuration; 24317 interpolator.setKeyFrame(framesCount, nextFrame, TRANSPARENT); 24318 24319 state = FADING; 24320 24321 // Kick off the fade animation 24322 host.invalidate(true); 24323 } 24324 } 24325 } 24326 24327 /** 24328 * Resuable callback for sending 24329 * {@link AccessibilityEvent#TYPE_VIEW_SCROLLED} accessibility event. 24330 */ 24331 private class SendViewScrolledAccessibilityEvent implements Runnable { 24332 public volatile boolean mIsPending; 24333 24334 public void run() { 24335 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SCROLLED); 24336 mIsPending = false; 24337 } 24338 } 24339 24340 /** 24341 * <p> 24342 * This class represents a delegate that can be registered in a {@link View} 24343 * to enhance accessibility support via composition rather via inheritance. 24344 * It is specifically targeted to widget developers that extend basic View 24345 * classes i.e. classes in package android.view, that would like their 24346 * applications to be backwards compatible. 24347 * </p> 24348 * <div class="special reference"> 24349 * <h3>Developer Guides</h3> 24350 * <p>For more information about making applications accessible, read the 24351 * <a href="{@docRoot}guide/topics/ui/accessibility/index.html">Accessibility</a> 24352 * developer guide.</p> 24353 * </div> 24354 * <p> 24355 * A scenario in which a developer would like to use an accessibility delegate 24356 * is overriding a method introduced in a later API version than the minimal API 24357 * version supported by the application. For example, the method 24358 * {@link View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} is not available 24359 * in API version 4 when the accessibility APIs were first introduced. If a 24360 * developer would like his application to run on API version 4 devices (assuming 24361 * all other APIs used by the application are version 4 or lower) and take advantage 24362 * of this method, instead of overriding the method which would break the application's 24363 * backwards compatibility, he can override the corresponding method in this 24364 * delegate and register the delegate in the target View if the API version of 24365 * the system is high enough, i.e. the API version is the same as or higher than the API 24366 * version that introduced 24367 * {@link View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)}. 24368 * </p> 24369 * <p> 24370 * Here is an example implementation: 24371 * </p> 24372 * <code><pre><p> 24373 * if (Build.VERSION.SDK_INT >= 14) { 24374 * // If the API version is equal of higher than the version in 24375 * // which onInitializeAccessibilityNodeInfo was introduced we 24376 * // register a delegate with a customized implementation. 24377 * View view = findViewById(R.id.view_id); 24378 * view.setAccessibilityDelegate(new AccessibilityDelegate() { 24379 * public void onInitializeAccessibilityNodeInfo(View host, 24380 * AccessibilityNodeInfo info) { 24381 * // Let the default implementation populate the info. 24382 * super.onInitializeAccessibilityNodeInfo(host, info); 24383 * // Set some other information. 24384 * info.setEnabled(host.isEnabled()); 24385 * } 24386 * }); 24387 * } 24388 * </code></pre></p> 24389 * <p> 24390 * This delegate contains methods that correspond to the accessibility methods 24391 * in View. If a delegate has been specified the implementation in View hands 24392 * off handling to the corresponding method in this delegate. The default 24393 * implementation the delegate methods behaves exactly as the corresponding 24394 * method in View for the case of no accessibility delegate been set. Hence, 24395 * to customize the behavior of a View method, clients can override only the 24396 * corresponding delegate method without altering the behavior of the rest 24397 * accessibility related methods of the host view. 24398 * </p> 24399 * <p> 24400 * <strong>Note:</strong> On platform versions prior to 24401 * {@link android.os.Build.VERSION_CODES#M API 23}, delegate methods on 24402 * views in the {@code android.widget.*} package are called <i>before</i> 24403 * host methods. This prevents certain properties such as class name from 24404 * being modified by overriding 24405 * {@link AccessibilityDelegate#onInitializeAccessibilityNodeInfo(View, AccessibilityNodeInfo)}, 24406 * as any changes will be overwritten by the host class. 24407 * <p> 24408 * Starting in {@link android.os.Build.VERSION_CODES#M API 23}, delegate 24409 * methods are called <i>after</i> host methods, which all properties to be 24410 * modified without being overwritten by the host class. 24411 */ 24412 public static class AccessibilityDelegate { 24413 24414 /** 24415 * Sends an accessibility event of the given type. If accessibility is not 24416 * enabled this method has no effect. 24417 * <p> 24418 * The default implementation behaves as {@link View#sendAccessibilityEvent(int) 24419 * View#sendAccessibilityEvent(int)} for the case of no accessibility delegate 24420 * been set. 24421 * </p> 24422 * 24423 * @param host The View hosting the delegate. 24424 * @param eventType The type of the event to send. 24425 * 24426 * @see View#sendAccessibilityEvent(int) View#sendAccessibilityEvent(int) 24427 */ 24428 public void sendAccessibilityEvent(View host, int eventType) { 24429 host.sendAccessibilityEventInternal(eventType); 24430 } 24431 24432 /** 24433 * Performs the specified accessibility action on the view. For 24434 * possible accessibility actions look at {@link AccessibilityNodeInfo}. 24435 * <p> 24436 * The default implementation behaves as 24437 * {@link View#performAccessibilityAction(int, Bundle) 24438 * View#performAccessibilityAction(int, Bundle)} for the case of 24439 * no accessibility delegate been set. 24440 * </p> 24441 * 24442 * @param action The action to perform. 24443 * @return Whether the action was performed. 24444 * 24445 * @see View#performAccessibilityAction(int, Bundle) 24446 * View#performAccessibilityAction(int, Bundle) 24447 */ 24448 public boolean performAccessibilityAction(View host, int action, Bundle args) { 24449 return host.performAccessibilityActionInternal(action, args); 24450 } 24451 24452 /** 24453 * Sends an accessibility event. This method behaves exactly as 24454 * {@link #sendAccessibilityEvent(View, int)} but takes as an argument an 24455 * empty {@link AccessibilityEvent} and does not perform a check whether 24456 * accessibility is enabled. 24457 * <p> 24458 * The default implementation behaves as 24459 * {@link View#sendAccessibilityEventUnchecked(AccessibilityEvent) 24460 * View#sendAccessibilityEventUnchecked(AccessibilityEvent)} for 24461 * the case of no accessibility delegate been set. 24462 * </p> 24463 * 24464 * @param host The View hosting the delegate. 24465 * @param event The event to send. 24466 * 24467 * @see View#sendAccessibilityEventUnchecked(AccessibilityEvent) 24468 * View#sendAccessibilityEventUnchecked(AccessibilityEvent) 24469 */ 24470 public void sendAccessibilityEventUnchecked(View host, AccessibilityEvent event) { 24471 host.sendAccessibilityEventUncheckedInternal(event); 24472 } 24473 24474 /** 24475 * Dispatches an {@link AccessibilityEvent} to the host {@link View} first and then 24476 * to its children for adding their text content to the event. 24477 * <p> 24478 * The default implementation behaves as 24479 * {@link View#dispatchPopulateAccessibilityEvent(AccessibilityEvent) 24480 * View#dispatchPopulateAccessibilityEvent(AccessibilityEvent)} for 24481 * the case of no accessibility delegate been set. 24482 * </p> 24483 * 24484 * @param host The View hosting the delegate. 24485 * @param event The event. 24486 * @return True if the event population was completed. 24487 * 24488 * @see View#dispatchPopulateAccessibilityEvent(AccessibilityEvent) 24489 * View#dispatchPopulateAccessibilityEvent(AccessibilityEvent) 24490 */ 24491 public boolean dispatchPopulateAccessibilityEvent(View host, AccessibilityEvent event) { 24492 return host.dispatchPopulateAccessibilityEventInternal(event); 24493 } 24494 24495 /** 24496 * Gives a chance to the host View to populate the accessibility event with its 24497 * text content. 24498 * <p> 24499 * The default implementation behaves as 24500 * {@link View#onPopulateAccessibilityEvent(AccessibilityEvent) 24501 * View#onPopulateAccessibilityEvent(AccessibilityEvent)} for 24502 * the case of no accessibility delegate been set. 24503 * </p> 24504 * 24505 * @param host The View hosting the delegate. 24506 * @param event The accessibility event which to populate. 24507 * 24508 * @see View#onPopulateAccessibilityEvent(AccessibilityEvent) 24509 * View#onPopulateAccessibilityEvent(AccessibilityEvent) 24510 */ 24511 public void onPopulateAccessibilityEvent(View host, AccessibilityEvent event) { 24512 host.onPopulateAccessibilityEventInternal(event); 24513 } 24514 24515 /** 24516 * Initializes an {@link AccessibilityEvent} with information about the 24517 * the host View which is the event source. 24518 * <p> 24519 * The default implementation behaves as 24520 * {@link View#onInitializeAccessibilityEvent(AccessibilityEvent) 24521 * View#onInitializeAccessibilityEvent(AccessibilityEvent)} for 24522 * the case of no accessibility delegate been set. 24523 * </p> 24524 * 24525 * @param host The View hosting the delegate. 24526 * @param event The event to initialize. 24527 * 24528 * @see View#onInitializeAccessibilityEvent(AccessibilityEvent) 24529 * View#onInitializeAccessibilityEvent(AccessibilityEvent) 24530 */ 24531 public void onInitializeAccessibilityEvent(View host, AccessibilityEvent event) { 24532 host.onInitializeAccessibilityEventInternal(event); 24533 } 24534 24535 /** 24536 * Initializes an {@link AccessibilityNodeInfo} with information about the host view. 24537 * <p> 24538 * The default implementation behaves as 24539 * {@link View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo) 24540 * View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} for 24541 * the case of no accessibility delegate been set. 24542 * </p> 24543 * 24544 * @param host The View hosting the delegate. 24545 * @param info The instance to initialize. 24546 * 24547 * @see View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo) 24548 * View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo) 24549 */ 24550 public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) { 24551 host.onInitializeAccessibilityNodeInfoInternal(info); 24552 } 24553 24554 /** 24555 * Adds extra data to an {@link AccessibilityNodeInfo} based on an explicit request for the 24556 * additional data. 24557 * <p> 24558 * This method only needs to be implemented if the View offers to provide additional data. 24559 * </p> 24560 * <p> 24561 * The default implementation behaves as 24562 * {@link View#addExtraDataToAccessibilityNodeInfo(AccessibilityNodeInfo, int) for 24563 * the case where no accessibility delegate is set. 24564 * </p> 24565 * 24566 * @param host The View hosting the delegate. Never {@code null}. 24567 * @param info The info to which to add the extra data. Never {@code null}. 24568 * @param extraDataKey A key specifying the type of extra data to add to the info. The 24569 * extra data should be added to the {@link Bundle} returned by 24570 * the info's {@link AccessibilityNodeInfo#getExtras} method. Never 24571 * {@code null}. 24572 * @param arguments A {@link Bundle} holding any arguments relevant for this request. 24573 * May be {@code null} if the if the service provided no arguments. 24574 * 24575 * @see AccessibilityNodeInfo#setExtraAvailableData 24576 */ 24577 public void addExtraDataToAccessibilityNodeInfo(@NonNull View host, 24578 @NonNull AccessibilityNodeInfo info, @NonNull String extraDataKey, 24579 @Nullable Bundle arguments) { 24580 host.addExtraDataToAccessibilityNodeInfo(info, extraDataKey, arguments); 24581 } 24582 24583 /** 24584 * Called when a child of the host View has requested sending an 24585 * {@link AccessibilityEvent} and gives an opportunity to the parent (the host) 24586 * to augment the event. 24587 * <p> 24588 * The default implementation behaves as 24589 * {@link ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent) 24590 * ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent)} for 24591 * the case of no accessibility delegate been set. 24592 * </p> 24593 * 24594 * @param host The View hosting the delegate. 24595 * @param child The child which requests sending the event. 24596 * @param event The event to be sent. 24597 * @return True if the event should be sent 24598 * 24599 * @see ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent) 24600 * ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent) 24601 */ 24602 public boolean onRequestSendAccessibilityEvent(ViewGroup host, View child, 24603 AccessibilityEvent event) { 24604 return host.onRequestSendAccessibilityEventInternal(child, event); 24605 } 24606 24607 /** 24608 * Gets the provider for managing a virtual view hierarchy rooted at this View 24609 * and reported to {@link android.accessibilityservice.AccessibilityService}s 24610 * that explore the window content. 24611 * <p> 24612 * The default implementation behaves as 24613 * {@link View#getAccessibilityNodeProvider() View#getAccessibilityNodeProvider()} for 24614 * the case of no accessibility delegate been set. 24615 * </p> 24616 * 24617 * @return The provider. 24618 * 24619 * @see AccessibilityNodeProvider 24620 */ 24621 public AccessibilityNodeProvider getAccessibilityNodeProvider(View host) { 24622 return null; 24623 } 24624 24625 /** 24626 * Returns an {@link AccessibilityNodeInfo} representing the host view from the 24627 * point of view of an {@link android.accessibilityservice.AccessibilityService}. 24628 * This method is responsible for obtaining an accessibility node info from a 24629 * pool of reusable instances and calling 24630 * {@link #onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} on the host 24631 * view to initialize the former. 24632 * <p> 24633 * <strong>Note:</strong> The client is responsible for recycling the obtained 24634 * instance by calling {@link AccessibilityNodeInfo#recycle()} to minimize object 24635 * creation. 24636 * </p> 24637 * <p> 24638 * The default implementation behaves as 24639 * {@link View#createAccessibilityNodeInfo() View#createAccessibilityNodeInfo()} for 24640 * the case of no accessibility delegate been set. 24641 * </p> 24642 * @return A populated {@link AccessibilityNodeInfo}. 24643 * 24644 * @see AccessibilityNodeInfo 24645 * 24646 * @hide 24647 */ 24648 public AccessibilityNodeInfo createAccessibilityNodeInfo(View host) { 24649 return host.createAccessibilityNodeInfoInternal(); 24650 } 24651 } 24652 24653 private static class MatchIdPredicate implements Predicate<View> { 24654 public int mId; 24655 24656 @Override 24657 public boolean test(View view) { 24658 return (view.mID == mId); 24659 } 24660 } 24661 24662 private static class MatchLabelForPredicate implements Predicate<View> { 24663 private int mLabeledId; 24664 24665 @Override 24666 public boolean test(View view) { 24667 return (view.mLabelForId == mLabeledId); 24668 } 24669 } 24670 24671 private class SendViewStateChangedAccessibilityEvent implements Runnable { 24672 private int mChangeTypes = 0; 24673 private boolean mPosted; 24674 private boolean mPostedWithDelay; 24675 private long mLastEventTimeMillis; 24676 24677 @Override 24678 public void run() { 24679 mPosted = false; 24680 mPostedWithDelay = false; 24681 mLastEventTimeMillis = SystemClock.uptimeMillis(); 24682 if (AccessibilityManager.getInstance(mContext).isEnabled()) { 24683 final AccessibilityEvent event = AccessibilityEvent.obtain(); 24684 event.setEventType(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED); 24685 event.setContentChangeTypes(mChangeTypes); 24686 sendAccessibilityEventUnchecked(event); 24687 } 24688 mChangeTypes = 0; 24689 } 24690 24691 public void runOrPost(int changeType) { 24692 mChangeTypes |= changeType; 24693 24694 // If this is a live region or the child of a live region, collect 24695 // all events from this frame and send them on the next frame. 24696 if (inLiveRegion()) { 24697 // If we're already posted with a delay, remove that. 24698 if (mPostedWithDelay) { 24699 removeCallbacks(this); 24700 mPostedWithDelay = false; 24701 } 24702 // Only post if we're not already posted. 24703 if (!mPosted) { 24704 post(this); 24705 mPosted = true; 24706 } 24707 return; 24708 } 24709 24710 if (mPosted) { 24711 return; 24712 } 24713 24714 final long timeSinceLastMillis = SystemClock.uptimeMillis() - mLastEventTimeMillis; 24715 final long minEventIntevalMillis = 24716 ViewConfiguration.getSendRecurringAccessibilityEventsInterval(); 24717 if (timeSinceLastMillis >= minEventIntevalMillis) { 24718 removeCallbacks(this); 24719 run(); 24720 } else { 24721 postDelayed(this, minEventIntevalMillis - timeSinceLastMillis); 24722 mPostedWithDelay = true; 24723 } 24724 } 24725 } 24726 24727 private boolean inLiveRegion() { 24728 if (getAccessibilityLiveRegion() != View.ACCESSIBILITY_LIVE_REGION_NONE) { 24729 return true; 24730 } 24731 24732 ViewParent parent = getParent(); 24733 while (parent instanceof View) { 24734 if (((View) parent).getAccessibilityLiveRegion() 24735 != View.ACCESSIBILITY_LIVE_REGION_NONE) { 24736 return true; 24737 } 24738 parent = parent.getParent(); 24739 } 24740 24741 return false; 24742 } 24743 24744 /** 24745 * Dump all private flags in readable format, useful for documentation and 24746 * sanity checking. 24747 */ 24748 private static void dumpFlags() { 24749 final HashMap<String, String> found = Maps.newHashMap(); 24750 try { 24751 for (Field field : View.class.getDeclaredFields()) { 24752 final int modifiers = field.getModifiers(); 24753 if (Modifier.isStatic(modifiers) && Modifier.isFinal(modifiers)) { 24754 if (field.getType().equals(int.class)) { 24755 final int value = field.getInt(null); 24756 dumpFlag(found, field.getName(), value); 24757 } else if (field.getType().equals(int[].class)) { 24758 final int[] values = (int[]) field.get(null); 24759 for (int i = 0; i < values.length; i++) { 24760 dumpFlag(found, field.getName() + "[" + i + "]", values[i]); 24761 } 24762 } 24763 } 24764 } 24765 } catch (IllegalAccessException e) { 24766 throw new RuntimeException(e); 24767 } 24768 24769 final ArrayList<String> keys = Lists.newArrayList(); 24770 keys.addAll(found.keySet()); 24771 Collections.sort(keys); 24772 for (String key : keys) { 24773 Log.d(VIEW_LOG_TAG, found.get(key)); 24774 } 24775 } 24776 24777 private static void dumpFlag(HashMap<String, String> found, String name, int value) { 24778 // Sort flags by prefix, then by bits, always keeping unique keys 24779 final String bits = String.format("%32s", Integer.toBinaryString(value)).replace('0', ' '); 24780 final int prefix = name.indexOf('_'); 24781 final String key = (prefix > 0 ? name.substring(0, prefix) : name) + bits + name; 24782 final String output = bits + " " + name; 24783 found.put(key, output); 24784 } 24785 24786 /** {@hide} */ 24787 public void encode(@NonNull ViewHierarchyEncoder stream) { 24788 stream.beginObject(this); 24789 encodeProperties(stream); 24790 stream.endObject(); 24791 } 24792 24793 /** {@hide} */ 24794 @CallSuper 24795 protected void encodeProperties(@NonNull ViewHierarchyEncoder stream) { 24796 Object resolveId = ViewDebug.resolveId(getContext(), mID); 24797 if (resolveId instanceof String) { 24798 stream.addProperty("id", (String) resolveId); 24799 } else { 24800 stream.addProperty("id", mID); 24801 } 24802 24803 stream.addProperty("misc:transformation.alpha", 24804 mTransformationInfo != null ? mTransformationInfo.mAlpha : 0); 24805 stream.addProperty("misc:transitionName", getTransitionName()); 24806 24807 // layout 24808 stream.addProperty("layout:left", mLeft); 24809 stream.addProperty("layout:right", mRight); 24810 stream.addProperty("layout:top", mTop); 24811 stream.addProperty("layout:bottom", mBottom); 24812 stream.addProperty("layout:width", getWidth()); 24813 stream.addProperty("layout:height", getHeight()); 24814 stream.addProperty("layout:layoutDirection", getLayoutDirection()); 24815 stream.addProperty("layout:layoutRtl", isLayoutRtl()); 24816 stream.addProperty("layout:hasTransientState", hasTransientState()); 24817 stream.addProperty("layout:baseline", getBaseline()); 24818 24819 // layout params 24820 ViewGroup.LayoutParams layoutParams = getLayoutParams(); 24821 if (layoutParams != null) { 24822 stream.addPropertyKey("layoutParams"); 24823 layoutParams.encode(stream); 24824 } 24825 24826 // scrolling 24827 stream.addProperty("scrolling:scrollX", mScrollX); 24828 stream.addProperty("scrolling:scrollY", mScrollY); 24829 24830 // padding 24831 stream.addProperty("padding:paddingLeft", mPaddingLeft); 24832 stream.addProperty("padding:paddingRight", mPaddingRight); 24833 stream.addProperty("padding:paddingTop", mPaddingTop); 24834 stream.addProperty("padding:paddingBottom", mPaddingBottom); 24835 stream.addProperty("padding:userPaddingRight", mUserPaddingRight); 24836 stream.addProperty("padding:userPaddingLeft", mUserPaddingLeft); 24837 stream.addProperty("padding:userPaddingBottom", mUserPaddingBottom); 24838 stream.addProperty("padding:userPaddingStart", mUserPaddingStart); 24839 stream.addProperty("padding:userPaddingEnd", mUserPaddingEnd); 24840 24841 // measurement 24842 stream.addProperty("measurement:minHeight", mMinHeight); 24843 stream.addProperty("measurement:minWidth", mMinWidth); 24844 stream.addProperty("measurement:measuredWidth", mMeasuredWidth); 24845 stream.addProperty("measurement:measuredHeight", mMeasuredHeight); 24846 24847 // drawing 24848 stream.addProperty("drawing:elevation", getElevation()); 24849 stream.addProperty("drawing:translationX", getTranslationX()); 24850 stream.addProperty("drawing:translationY", getTranslationY()); 24851 stream.addProperty("drawing:translationZ", getTranslationZ()); 24852 stream.addProperty("drawing:rotation", getRotation()); 24853 stream.addProperty("drawing:rotationX", getRotationX()); 24854 stream.addProperty("drawing:rotationY", getRotationY()); 24855 stream.addProperty("drawing:scaleX", getScaleX()); 24856 stream.addProperty("drawing:scaleY", getScaleY()); 24857 stream.addProperty("drawing:pivotX", getPivotX()); 24858 stream.addProperty("drawing:pivotY", getPivotY()); 24859 stream.addProperty("drawing:opaque", isOpaque()); 24860 stream.addProperty("drawing:alpha", getAlpha()); 24861 stream.addProperty("drawing:transitionAlpha", getTransitionAlpha()); 24862 stream.addProperty("drawing:shadow", hasShadow()); 24863 stream.addProperty("drawing:solidColor", getSolidColor()); 24864 stream.addProperty("drawing:layerType", mLayerType); 24865 stream.addProperty("drawing:willNotDraw", willNotDraw()); 24866 stream.addProperty("drawing:hardwareAccelerated", isHardwareAccelerated()); 24867 stream.addProperty("drawing:willNotCacheDrawing", willNotCacheDrawing()); 24868 stream.addProperty("drawing:drawingCacheEnabled", isDrawingCacheEnabled()); 24869 stream.addProperty("drawing:overlappingRendering", hasOverlappingRendering()); 24870 24871 // focus 24872 stream.addProperty("focus:hasFocus", hasFocus()); 24873 stream.addProperty("focus:isFocused", isFocused()); 24874 stream.addProperty("focus:isFocusable", isFocusable()); 24875 stream.addProperty("focus:isFocusableInTouchMode", isFocusableInTouchMode()); 24876 24877 stream.addProperty("misc:clickable", isClickable()); 24878 stream.addProperty("misc:pressed", isPressed()); 24879 stream.addProperty("misc:selected", isSelected()); 24880 stream.addProperty("misc:touchMode", isInTouchMode()); 24881 stream.addProperty("misc:hovered", isHovered()); 24882 stream.addProperty("misc:activated", isActivated()); 24883 24884 stream.addProperty("misc:visibility", getVisibility()); 24885 stream.addProperty("misc:fitsSystemWindows", getFitsSystemWindows()); 24886 stream.addProperty("misc:filterTouchesWhenObscured", getFilterTouchesWhenObscured()); 24887 24888 stream.addProperty("misc:enabled", isEnabled()); 24889 stream.addProperty("misc:soundEffectsEnabled", isSoundEffectsEnabled()); 24890 stream.addProperty("misc:hapticFeedbackEnabled", isHapticFeedbackEnabled()); 24891 24892 // theme attributes 24893 Resources.Theme theme = getContext().getTheme(); 24894 if (theme != null) { 24895 stream.addPropertyKey("theme"); 24896 theme.encode(stream); 24897 } 24898 24899 // view attribute information 24900 int n = mAttributes != null ? mAttributes.length : 0; 24901 stream.addProperty("meta:__attrCount__", n/2); 24902 for (int i = 0; i < n; i += 2) { 24903 stream.addProperty("meta:__attr__" + mAttributes[i], mAttributes[i+1]); 24904 } 24905 24906 stream.addProperty("misc:scrollBarStyle", getScrollBarStyle()); 24907 24908 // text 24909 stream.addProperty("text:textDirection", getTextDirection()); 24910 stream.addProperty("text:textAlignment", getTextAlignment()); 24911 24912 // accessibility 24913 CharSequence contentDescription = getContentDescription(); 24914 stream.addProperty("accessibility:contentDescription", 24915 contentDescription == null ? "" : contentDescription.toString()); 24916 stream.addProperty("accessibility:labelFor", getLabelFor()); 24917 stream.addProperty("accessibility:importantForAccessibility", getImportantForAccessibility()); 24918 } 24919 24920 /** 24921 * Determine if this view is rendered on a round wearable device and is the main view 24922 * on the screen. 24923 */ 24924 boolean shouldDrawRoundScrollbar() { 24925 if (!mResources.getConfiguration().isScreenRound() || mAttachInfo == null) { 24926 return false; 24927 } 24928 24929 final View rootView = getRootView(); 24930 final WindowInsets insets = getRootWindowInsets(); 24931 24932 int height = getHeight(); 24933 int width = getWidth(); 24934 int displayHeight = rootView.getHeight(); 24935 int displayWidth = rootView.getWidth(); 24936 24937 if (height != displayHeight || width != displayWidth) { 24938 return false; 24939 } 24940 24941 getLocationInWindow(mAttachInfo.mTmpLocation); 24942 return mAttachInfo.mTmpLocation[0] == insets.getStableInsetLeft() 24943 && mAttachInfo.mTmpLocation[1] == insets.getStableInsetTop(); 24944 } 24945 24946 /** 24947 * Sets the tooltip text which will be displayed in a small popup next to the view. 24948 * <p> 24949 * The tooltip will be displayed: 24950 * <ul> 24951 * <li>On long click, unless is not handled otherwise (by OnLongClickListener or a context 24952 * menu). </li> 24953 * <li>On hover, after a brief delay since the pointer has stopped moving </li> 24954 * </ul> 24955 * <p> 24956 * <strong>Note:</strong> Do not override this method, as it will have no 24957 * effect on the text displayed in the tooltip. 24958 * 24959 * @param tooltipText the tooltip text, or null if no tooltip is required 24960 * @see #getTooltipText() 24961 * @attr ref android.R.styleable#View_tooltipText 24962 */ 24963 public void setTooltipText(@Nullable CharSequence tooltipText) { 24964 if (TextUtils.isEmpty(tooltipText)) { 24965 setFlags(0, TOOLTIP); 24966 hideTooltip(); 24967 mTooltipInfo = null; 24968 } else { 24969 setFlags(TOOLTIP, TOOLTIP); 24970 if (mTooltipInfo == null) { 24971 mTooltipInfo = new TooltipInfo(); 24972 mTooltipInfo.mShowTooltipRunnable = this::showHoverTooltip; 24973 mTooltipInfo.mHideTooltipRunnable = this::hideTooltip; 24974 } 24975 mTooltipInfo.mTooltipText = tooltipText; 24976 if (mTooltipInfo.mTooltipPopup != null && mTooltipInfo.mTooltipPopup.isShowing()) { 24977 mTooltipInfo.mTooltipPopup.updateContent(mTooltipInfo.mTooltipText); 24978 } 24979 } 24980 } 24981 24982 /** 24983 * @hide Binary compatibility stub. To be removed when we finalize O APIs. 24984 */ 24985 public void setTooltip(@Nullable CharSequence tooltipText) { 24986 setTooltipText(tooltipText); 24987 } 24988 24989 /** 24990 * Returns the view's tooltip text. 24991 * 24992 * <strong>Note:</strong> Do not override this method, as it will have no 24993 * effect on the text displayed in the tooltip. You must call 24994 * {@link #setTooltipText(CharSequence)} to modify the tooltip text. 24995 * 24996 * @return the tooltip text 24997 * @see #setTooltipText(CharSequence) 24998 * @attr ref android.R.styleable#View_tooltipText 24999 */ 25000 @Nullable 25001 public CharSequence getTooltipText() { 25002 return mTooltipInfo != null ? mTooltipInfo.mTooltipText : null; 25003 } 25004 25005 /** 25006 * @hide Binary compatibility stub. To be removed when we finalize O APIs. 25007 */ 25008 @Nullable 25009 public CharSequence getTooltip() { 25010 return getTooltipText(); 25011 } 25012 25013 private boolean showTooltip(int x, int y, boolean fromLongClick) { 25014 if (mAttachInfo == null || mTooltipInfo == null) { 25015 return false; 25016 } 25017 if ((mViewFlags & ENABLED_MASK) != ENABLED) { 25018 return false; 25019 } 25020 if (TextUtils.isEmpty(mTooltipInfo.mTooltipText)) { 25021 return false; 25022 } 25023 hideTooltip(); 25024 mTooltipInfo.mTooltipFromLongClick = fromLongClick; 25025 mTooltipInfo.mTooltipPopup = new TooltipPopup(getContext()); 25026 final boolean fromTouch = (mPrivateFlags3 & PFLAG3_FINGER_DOWN) == PFLAG3_FINGER_DOWN; 25027 mTooltipInfo.mTooltipPopup.show(this, x, y, fromTouch, mTooltipInfo.mTooltipText); 25028 mAttachInfo.mTooltipHost = this; 25029 return true; 25030 } 25031 25032 void hideTooltip() { 25033 if (mTooltipInfo == null) { 25034 return; 25035 } 25036 removeCallbacks(mTooltipInfo.mShowTooltipRunnable); 25037 if (mTooltipInfo.mTooltipPopup == null) { 25038 return; 25039 } 25040 mTooltipInfo.mTooltipPopup.hide(); 25041 mTooltipInfo.mTooltipPopup = null; 25042 mTooltipInfo.mTooltipFromLongClick = false; 25043 if (mAttachInfo != null) { 25044 mAttachInfo.mTooltipHost = null; 25045 } 25046 } 25047 25048 private boolean showLongClickTooltip(int x, int y) { 25049 removeCallbacks(mTooltipInfo.mShowTooltipRunnable); 25050 removeCallbacks(mTooltipInfo.mHideTooltipRunnable); 25051 return showTooltip(x, y, true); 25052 } 25053 25054 private void showHoverTooltip() { 25055 showTooltip(mTooltipInfo.mAnchorX, mTooltipInfo.mAnchorY, false); 25056 } 25057 25058 boolean dispatchTooltipHoverEvent(MotionEvent event) { 25059 if (mTooltipInfo == null) { 25060 return false; 25061 } 25062 switch(event.getAction()) { 25063 case MotionEvent.ACTION_HOVER_MOVE: 25064 if ((mViewFlags & TOOLTIP) != TOOLTIP || (mViewFlags & ENABLED_MASK) != ENABLED) { 25065 break; 25066 } 25067 if (!mTooltipInfo.mTooltipFromLongClick) { 25068 if (mTooltipInfo.mTooltipPopup == null) { 25069 // Schedule showing the tooltip after a timeout. 25070 mTooltipInfo.mAnchorX = (int) event.getX(); 25071 mTooltipInfo.mAnchorY = (int) event.getY(); 25072 removeCallbacks(mTooltipInfo.mShowTooltipRunnable); 25073 postDelayed(mTooltipInfo.mShowTooltipRunnable, 25074 ViewConfiguration.getHoverTooltipShowTimeout()); 25075 } 25076 25077 // Hide hover-triggered tooltip after a period of inactivity. 25078 // Match the timeout used by NativeInputManager to hide the mouse pointer 25079 // (depends on SYSTEM_UI_FLAG_LOW_PROFILE being set). 25080 final int timeout; 25081 if ((getWindowSystemUiVisibility() & SYSTEM_UI_FLAG_LOW_PROFILE) 25082 == SYSTEM_UI_FLAG_LOW_PROFILE) { 25083 timeout = ViewConfiguration.getHoverTooltipHideShortTimeout(); 25084 } else { 25085 timeout = ViewConfiguration.getHoverTooltipHideTimeout(); 25086 } 25087 removeCallbacks(mTooltipInfo.mHideTooltipRunnable); 25088 postDelayed(mTooltipInfo.mHideTooltipRunnable, timeout); 25089 } 25090 return true; 25091 25092 case MotionEvent.ACTION_HOVER_EXIT: 25093 if (!mTooltipInfo.mTooltipFromLongClick) { 25094 hideTooltip(); 25095 } 25096 break; 25097 } 25098 return false; 25099 } 25100 25101 void handleTooltipKey(KeyEvent event) { 25102 switch (event.getAction()) { 25103 case KeyEvent.ACTION_DOWN: 25104 if (event.getRepeatCount() == 0) { 25105 hideTooltip(); 25106 } 25107 break; 25108 25109 case KeyEvent.ACTION_UP: 25110 handleTooltipUp(); 25111 break; 25112 } 25113 } 25114 25115 private void handleTooltipUp() { 25116 if (mTooltipInfo == null || mTooltipInfo.mTooltipPopup == null) { 25117 return; 25118 } 25119 removeCallbacks(mTooltipInfo.mHideTooltipRunnable); 25120 postDelayed(mTooltipInfo.mHideTooltipRunnable, 25121 ViewConfiguration.getLongPressTooltipHideTimeout()); 25122 } 25123 25124 private int getFocusableAttribute(TypedArray attributes) { 25125 TypedValue val = new TypedValue(); 25126 if (attributes.getValue(com.android.internal.R.styleable.View_focusable, val)) { 25127 if (val.type == TypedValue.TYPE_INT_BOOLEAN) { 25128 return (val.data == 0 ? NOT_FOCUSABLE : FOCUSABLE); 25129 } else { 25130 return val.data; 25131 } 25132 } else { 25133 return FOCUSABLE_AUTO; 25134 } 25135 } 25136 25137 /** 25138 * @return The content view of the tooltip popup currently being shown, or null if the tooltip 25139 * is not showing. 25140 * @hide 25141 */ 25142 @TestApi 25143 public View getTooltipView() { 25144 if (mTooltipInfo == null || mTooltipInfo.mTooltipPopup == null) { 25145 return null; 25146 } 25147 return mTooltipInfo.mTooltipPopup.getContentView(); 25148 } 25149} 25150